CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
FullModelReactionDynamics.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * DISCLAIMER *
4 // * *
5 // * The following disclaimer summarizes all the specific disclaimers *
6 // * of contributors to this software. The specific disclaimers,which *
7 // * govern, are listed with their locations in: *
8 // * http://cern.ch/geant4/license *
9 // * *
10 // * Neither the authors of this software system, nor their employing *
11 // * institutes,nor the agencies providing financial support for this *
12 // * work make any representation or warranty, express or implied, *
13 // * regarding this software system or assume any liability for its *
14 // * use. *
15 // * *
16 // * This code implementation is the intellectual property of the *
17 // * GEANT4 collaboration. *
18 // * By copying, distributing or modifying the Program (or any work *
19 // * based on the Program) you indicate your acceptance of this *
20 // * statement, and all its terms. *
21 // ********************************************************************
22 //
23 //
24 //
25  // Hadronic Process: Reaction Dynamics
26  // original by H.P. Wellisch
27  // modified by J.L. Chuma, TRIUMF, 19-Nov-1996
28  // Last modified: 27-Mar-1997
29  // modified by H.P. Wellisch, 24-Apr-97
30  // H.P. Wellisch, 25.Apr-97: Side of current and target particle taken into account
31  // H.P. Wellisch, 29.Apr-97: Bug fix in NuclearReaction. (pseudo1 was without energy)
32  // J.L. Chuma, 30-Apr-97: Changed return value for GenerateXandPt. It seems possible
33  // that GenerateXandPt could eliminate some secondaries, but
34  // still finish its calculations, thus we would not want to
35  // then use TwoCluster to again calculate the momenta if vecLen
36  // was less than 6.
37  // J.L. Chuma, 10-Jun-97: Modified NuclearReaction. Was not creating ReactionProduct's
38  // with the new operator, thus they would be meaningless when
39  // going out of scope.
40  // J.L. Chuma, 20-Jun-97: Modified GenerateXandPt and TwoCluster to fix units problems
41  // J.L. Chuma, 23-Jun-97: Modified ProduceStrangeParticlePairs to fix units problems
42  // J.L. Chuma, 26-Jun-97: Modified ProduceStrangeParticlePairs to fix array indices
43  // which were sometimes going out of bounds
44  // J.L. Chuma, 04-Jul-97: Many minor modifications to GenerateXandPt and TwoCluster
45  // J.L. Chuma, 06-Aug-97: Added original incident particle, before Fermi motion and
46  // evaporation effects are included, needed for self absorption
47  // and corrections for single particle spectra (shower particles)
48  // logging stopped 1997
49  // J. Allison, 17-Jun-99: Replaced a min function to get correct behaviour on DEC.
50 
51 #include "SimG4Core/CustomPhysics/interface/FullModelReactionDynamics.hh"
52 #include "G4AntiProton.hh"
53 #include "G4AntiNeutron.hh"
54 #include "Randomize.hh"
55 #include <iostream>
56 #include "G4HadReentrentException.hh"
57 #include <signal.h>
58 #include "G4ParticleTable.hh"
59 
60 using namespace CLHEP;
61 
62 // #include "DumpFrame.hh"
63 
64 /* G4double GetQValue(G4ReactionProduct * aSec)
65  {
66  double QValue=0;
67  if(aSec->GetDefinition()->GetParticleType() == "baryon")
68  {
69  if(aSec->GetDefinition()->GetBaryonNumber() < 0)
70  {
71  QValue = aSec->GetTotalEnergy();
72  QValue += G4Neutron::Neutron()->GetPDGMass();
73  }
74  else
75  {
76  G4double ss = 0;
77  ss +=aSec->GetDefinition()->GetPDGMass();
78  if(aSec->GetDefinition() == G4Proton::Proton())
79  {
80  ss -=G4Proton::Proton()->GetPDGMass();
81  }
82  else
83  {
84  ss -=G4Neutron::Neutron()->GetPDGMass();
85  }
86  ss += aSec->GetKineticEnergy();
87  QValue = ss;
88  }
89  }
90  else if(aSec->GetDefinition()->GetPDGEncoding() == 0)
91  {
92  QValue = aSec->GetKineticEnergy();
93  }
94  else
95  {
96  QValue = aSec->GetTotalEnergy();
97  }
98  return QValue;
99  }
100 */
101 
102  G4bool FullModelReactionDynamics::GenerateXandPt(
103  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
104  G4int &vecLen,
105  G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
106  const G4HadProjectile *originalIncident, // the original incident particle
107  G4ReactionProduct &currentParticle,
108  G4ReactionProduct &targetParticle,
109  const G4Nucleus &targetNucleus,
110  G4bool &incidentHasChanged,
111  G4bool &targetHasChanged,
112  G4bool leadFlag,
113  G4ReactionProduct &leadingStrangeParticle )
114  {
115  //
116  // derived from original FORTRAN code GENXPT by H. Fesefeldt (11-Oct-1987)
117  //
118  // Generation of X- and PT- values for incident, target, and all secondary particles
119  // A simple single variable description E D3S/DP3= F(Q) with
120  // Q^2 = (M*X)^2 + PT^2 is used. Final state kinematic is produced
121  // by an FF-type iterative cascade method
122  //
123  // internal units are GeV
124  //
125  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
126 
127  // Protection in case no secondary has been created; cascades down to two-body.
128  if(vecLen == 0) return false;
129 
130  G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
131  // G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
132  // G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
133  G4ParticleDefinition *aProton = G4Proton::Proton();
134  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
135  G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
136  G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
137  G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
138  G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
139  G4ParticleDefinition *aKaonZeroS = G4KaonZeroShort::KaonZeroShort();
140  G4ParticleDefinition *aKaonZeroL = G4KaonZeroLong::KaonZeroLong();
141 
142  G4int i, l;
143  // G4double forVeryForward = 0.;
144  G4bool veryForward = false;
145 
146  const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
147  const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
148  const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
149  const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
150  G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
151  G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
152  targetMass*targetMass +
153  2.0*targetMass*etOriginal ); // GeV
154  G4double currentMass = currentParticle.GetMass()/GeV;
155  targetMass = targetParticle.GetMass()/GeV;
156  //
157  // randomize the order of the secondary particles
158  // note that the current and target particles are not affected
159  //
160  for( i=0; i<vecLen; ++i )
161  {
162  G4int itemp = G4int( G4UniformRand()*vecLen );
163  G4ReactionProduct pTemp = *vec[itemp];
164  *vec[itemp] = *vec[i];
165  *vec[i] = pTemp;
166  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
167  }
168 
169  if( currentMass == 0.0 && targetMass == 0.0 ) // annihilation
170  {
171  // no kinetic energy in target .....
172  G4double ek = currentParticle.GetKineticEnergy();
173  G4ThreeVector m = currentParticle.GetMomentum();
174  currentParticle = *vec[0];
175  targetParticle = *vec[1];
176  for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
177  G4ReactionProduct *temp = vec[vecLen-1];
178  delete temp;
179  temp = vec[vecLen-2];
180  delete temp;
181  vecLen -= 2;
182  currentMass = currentParticle.GetMass()/GeV;
183  targetMass = targetParticle.GetMass()/GeV;
184  incidentHasChanged = true;
185  targetHasChanged = true;
186  currentParticle.SetKineticEnergy( ek );
187  currentParticle.SetMomentum( m );
188  // forVeryForward = aProton->GetPDGMass();
189  veryForward = true;
190  }
191  const G4double atomicWeight = targetNucleus.GetN_asInt();
192  // G4cout <<"Atomic weight is: "<<atomicWeight<<G4endl;
193  const G4double atomicNumber = targetNucleus.GetZ_asInt();
194  const G4double protonMass = aProton->GetPDGMass()/MeV;
195  if( (originalIncident->GetDefinition() == aKaonMinus ||
196  originalIncident->GetDefinition() == aKaonZeroL ||
197  originalIncident->GetDefinition() == aKaonZeroS ||
198  originalIncident->GetDefinition() == aKaonPlus) &&
199  G4UniformRand() >= 0.7 )
200  {
201  G4ReactionProduct temp = currentParticle;
202  currentParticle = targetParticle;
203  targetParticle = temp;
204  incidentHasChanged = true;
205  targetHasChanged = true;
206  currentMass = currentParticle.GetMass()/GeV;
207  targetMass = targetParticle.GetMass()/GeV;
208  }
209  const G4double afc = std::min( 0.75,
210  0.312+0.200*std::log(std::log(centerofmassEnergy*centerofmassEnergy))+
211  std::pow(centerofmassEnergy*centerofmassEnergy,1.5)/6000.0 );
212 
213  // PROBLEMET ER HER!!!
214 
215  G4double freeEnergy = centerofmassEnergy-currentMass-targetMass;
216 
217  if(freeEnergy<0)
218  {
219  G4cout<<"Free energy < 0!"<<G4endl;
220  G4cout<<"E_CMS = "<<centerofmassEnergy<<" GeV"<<G4endl;
221  G4cout<<"m_curr = "<<currentMass<<" GeV"<<G4endl;
222  G4cout<<"m_orig = "<<mOriginal<<" GeV"<<G4endl;
223  G4cout<<"m_targ = "<<targetMass<<" GeV"<<G4endl;
224  G4cout<<"E_free = "<<freeEnergy<<" GeV"<<G4endl;
225  }
226 
227  G4double forwardEnergy = freeEnergy/2.;
228  G4int forwardCount = 1; // number of particles in forward hemisphere
229 
230  G4double backwardEnergy = freeEnergy/2.;
231  G4int backwardCount = 1; // number of particles in backward hemisphere
232  if(veryForward)
233  {
234  if(currentParticle.GetSide()==-1)
235  {
236  forwardEnergy += currentMass;
237  forwardCount --;
238  backwardEnergy -= currentMass;
239  backwardCount ++;
240  }
241  if(targetParticle.GetSide()!=-1)
242  {
243  backwardEnergy += targetMass;
244  backwardCount --;
245  forwardEnergy -= targetMass;
246  forwardCount ++;
247  }
248  }
249  for( i=0; i<vecLen; ++i )
250  {
251  if( vec[i]->GetSide() == -1 )
252  {
253  ++backwardCount;
254  backwardEnergy -= vec[i]->GetMass()/GeV;
255  } else {
256  ++forwardCount;
257  forwardEnergy -= vec[i]->GetMass()/GeV;
258  }
259  }
260  //
261  // add particles from intranuclear cascade
262  // nuclearExcitationCount = number of new secondaries produced by nuclear excitation
263  // extraCount = number of nucleons within these new secondaries
264  //
265  G4double xtarg;
266  if( centerofmassEnergy < (2.0+G4UniformRand()) )
267  xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount+vecLen+2)/2.0;
268  else
269  xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2.0*backwardCount);
270  if( xtarg <= 0.0 )xtarg = 0.01;
271  G4int nuclearExcitationCount = Poisson( xtarg );
272  if(atomicWeight<1.0001) nuclearExcitationCount = 0;
273  G4int extraNucleonCount = 0;
274  G4double extraNucleonMass = 0.0;
275  if( nuclearExcitationCount > 0 )
276  {
277  const G4double nucsup[] = { 1.00, 0.7, 0.5, 0.4, 0.35, 0.3 };
278  const G4double psup[] = { 3., 6., 20., 50., 100., 1000. };
279  G4int momentumBin = 0;
280  while( (momentumBin < 6) &&
281  (modifiedOriginal.GetTotalMomentum()/GeV > psup[momentumBin]) )
282  ++momentumBin;
283  momentumBin = std::min( 5, momentumBin );
284  //
285  // NOTE: in GENXPT, these new particles were given negative codes
286  // here I use NewlyAdded = true instead
287  //
288 // G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
289  for( i=0; i<nuclearExcitationCount; ++i )
290  {
291  G4ReactionProduct * pVec = new G4ReactionProduct();
292  if( G4UniformRand() < nucsup[momentumBin] )
293  {
294  if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
295  pVec->SetDefinition( aProton );
296  else
297  pVec->SetDefinition( aNeutron );
298  pVec->SetSide( -2 ); // -2 means backside nucleon
299  ++extraNucleonCount;
300  backwardEnergy += pVec->GetMass()/GeV;
301  extraNucleonMass += pVec->GetMass()/GeV;
302  }
303  else
304  {
305  G4double ran = G4UniformRand();
306  if( ran < 0.3181 )
307  pVec->SetDefinition( aPiPlus );
308  else if( ran < 0.6819 )
309  pVec->SetDefinition( aPiZero );
310  else
311  pVec->SetDefinition( aPiMinus );
312  pVec->SetSide( -1 ); // backside particle, but not a nucleon
313  }
314  pVec->SetNewlyAdded( true ); // true is the same as IPA(i)<0
315  vec.SetElement( vecLen++, pVec );
316  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
317  backwardEnergy -= pVec->GetMass()/GeV;
318  ++backwardCount;
319  }
320  }
321  //
322  // assume conservation of kinetic energy in forward & backward hemispheres
323  //
324  G4int is, iskip;
325  while( forwardEnergy <= 0.0 ) // must eliminate a particle from the forward side
326  {
327  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
328  iskip = G4int(G4UniformRand()*forwardCount) + 1; // 1 <= iskip <= forwardCount
329  is = 0;
330  G4int forwardParticlesLeft = 0;
331  for( i=(vecLen-1); i>=0; --i )
332  {
333  if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
334  {
335  forwardParticlesLeft = 1;
336  if( ++is == iskip )
337  {
338  forwardEnergy += vec[i]->GetMass()/GeV;
339  for( G4int j=i; j<(vecLen-1); j++ )*vec[j] = *vec[j+1]; // shift up
340  --forwardCount;
341  G4ReactionProduct *temp = vec[vecLen-1];
342  delete temp;
343  if( --vecLen == 0 )return false; // all the secondaries have been eliminated
344  break; // --+
345  } // |
346  } // |
347  } // break goes down to here
348  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
349  if( forwardParticlesLeft == 0 )
350  {
351  forwardEnergy += currentParticle.GetMass()/GeV;
352  currentParticle.SetDefinitionAndUpdateE( targetParticle.GetDefinition() );
353  targetParticle.SetDefinitionAndUpdateE( vec[0]->GetDefinition() );
354  // above two lines modified 20-oct-97: were just simple equalities
355  --forwardCount;
356  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];
357  G4ReactionProduct *temp = vec[vecLen-1];
358  delete temp;
359  if( --vecLen == 0 )return false; // all the secondaries have been eliminated
360  break;
361  }
362  }
363  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
364  while( backwardEnergy <= 0.0 ) // must eliminate a particle from the backward side
365  {
366  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
367  iskip = G4int(G4UniformRand()*backwardCount) + 1; // 1 <= iskip <= backwardCount
368  is = 0;
369  G4int backwardParticlesLeft = 0;
370  for( i=(vecLen-1); i>=0; --i )
371  {
372  if( vec[i]->GetSide() < 0 && vec[i]->GetMayBeKilled())
373  {
374  backwardParticlesLeft = 1;
375  if( ++is == iskip ) // eliminate the i'th particle
376  {
377  if( vec[i]->GetSide() == -2 )
378  {
379  --extraNucleonCount;
380  extraNucleonMass -= vec[i]->GetMass()/GeV;
381  backwardEnergy -= vec[i]->GetTotalEnergy()/GeV;
382  }
383  backwardEnergy += vec[i]->GetTotalEnergy()/GeV;
384  for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
385  --backwardCount;
386  G4ReactionProduct *temp = vec[vecLen-1];
387  delete temp;
388  if( --vecLen == 0 )return false; // all the secondaries have been eliminated
389  break;
390  }
391  }
392  }
393  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
394  if( backwardParticlesLeft == 0 )
395  {
396  backwardEnergy += targetParticle.GetMass()/GeV;
397  targetParticle = *vec[0];
398  --backwardCount;
399  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1];
400  G4ReactionProduct *temp = vec[vecLen-1];
401  delete temp;
402  if( --vecLen == 0 )return false; // all the secondaries have been eliminated
403  break;
404  }
405  }
406  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
407  //
408  // define initial state vectors for Lorentz transformations
409  // the pseudoParticles have non-standard masses, hence the "pseudo"
410  //
411  G4ReactionProduct pseudoParticle[10];
412  for( i=0; i<10; ++i )pseudoParticle[i].SetZero();
413 
414  pseudoParticle[0].SetMass( mOriginal*GeV );
415  pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
416  pseudoParticle[0].SetTotalEnergy(
417  std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
418 
419  pseudoParticle[1].SetMass( protonMass*MeV ); // this could be targetMass
420  pseudoParticle[1].SetTotalEnergy( protonMass*MeV );
421 
422  pseudoParticle[3].SetMass( protonMass*(1+extraNucleonCount)*MeV );
423  pseudoParticle[3].SetTotalEnergy( protonMass*(1+extraNucleonCount)*MeV );
424 
425  pseudoParticle[8].SetMomentum( 1.0*GeV, 0.0, 0.0 );
426 
427  pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
428  pseudoParticle[3] = pseudoParticle[3] + pseudoParticle[0];
429 
430  pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
431  pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
432 
433  G4double dndl[20];
434  //
435  // main loop for 4-momentum generation
436  // see Pitha-report (Aachen) for a detailed description of the method
437  //
438  G4double aspar, pt, et, x, pp, pp1, rthnve, phinve, rmb, wgt;
439  G4int innerCounter, outerCounter;
440  G4bool eliminateThisParticle, resetEnergies, constantCrossSection;
441 
442  G4double forwardKinetic = 0.0, backwardKinetic = 0.0;
443  //
444  // process the secondary particles in reverse order
445  // the incident particle is Done after the secondaries
446  // nucleons, including the target, in the backward hemisphere are also Done later
447  //
448  G4double binl[20] = {0.,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.11,1.25,
449  1.43,1.67,2.0,2.5,3.33,5.00,10.00};
450  G4int backwardNucleonCount = 0; // number of nucleons in backward hemisphere
451  G4double totalEnergy, kineticEnergy, vecMass;
452 
453  for( i=(vecLen-1); i>=0; --i )
454  {
455  G4double phi = G4UniformRand()*twopi;
456  if( vec[i]->GetNewlyAdded() ) // added from intranuclear cascade
457  {
458  if( vec[i]->GetSide() == -2 ) // is a nucleon
459  {
460  if( backwardNucleonCount < 18 )
461  {
462  if( vec[i]->GetDefinition() == G4PionMinus::PionMinus() ||
463  vec[i]->GetDefinition() == G4PionPlus::PionPlus() ||
464  vec[i]->GetDefinition() == G4PionZero::PionZero() )
465  {
466  for(G4int i=0; i<vecLen; i++) delete vec[i];
467  vecLen = 0;
468  throw G4HadReentrentException(__FILE__, __LINE__,
469  "FullModelReactionDynamics::GenerateXandPt : a pion has been counted as a backward nucleon");
470  }
471  vec[i]->SetSide( -3 );
472  ++backwardNucleonCount;
473  continue;
474  }
475  }
476  }
477  //
478  // set pt and phi values, they are changed somewhat in the iteration loop
479  // set mass parameter for lambda fragmentation model
480  //
481  vecMass = vec[i]->GetMass()/GeV;
482  G4double ran = -std::log(1.0-G4UniformRand())/3.5;
483  if( vec[i]->GetSide() == -2 ) // backward nucleon
484  {
485  if( vec[i]->GetDefinition() == aKaonMinus ||
486  vec[i]->GetDefinition() == aKaonZeroL ||
487  vec[i]->GetDefinition() == aKaonZeroS ||
488  vec[i]->GetDefinition() == aKaonPlus ||
489  vec[i]->GetDefinition() == aPiMinus ||
490  vec[i]->GetDefinition() == aPiZero ||
491  vec[i]->GetDefinition() == aPiPlus )
492  {
493  aspar = 0.75;
494  pt = std::sqrt( std::pow( ran, 1.7 ) );
495  } else { // vec[i] must be a proton, neutron,
496  aspar = 0.20; // lambda, sigma, xsi, or ion
497  pt = std::sqrt( std::pow( ran, 1.2 ) );
498  }
499  } else { // not a backward nucleon
500  if( vec[i]->GetDefinition() == aPiMinus ||
501  vec[i]->GetDefinition() == aPiZero ||
502  vec[i]->GetDefinition() == aPiPlus )
503  {
504  aspar = 0.75;
505  pt = std::sqrt( std::pow( ran, 1.7 ) );
506  } else if( vec[i]->GetDefinition() == aKaonMinus ||
507  vec[i]->GetDefinition() == aKaonZeroL ||
508  vec[i]->GetDefinition() == aKaonZeroS ||
509  vec[i]->GetDefinition() == aKaonPlus )
510  {
511  aspar = 0.70;
512  pt = std::sqrt( std::pow( ran, 1.7 ) );
513  } else { // vec[i] must be a proton, neutron,
514  aspar = 0.65; // lambda, sigma, xsi, or ion
515  pt = std::sqrt( std::pow( ran, 1.5 ) );
516  }
517  }
518  pt = std::max( 0.001, pt );
519  vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
520  for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
521  if( vec[i]->GetSide() > 0 )
522  et = pseudoParticle[0].GetTotalEnergy()/GeV;
523  else
524  et = pseudoParticle[1].GetTotalEnergy()/GeV;
525  dndl[0] = 0.0;
526  //
527  // start of outer iteration loop
528  //
529  outerCounter = 0;
530  eliminateThisParticle = true;
531  resetEnergies = true;
532  while( ++outerCounter < 3 )
533  {
534  for( l=1; l<20; ++l )
535  {
536  x = (binl[l]+binl[l-1])/2.;
537  pt = std::max( 0.001, pt );
538  if( x > 1.0/pt )
539  dndl[l] += dndl[l-1]; // changed from just = on 02 April 98
540  else
541  dndl[l] = et * aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) )
542  * (binl[l]-binl[l-1]) / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass )
543  + dndl[l-1];
544  }
545  innerCounter = 0;
546  vec[i]->SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
547  //
548  // start of inner iteration loop
549  //
550  while( ++innerCounter < 7 )
551  {
552  ran = G4UniformRand()*dndl[19];
553  l = 1;
554  while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
555  l = std::min( 19, l );
556  x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
557  if( vec[i]->GetSide() < 0 )x *= -1.;
558  vec[i]->SetMomentum( x*et*GeV ); // set the z-momentum
559  totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
560  vec[i]->SetTotalEnergy( totalEnergy*GeV );
561  kineticEnergy = vec[i]->GetKineticEnergy()/GeV;
562  if( vec[i]->GetSide() > 0 ) // forward side
563  {
564  if( (forwardKinetic+kineticEnergy) < 0.95*forwardEnergy )
565  {
566  pseudoParticle[4] = pseudoParticle[4] + (*vec[i]);
567  forwardKinetic += kineticEnergy;
568  pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
569  pseudoParticle[6].SetMomentum( 0.0 ); // set the z-momentum
570  phi = pseudoParticle[6].Angle( pseudoParticle[8] );
571  if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
572  phi += pi + normal()*pi/12.0;
573  if( phi > twopi )phi -= twopi;
574  if( phi < 0.0 )phi = twopi - phi;
575  outerCounter = 2; // leave outer loop
576  eliminateThisParticle = false; // don't eliminate this particle
577  resetEnergies = false;
578  break; // leave inner loop
579  }
580  if( innerCounter > 5 )break; // leave inner loop
581  if( backwardEnergy >= vecMass ) // switch sides
582  {
583  vec[i]->SetSide( -1 );
584  forwardEnergy += vecMass;
585  backwardEnergy -= vecMass;
586  ++backwardCount;
587  }
588  } else { // backward side
589  if( extraNucleonCount > 19 ) // commented out to duplicate ?bug? in GENXPT
590  x = 0.999;
591  G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
592  if( (backwardKinetic+kineticEnergy) < xxx*backwardEnergy )
593  {
594  pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
595  backwardKinetic += kineticEnergy;
596  pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
597  pseudoParticle[6].SetMomentum( 0.0 ); // set the z-momentum
598  phi = pseudoParticle[6].Angle( pseudoParticle[8] );
599  if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
600  phi += pi + normal() * pi / 12.0;
601  if( phi > twopi )phi -= twopi;
602  if( phi < 0.0 )phi = twopi - phi;
603  outerCounter = 2; // leave outer loop
604  eliminateThisParticle = false; // don't eliminate this particle
605  resetEnergies = false;
606  break; // leave inner loop
607  }
608  if( innerCounter > 5 )break; // leave inner loop
609  if( forwardEnergy >= vecMass ) // switch sides
610  {
611  vec[i]->SetSide( 1 );
612  forwardEnergy -= vecMass;
613  backwardEnergy += vecMass;
614  backwardCount--;
615  }
616  }
617  G4ThreeVector momentum = vec[i]->GetMomentum();
618  vec[i]->SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
619  pt *= 0.9;
620  dndl[19] *= 0.9;
621  } // closes inner loop
622  if( resetEnergies )
623  {
624  // if we get to here, the inner loop has been Done 6 Times
625  // reset the kinetic energies of previously Done particles, if they are lighter
626  // than protons and in the forward hemisphere
627  // then continue with outer loop
628  //
629  forwardKinetic = 0.0;
630  backwardKinetic = 0.0;
631  pseudoParticle[4].SetZero();
632  pseudoParticle[5].SetZero();
633  for( l=i+1; l<vecLen; ++l )
634  {
635  if( vec[l]->GetSide() > 0 ||
636  vec[l]->GetDefinition() == aKaonMinus ||
637  vec[l]->GetDefinition() == aKaonZeroL ||
638  vec[l]->GetDefinition() == aKaonZeroS ||
639  vec[l]->GetDefinition() == aKaonPlus ||
640  vec[l]->GetDefinition() == aPiMinus ||
641  vec[l]->GetDefinition() == aPiZero ||
642  vec[l]->GetDefinition() == aPiPlus )
643  {
644  G4double tempMass = vec[l]->GetMass()/MeV;
645  totalEnergy = 0.95*vec[l]->GetTotalEnergy()/MeV + 0.05*tempMass;
646  totalEnergy = std::max( tempMass, totalEnergy );
647  vec[l]->SetTotalEnergy( totalEnergy*MeV );
648  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) );
649  pp1 = vec[l]->GetMomentum().mag()/MeV;
650  if( pp1 < 1.0e-6*GeV )
651  {
652  G4double rthnve = pi*G4UniformRand();
653  G4double phinve = twopi*G4UniformRand();
654  G4double srth = std::sin(rthnve);
655  vec[l]->SetMomentum( pp*srth*std::cos(phinve)*MeV,
656  pp*srth*std::sin(phinve)*MeV,
657  pp*std::cos(rthnve)*MeV ) ;
658  } else {
659  vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
660  }
661  G4double px = vec[l]->GetMomentum().x()/MeV;
662  G4double py = vec[l]->GetMomentum().y()/MeV;
663  pt = std::max( 1.0, std::sqrt( px*px + py*py ) )/GeV;
664  if( vec[l]->GetSide() > 0 )
665  {
666  forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
667  pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
668  } else {
669  backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
670  pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
671  }
672  }
673  }
674  }
675  } // closes outer loop
676 
677  if( eliminateThisParticle && vec[i]->GetMayBeKilled()) // not enough energy, eliminate this particle
678  {
679  if( vec[i]->GetSide() > 0 )
680  {
681  --forwardCount;
682  forwardEnergy += vecMass;
683  } else {
684  if( vec[i]->GetSide() == -2 )
685  {
686  --extraNucleonCount;
687  extraNucleonMass -= vecMass;
688  backwardEnergy -= vecMass;
689  }
690  --backwardCount;
691  backwardEnergy += vecMass;
692  }
693  for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
694  G4ReactionProduct *temp = vec[vecLen-1];
695  delete temp;
696  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
697  if( --vecLen == 0 )return false; // all the secondaries have been eliminated
698  pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
699  pseudoParticle[6].SetMomentum( 0.0 ); // set z-momentum
700  phi = pseudoParticle[6].Angle( pseudoParticle[8] );
701  if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
702  phi += pi + normal() * pi / 12.0;
703  if( phi > twopi )phi -= twopi;
704  if( phi < 0.0 )phi = twopi - phi;
705  }
706  } // closes main for loop
707 
708  //
709  // for the incident particle: it was placed in the forward hemisphere
710  // set pt and phi values, they are changed somewhat in the iteration loop
711  // set mass parameter for lambda fragmentation model
712  //
713  G4double phi = G4UniformRand()*twopi;
714  G4double ran = -std::log(1.0-G4UniformRand());
715  if( currentParticle.GetDefinition() == aPiMinus ||
716  currentParticle.GetDefinition() == aPiZero ||
717  currentParticle.GetDefinition() == aPiPlus )
718  {
719  aspar = 0.60;
720  pt = std::sqrt( std::pow( ran/6.0, 1.7 ) );
721  } else if( currentParticle.GetDefinition() == aKaonMinus ||
722  currentParticle.GetDefinition() == aKaonZeroL ||
723  currentParticle.GetDefinition() == aKaonZeroS ||
724  currentParticle.GetDefinition() == aKaonPlus )
725  {
726  aspar = 0.50;
727  pt = std::sqrt( std::pow( ran/5.0, 1.4 ) );
728  } else {
729  aspar = 0.40;
730  pt = std::sqrt( std::pow( ran/4.0, 1.2 ) );
731  }
732  for( G4int j=0; j<20; ++j )binl[j] = j/(19.*pt);
733  currentParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
734  et = pseudoParticle[0].GetTotalEnergy()/GeV;
735  dndl[0] = 0.0;
736  vecMass = currentParticle.GetMass()/GeV;
737  for( l=1; l<20; ++l )
738  {
739  x = (binl[l]+binl[l-1])/2.;
740  if( x > 1.0/pt )
741  dndl[l] += dndl[l-1]; // changed from just = on 02 April 98
742  else
743  dndl[l] = aspar/std::sqrt( std::pow((1.+sqr(aspar*x)),3) ) *
744  (binl[l]-binl[l-1]) * et / std::sqrt( pt*x*et*pt*x*et + pt*pt + vecMass*vecMass ) +
745  dndl[l-1];
746  }
747  ran = G4UniformRand()*dndl[19];
748  l = 1;
749  while( (ran>dndl[l]) && (l<20) )l++;
750  l = std::min( 19, l );
751  x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
752  currentParticle.SetMomentum( x*et*GeV ); // set the z-momentum
753  if( forwardEnergy < forwardKinetic )
754  totalEnergy = vecMass + 0.04*std::fabs(normal());
755  else
756  totalEnergy = vecMass + forwardEnergy - forwardKinetic;
757  currentParticle.SetTotalEnergy( totalEnergy*GeV );
758  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
759  pp1 = currentParticle.GetMomentum().mag()/MeV;
760  if( pp1 < 1.0e-6*GeV )
761  {
762  G4double rthnve = pi*G4UniformRand();
763  G4double phinve = twopi*G4UniformRand();
764  G4double srth = std::sin(rthnve);
765  currentParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
766  pp*srth*std::sin(phinve)*MeV,
767  pp*std::cos(rthnve)*MeV );
768  } else {
769  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
770  }
771  pseudoParticle[4] = pseudoParticle[4] + currentParticle;
772  //
773  // this finishes the current particle
774  // now for the target particle
775  //
776  if( backwardNucleonCount < 18 )
777  {
778  targetParticle.SetSide( -3 );
779  ++backwardNucleonCount;
780  }
781  else
782  {
783  // set pt and phi values, they are changed somewhat in the iteration loop
784  // set mass parameter for lambda fragmentation model
785  //
786  vecMass = targetParticle.GetMass()/GeV;
787  ran = -std::log(1.0-G4UniformRand());
788  aspar = 0.40;
789  pt = std::max( 0.001, std::sqrt( std::pow( ran/4.0, 1.2 ) ) );
790  targetParticle.SetMomentum( pt*std::cos(phi)*GeV, pt*std::sin(phi)*GeV );
791  for( G4int j=0; j<20; ++j )binl[j] = (j-1.)/(19.*pt);
792  et = pseudoParticle[1].GetTotalEnergy()/GeV;
793  dndl[0] = 0.0;
794  outerCounter = 0;
795  eliminateThisParticle = true; // should never eliminate the target particle
796  resetEnergies = true;
797  while( ++outerCounter < 3 ) // start of outer iteration loop
798  {
799  for( l=1; l<20; ++l )
800  {
801  x = (binl[l]+binl[l-1])/2.;
802  if( x > 1.0/pt )
803  dndl[l] += dndl[l-1]; // changed from just = on 02 April 98
804  else
805  dndl[l] = aspar/std::sqrt( std::pow((1.+aspar*x*aspar*x),3) ) *
806  (binl[l]-binl[l-1])*et / std::sqrt( pt*x*et*pt*x*et+pt*pt+vecMass*vecMass ) +
807  dndl[l-1];
808  }
809  innerCounter = 0;
810  while( ++innerCounter < 7 ) // start of inner iteration loop
811  {
812  l = 1;
813  ran = G4UniformRand()*dndl[19];
814  while( ( ran >= dndl[l] ) && ( l < 20 ) )l++;
815  l = std::min( 19, l );
816  x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
817  if( targetParticle.GetSide() < 0 )x *= -1.;
818  targetParticle.SetMomentum( x*et*GeV ); // set the z-momentum
819  totalEnergy = std::sqrt( x*et*x*et + pt*pt + vecMass*vecMass );
820  targetParticle.SetTotalEnergy( totalEnergy*GeV );
821  if( targetParticle.GetSide() < 0 )
822  {
823  if( extraNucleonCount > 19 )x=0.999;
824  G4double xxx = 0.95+0.05*extraNucleonCount/20.0;
825  if( (backwardKinetic+totalEnergy-vecMass) < xxx*backwardEnergy )
826  {
827  pseudoParticle[5] = pseudoParticle[5] + targetParticle;
828  backwardKinetic += totalEnergy - vecMass;
829  pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
830  pseudoParticle[6].SetMomentum( 0.0 ); // set z-momentum
831  phi = pseudoParticle[6].Angle( pseudoParticle[8] );
832  if( pseudoParticle[6].GetMomentum().y()/MeV < 0.0 )phi = twopi - phi;
833  phi += pi + normal() * pi / 12.0;
834  if( phi > twopi )phi -= twopi;
835  if( phi < 0.0 )phi = twopi - phi;
836  outerCounter = 2; // leave outer loop
837  eliminateThisParticle = false; // don't eliminate this particle
838  resetEnergies = false;
839  break; // leave inner loop
840  }
841  if( innerCounter > 5 )break; // leave inner loop
842  if( forwardEnergy >= vecMass ) // switch sides
843  {
844  targetParticle.SetSide( 1 );
845  forwardEnergy -= vecMass;
846  backwardEnergy += vecMass;
847  --backwardCount;
848  }
849  G4ThreeVector momentum = targetParticle.GetMomentum();
850  targetParticle.SetMomentum( momentum.x() * 0.9, momentum.y() * 0.9 );
851  pt *= 0.9;
852  dndl[19] *= 0.9;
853  }
854  else // target has gone to forward side
855  {
856  if( forwardEnergy < forwardKinetic )
857  totalEnergy = vecMass + 0.04*std::fabs(normal());
858  else
859  totalEnergy = vecMass + forwardEnergy - forwardKinetic;
860  targetParticle.SetTotalEnergy( totalEnergy*GeV );
861  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
862  pp1 = targetParticle.GetMomentum().mag()/MeV;
863  if( pp1 < 1.0e-6*GeV )
864  {
865  G4double rthnve = pi*G4UniformRand();
866  G4double phinve = twopi*G4UniformRand();
867  G4double srth = std::sin(rthnve);
868  targetParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
869  pp*srth*std::sin(phinve)*MeV,
870  pp*std::cos(rthnve)*MeV );
871  }
872  else
873  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
874 
875  pseudoParticle[4] = pseudoParticle[4] + targetParticle;
876  outerCounter = 2; // leave outer loop
877  eliminateThisParticle = false; // don't eliminate this particle
878  resetEnergies = false;
879  break; // leave inner loop
880  }
881  } // closes inner loop
882  if( resetEnergies )
883  {
884  // if we get to here, the inner loop has been Done 6 Times
885  // reset the kinetic energies of previously Done particles, if they are lighter
886  // than protons and in the forward hemisphere
887  // then continue with outer loop
888 
889  forwardKinetic = backwardKinetic = 0.0;
890  pseudoParticle[4].SetZero();
891  pseudoParticle[5].SetZero();
892  for( l=0; l<vecLen; ++l ) // changed from l=1 on 02 April 98
893  {
894  if( vec[l]->GetSide() > 0 ||
895  vec[l]->GetDefinition() == aKaonMinus ||
896  vec[l]->GetDefinition() == aKaonZeroL ||
897  vec[l]->GetDefinition() == aKaonZeroS ||
898  vec[l]->GetDefinition() == aKaonPlus ||
899  vec[l]->GetDefinition() == aPiMinus ||
900  vec[l]->GetDefinition() == aPiZero ||
901  vec[l]->GetDefinition() == aPiPlus )
902  {
903  G4double tempMass = vec[l]->GetMass()/GeV;
904  totalEnergy =
905  std::max( tempMass, 0.95*vec[l]->GetTotalEnergy()/GeV + 0.05*tempMass );
906  vec[l]->SetTotalEnergy( totalEnergy*GeV );
907  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - tempMass*tempMass ) )*GeV;
908  pp1 = vec[l]->GetMomentum().mag()/MeV;
909  if( pp1 < 1.0e-6*GeV )
910  {
911  G4double rthnve = pi*G4UniformRand();
912  G4double phinve = twopi*G4UniformRand();
913  G4double srth = std::sin(rthnve);
914  vec[l]->SetMomentum( pp*srth*std::cos(phinve)*MeV,
915  pp*srth*std::sin(phinve)*MeV,
916  pp*std::cos(rthnve)*MeV );
917  }
918  else
919  vec[l]->SetMomentum( vec[l]->GetMomentum() * (pp/pp1) );
920 
921  pt = std::max( 0.001*GeV, std::sqrt( sqr(vec[l]->GetMomentum().x()/MeV) +
922  sqr(vec[l]->GetMomentum().y()/MeV) ) )/GeV;
923  if( vec[l]->GetSide() > 0)
924  {
925  forwardKinetic += vec[l]->GetKineticEnergy()/GeV;
926  pseudoParticle[4] = pseudoParticle[4] + (*vec[l]);
927  } else {
928  backwardKinetic += vec[l]->GetKineticEnergy()/GeV;
929  pseudoParticle[5] = pseudoParticle[5] + (*vec[l]);
930  }
931  }
932  }
933  }
934  } // closes outer loop
935 // if( eliminateThisParticle ) // not enough energy, eliminate target
936 // {
937 // G4cerr << "Warning: eliminating target particle" << G4endl;
938 // exit( EXIT_FAILURE );
939 // }
940  }
941  //
942  // this finishes the target particle
943  // backward nucleons produced with a cluster model
944  //
945  pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
946  pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
947  pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
948  if( backwardNucleonCount == 1 ) // target particle is the only backward nucleon
949  {
950  G4double ekin =
951  std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
952  if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
953  vecMass = targetParticle.GetMass()/GeV;
954  totalEnergy = ekin+vecMass;
955  targetParticle.SetTotalEnergy( totalEnergy*GeV );
956  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
957  pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
958  if( pp1 < 1.0e-6*GeV )
959  {
960  rthnve = pi*G4UniformRand();
961  phinve = twopi*G4UniformRand();
962  G4double srth = std::sin(rthnve);
963  targetParticle.SetMomentum( pp*srth*std::cos(phinve)*MeV,
964  pp*srth*std::sin(phinve)*MeV,
965  pp*std::cos(rthnve)*MeV );
966  } else {
967  targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
968  }
969  pseudoParticle[5] = pseudoParticle[5] + targetParticle;
970  }
971  else // more than one backward nucleon
972  {
973  const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
974  const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
975  // Replaced the following min function to get correct behaviour on DEC.
976  // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
977  G4int tempCount;
978  if (backwardNucleonCount < 5)
979  {
980  tempCount = backwardNucleonCount;
981  }
982  else
983  {
984  tempCount = 5;
985  }
986  tempCount--;
987  //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
988  //cout << "tempCount " << tempCount << G4endl;
989  G4double rmb0 = 0.0;
990  if( targetParticle.GetSide() == -3 )
991  rmb0 += targetParticle.GetMass()/GeV;
992  for( i=0; i<vecLen; ++i )
993  {
994  if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
995  }
996  rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
997  totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
998  vecMass = std::min( rmb, totalEnergy );
999  pseudoParticle[6].SetMass( vecMass*GeV );
1000  pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
1001  pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
1002  if( pp1 < 1.0e-6*GeV )
1003  {
1004  rthnve = pi * G4UniformRand();
1005  phinve = twopi * G4UniformRand();
1006  G4double srth = std::sin(rthnve);
1007  pseudoParticle[6].SetMomentum( -pp*srth*std::cos(phinve)*MeV,
1008  -pp*srth*std::sin(phinve)*MeV,
1009  -pp*std::cos(rthnve)*MeV );
1010  }
1011  else
1012  pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
1013 
1014  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV; // tempV contains the backward nucleons
1015  tempV.Initialize( backwardNucleonCount );
1016  G4int tempLen = 0;
1017  if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
1018  for( i=0; i<vecLen; ++i )
1019  {
1020  if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
1021  }
1022  if( tempLen != backwardNucleonCount )
1023  {
1024  G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
1025  G4cerr << "tempLen = " << tempLen;
1026  G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
1027  G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
1028  G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
1029  for( i=0; i<vecLen; ++i )
1030  G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
1031  exit( EXIT_FAILURE );
1032  }
1033  constantCrossSection = true;
1034  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1035  if( tempLen >= 2 )
1036  {
1037  wgt = GenerateNBodyEvent(
1038  pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
1039  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1040  if( targetParticle.GetSide() == -3 )
1041  {
1042  targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1043  // tempV contains the real stuff
1044  pseudoParticle[5] = pseudoParticle[5] + targetParticle;
1045  }
1046  for( i=0; i<vecLen; ++i )
1047  {
1048  if( vec[i]->GetSide() == -3 )
1049  {
1050  vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1051  pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
1052  }
1053  }
1054  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1055  }
1056  }
1057  //
1058  // Lorentz transformation in lab system
1059  //
1060  if( vecLen == 0 )return false; // all the secondaries have been eliminated
1061  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1062 
1063  G4int numberofFinalStateNucleons = 0;
1064  if( currentParticle.GetDefinition() ==aProton ||
1065  currentParticle.GetDefinition() == aNeutron ||
1066  currentParticle.GetDefinition() == G4SigmaMinus::SigmaMinus()||
1067  currentParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
1068  currentParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
1069  currentParticle.GetDefinition() == G4XiZero::XiZero()||
1070  currentParticle.GetDefinition() == G4XiMinus::XiMinus()||
1071  currentParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
1072  currentParticle.GetDefinition() == G4Lambda::Lambda()) ++numberofFinalStateNucleons;
1073  currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
1074 
1075  if( targetParticle.GetDefinition() ==aProton ||
1076  targetParticle.GetDefinition() == aNeutron ||
1077  targetParticle.GetDefinition() == G4Lambda::Lambda() ||
1078  targetParticle.GetDefinition() == G4XiZero::XiZero()||
1079  targetParticle.GetDefinition() == G4XiMinus::XiMinus()||
1080  targetParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
1081  targetParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
1082  targetParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
1083  targetParticle.GetDefinition() == G4SigmaMinus::SigmaMinus()) ++numberofFinalStateNucleons;
1084  if( targetParticle.GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
1085  if( targetParticle.GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
1086  if( targetParticle.GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
1087  if( targetParticle.GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
1088  if( targetParticle.GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
1089  if( targetParticle.GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
1090  if( targetParticle.GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
1091  if( targetParticle.GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
1092  if( targetParticle.GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
1093  targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
1094 
1095  for( i=0; i<vecLen; ++i )
1096  {
1097  if( vec[i]->GetDefinition() ==aProton ||
1098  vec[i]->GetDefinition() == aNeutron ||
1099  vec[i]->GetDefinition() == G4Lambda::Lambda() ||
1100  vec[i]->GetDefinition() == G4XiZero::XiZero() ||
1101  vec[i]->GetDefinition() == G4XiMinus::XiMinus() ||
1102  vec[i]->GetDefinition() == G4OmegaMinus::OmegaMinus() ||
1103  vec[i]->GetDefinition() == G4SigmaPlus::SigmaPlus()||
1104  vec[i]->GetDefinition() == G4SigmaZero::SigmaZero()||
1105  vec[i]->GetDefinition() == G4SigmaMinus::SigmaMinus()) ++numberofFinalStateNucleons;
1106  if( vec[i]->GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
1107  if( vec[i]->GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
1108  if( vec[i]->GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
1109  if( vec[i]->GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
1110  if( vec[i]->GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
1111  if( vec[i]->GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
1112  if( vec[i]->GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
1113  if( vec[i]->GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
1114  if( vec[i]->GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
1115  vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
1116  }
1117  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1118  if(veryForward) numberofFinalStateNucleons++;
1119  numberofFinalStateNucleons = std::max( 1, numberofFinalStateNucleons );
1120  //
1121  // leadFlag will be true
1122  // iff original particle is at least as heavy as K+ and not a proton or neutron AND
1123  // if
1124  // incident particle is at least as heavy as K+ and it is not a proton or neutron
1125  // leadFlag is set to the incident particle
1126  // or
1127  // target particle is at least as heavy as K+ and it is not a proton or neutron
1128  // leadFlag is set to the target particle
1129  //
1130  G4bool leadingStrangeParticleHasChanged = true;
1131  if( leadFlag )
1132  {
1133  if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1134  leadingStrangeParticleHasChanged = false;
1135  if( leadingStrangeParticleHasChanged &&
1136  ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
1137  leadingStrangeParticleHasChanged = false;
1138  if( leadingStrangeParticleHasChanged )
1139  {
1140  for( i=0; i<vecLen; i++ )
1141  {
1142  if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1143  {
1144  leadingStrangeParticleHasChanged = false;
1145  break;
1146  }
1147  }
1148  }
1149  if( leadingStrangeParticleHasChanged )
1150  {
1151  G4bool leadTest =
1152  (leadingStrangeParticle.GetDefinition() == aKaonMinus ||
1153  leadingStrangeParticle.GetDefinition() == aKaonZeroL ||
1154  leadingStrangeParticle.GetDefinition() == aKaonZeroS ||
1155  leadingStrangeParticle.GetDefinition() == aKaonPlus ||
1156  leadingStrangeParticle.GetDefinition() == aPiMinus ||
1157  leadingStrangeParticle.GetDefinition() == aPiZero ||
1158  leadingStrangeParticle.GetDefinition() == aPiPlus);
1159  G4bool targetTest = false;
1160  /* (targetParticle.GetDefinition() == aKaonMinus ||
1161  targetParticle.GetDefinition() == aKaonZeroL ||
1162  targetParticle.GetDefinition() == aKaonZeroS ||
1163  targetParticle.GetDefinition() == aKaonPlus ||
1164  targetParticle.GetDefinition() == aPiMinus ||
1165  targetParticle.GetDefinition() == aPiZero ||
1166  targetParticle.GetDefinition() == aPiPlus);
1167  */
1168  // following modified by JLC 22-Oct-97
1169 
1170  if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
1171  {
1172  targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1173  targetHasChanged = true;
1174  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1175  }
1176  else
1177  {
1178  currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1179  incidentHasChanged = false;
1180  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1181  }
1182  }
1183  } // end of if( leadFlag )
1184 
1185  pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1186  pseudoParticle[3].SetMass( mOriginal*GeV );
1187  pseudoParticle[3].SetTotalEnergy(
1188  std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
1189 
1190 // G4double ekin0 = pseudoParticle[3].GetKineticEnergy()/GeV;
1191 
1192  const G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
1193  G4int diff = 0;
1194  if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() ) diff = 1;
1195  if(numberofFinalStateNucleons == 1) diff = 0;
1196  pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
1197  pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1198  pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1199 
1200  G4double theoreticalKinetic =
1201  pseudoParticle[3].GetTotalEnergy()/MeV +
1202  pseudoParticle[4].GetTotalEnergy()/MeV -
1203  currentParticle.GetMass()/MeV -
1204  targetParticle.GetMass()/MeV;
1205 
1206  G4double simulatedKinetic =
1207  currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
1208 
1209  pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
1210  pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
1211  pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
1212 
1213  pseudoParticle[7].SetZero();
1214  pseudoParticle[7] = pseudoParticle[7] + currentParticle;
1215  pseudoParticle[7] = pseudoParticle[7] + targetParticle;
1216 
1217  for( i=0; i<vecLen; ++i )
1218  {
1219  pseudoParticle[7] = pseudoParticle[7] + *vec[i];
1220  simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
1221  theoreticalKinetic -= vec[i]->GetMass()/MeV;
1222  }
1223  if( vecLen <= 16 && vecLen > 0 )
1224  {
1225  // must create a new set of ReactionProducts here because GenerateNBody will
1226  // modify the momenta for the particles, and we don't want to do this
1227  //
1228  G4ReactionProduct tempR[130];
1229  //G4ReactionProduct *tempR = new G4ReactionProduct [vecLen+2];
1230  tempR[0] = currentParticle;
1231  tempR[1] = targetParticle;
1232  for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
1233  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
1234  tempV.Initialize( vecLen+2 );
1235  G4int tempLen = 0;
1236  for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
1237  constantCrossSection = true;
1238 
1239  wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
1240  pseudoParticle[4].GetTotalEnergy()/MeV,
1241  constantCrossSection, tempV, tempLen );
1242  if(wgt>-.5)
1243  {
1244  theoreticalKinetic = 0.0;
1245  for( i=0; i<tempLen; ++i )
1246  {
1247  pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
1248  theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
1249  }
1250  }
1251  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1252  //delete [] tempR;
1253  }
1254  //
1255  // Make sure, that the kinetic energies are correct
1256  //
1257  if( simulatedKinetic != 0.0 )
1258  {
1259  wgt = (theoreticalKinetic)/simulatedKinetic;
1260  theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
1261  simulatedKinetic = theoreticalKinetic;
1262  currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1263  pp = currentParticle.GetTotalMomentum()/MeV;
1264  pp1 = currentParticle.GetMomentum().mag()/MeV;
1265  if( pp1 < 1.0e-6*GeV )
1266  {
1267  rthnve = pi*G4UniformRand();
1268  phinve = twopi*G4UniformRand();
1269  currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
1270  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
1271  pp*std::cos(rthnve)*MeV );
1272  }
1273  else
1274  {
1275  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
1276  }
1277  theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
1278  targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1279  simulatedKinetic += theoreticalKinetic;
1280  pp = targetParticle.GetTotalMomentum()/MeV;
1281  pp1 = targetParticle.GetMomentum().mag()/MeV;
1282  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1283  if( pp1 < 1.0e-6*GeV )
1284  {
1285  rthnve = pi*G4UniformRand();
1286  phinve = twopi*G4UniformRand();
1287  targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
1288  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
1289  pp*std::cos(rthnve)*MeV );
1290  } else {
1291  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1292  }
1293  for( i=0; i<vecLen; ++i )
1294  {
1295  theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
1296  simulatedKinetic += theoreticalKinetic;
1297  vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
1298  pp = vec[i]->GetTotalMomentum()/MeV;
1299  pp1 = vec[i]->GetMomentum().mag()/MeV;
1300  if( pp1 < 1.0e-6*GeV )
1301  {
1302  rthnve = pi*G4UniformRand();
1303  phinve = twopi*G4UniformRand();
1304  vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
1305  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
1306  pp*std::cos(rthnve)*MeV );
1307  }
1308  else
1309  vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
1310  }
1311  }
1312  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1313  Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
1314  modifiedOriginal, originalIncident, targetNucleus,
1315  currentParticle, targetParticle, vec, vecLen );
1316  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1317  //
1318  // add black track particles
1319  // the total number of particles produced is restricted to 198
1320  // this may have influence on very high energies
1321  //
1322  if( atomicWeight >= 1.5 )
1323  {
1324  // npnb is number of proton/neutron black track particles
1325  // ndta is the number of deuterons, tritons, and alphas produced
1326  // epnb is the kinetic energy available for proton/neutron black track particles
1327  // edta is the kinetic energy available for deuteron/triton/alpha particles
1328  //
1329  G4double epnb, edta;
1330  G4int npnb = 0;
1331  G4int ndta = 0;
1332 
1333  epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
1334  edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
1335  const G4double pnCutOff = 0.001;
1336  const G4double dtaCutOff = 0.001;
1337  const G4double kineticMinimum = 1.e-6;
1338  const G4double kineticFactor = -0.010;
1339  G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
1340  const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
1341  if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
1342  if( epnb >= pnCutOff )
1343  {
1344  npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
1345  if( numberofFinalStateNucleons + npnb > atomicWeight )
1346  npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
1347  npnb = std::min( npnb, 127-vecLen );
1348  }
1349  if( edta >= dtaCutOff )
1350  {
1351  ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
1352  ndta = std::min( ndta, 127-vecLen );
1353  }
1354  G4double spall = numberofFinalStateNucleons;
1355  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1356 
1357  AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
1358  modifiedOriginal, spall, targetNucleus,
1359  vec, vecLen );
1360 
1361 // G4double jpw=0;
1362 // jpw+=GetQValue(&currentParticle);
1363 // jpw+=GetQValue(&targetParticle);
1364 // for( i=0; i<vecLen; ++i )jpw += GetQValue(vec[i]);
1365 // G4cout << "JPW ### "<<jpw<<G4endl;
1366  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1367  }
1368  //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
1369  // MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
1370  //
1371  // calculate time delay for nuclear reactions
1372  //
1373  if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
1374  currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
1375  else
1376  currentParticle.SetTOF( 1.0 );
1377  return true;
1378  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1379  }
1380 
1381  void FullModelReactionDynamics::SuppressChargedPions(
1382  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
1383  G4int &vecLen,
1384  const G4ReactionProduct &modifiedOriginal,
1385  G4ReactionProduct &currentParticle,
1386  G4ReactionProduct &targetParticle,
1387  const G4Nucleus &targetNucleus,
1388  G4bool &incidentHasChanged,
1389  G4bool &targetHasChanged )
1390  {
1391  // this code was originally in the fortran code TWOCLU
1392  //
1393  // suppress charged pions, for various reasons
1394  //
1395  const G4double atomicWeight = targetNucleus.GetN_asInt();
1396  const G4double atomicNumber = targetNucleus.GetZ_asInt();
1397  const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
1398 
1399  // G4ParticleDefinition *aGamma = G4Gamma::Gamma();
1400  G4ParticleDefinition *aProton = G4Proton::Proton();
1401  G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
1402  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1403  G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
1404  G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1405  G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1406 
1407  const G4bool antiTest =
1408  modifiedOriginal.GetDefinition() != anAntiProton &&
1409  modifiedOriginal.GetDefinition() != anAntiNeutron;
1410  if( antiTest && (
1411  // currentParticle.GetDefinition() == aGamma ||
1412  currentParticle.GetDefinition() == aPiPlus ||
1413  currentParticle.GetDefinition() == aPiMinus ) &&
1414  ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1415  ( G4UniformRand() <= atomicWeight/300.0 ) )
1416  {
1417  if( G4UniformRand() > atomicNumber/atomicWeight )
1418  currentParticle.SetDefinitionAndUpdateE( aNeutron );
1419  else
1420  currentParticle.SetDefinitionAndUpdateE( aProton );
1421  incidentHasChanged = true;
1422  }
1423  /* if( antiTest && (
1424  // targetParticle.GetDefinition() == aGamma ||
1425  targetParticle.GetDefinition() == aPiPlus ||
1426  targetParticle.GetDefinition() == aPiMinus ) &&
1427  ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1428  ( G4UniformRand() <= atomicWeight/300.0 ) )
1429  {
1430  if( G4UniformRand() > atomicNumber/atomicWeight )
1431  targetParticle.SetDefinitionAndUpdateE( aNeutron );
1432  else
1433  targetParticle.SetDefinitionAndUpdateE( aProton );
1434  targetHasChanged = true;
1435  }*/
1436  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1437  for( G4int i=0; i<vecLen; ++i )
1438  {
1439  if( antiTest && (
1440  // vec[i]->GetDefinition() == aGamma ||
1441  vec[i]->GetDefinition() == aPiPlus ||
1442  vec[i]->GetDefinition() == aPiMinus ) &&
1443  ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1444  ( G4UniformRand() <= atomicWeight/300.0 ) )
1445  {
1446  if( G4UniformRand() > atomicNumber/atomicWeight )
1447  vec[i]->SetDefinitionAndUpdateE( aNeutron );
1448  else
1449  vec[i]->SetDefinitionAndUpdateE( aProton );
1450  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1451  }
1452  }
1453  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1454  }
1455 
1456  G4bool FullModelReactionDynamics::TwoCluster(
1457  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
1458  G4int &vecLen,
1459  G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
1460  const G4HadProjectile *originalIncident, // the original incident particle
1461  G4ReactionProduct &currentParticle,
1462  G4ReactionProduct &targetParticle,
1463  const G4Nucleus &targetNucleus,
1464  G4bool &incidentHasChanged,
1465  G4bool &targetHasChanged,
1466  G4bool leadFlag,
1467  G4ReactionProduct &leadingStrangeParticle )
1468  {
1469  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1470  // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
1471  //
1472  // Generation of X- and PT- values for incident, target, and all secondary particles
1473  //
1474  // A simple two cluster model is used.
1475  // This should be sufficient for low energy interactions.
1476  //
1477 
1478  // + debugging
1479  // raise(SIGSEGV);
1480  // - debugging
1481 
1482  G4int i;
1483  G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1484  G4ParticleDefinition *aProton = G4Proton::Proton();
1485  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1486  G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1487  G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
1488  G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
1489  const G4double protonMass = aProton->GetPDGMass()/MeV;
1490  const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
1491  const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1492  const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1493  const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
1494  G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1495  G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
1496  targetMass*targetMass +
1497  2.0*targetMass*etOriginal ); // GeV
1498  G4double currentMass = currentParticle.GetMass()/GeV;
1499  targetMass = targetParticle.GetMass()/GeV;
1500 
1501  if( currentMass == 0.0 && targetMass == 0.0 )
1502  {
1503  G4double ek = currentParticle.GetKineticEnergy();
1504  G4ThreeVector m = currentParticle.GetMomentum();
1505  currentParticle = *vec[0];
1506  targetParticle = *vec[1];
1507  for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
1508  if(vecLen<2)
1509  {
1510  for(G4int i=0; i<vecLen; i++) delete vec[i];
1511  vecLen = 0;
1512  throw G4HadReentrentException(__FILE__, __LINE__,
1513  "FullModelReactionDynamics::TwoCluster: Negative number of particles");
1514  }
1515  delete vec[vecLen-1];
1516  delete vec[vecLen-2];
1517  vecLen -= 2;
1518  currentMass = currentParticle.GetMass()/GeV;
1519  targetMass = targetParticle.GetMass()/GeV;
1520  incidentHasChanged = true;
1521  targetHasChanged = true;
1522  currentParticle.SetKineticEnergy( ek );
1523  currentParticle.SetMomentum( m );
1524  }
1525  const G4double atomicWeight = targetNucleus.GetN_asInt();
1526  const G4double atomicNumber = targetNucleus.GetZ_asInt();
1527  //
1528  // particles have been distributed in forward and backward hemispheres
1529  // in center of mass system of the hadron nucleon interaction
1530  //
1531  // incident is always in forward hemisphere
1532  G4int forwardCount = 1; // number of particles in forward hemisphere
1533  currentParticle.SetSide( 1 );
1534  G4double forwardMass = currentParticle.GetMass()/GeV;
1535  G4double cMass = forwardMass;
1536 
1537  // target is always in backward hemisphere
1538  G4int backwardCount = 1; // number of particles in backward hemisphere
1539  G4int backwardNucleonCount = 1; // number of nucleons in backward hemisphere
1540  targetParticle.SetSide( -1 );
1541  G4double backwardMass = targetParticle.GetMass()/GeV;
1542  G4double bMass = backwardMass;
1543 
1544  for( i=0; i<vecLen; ++i )
1545  {
1546  if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
1547  // to take care of the case where vec has been preprocessed by GenerateXandPt
1548  // and some of them have been set to -2 or -3
1549  if( vec[i]->GetSide() == -1 )
1550  {
1551  ++backwardCount;
1552  backwardMass += vec[i]->GetMass()/GeV;
1553  }
1554  else
1555  {
1556  ++forwardCount;
1557  forwardMass += vec[i]->GetMass()/GeV;
1558  }
1559  }
1560  //
1561  // nucleons and some pions from intranuclear cascade
1562  //
1563  G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
1564  if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
1565  const G4double afc = 0.312 + 0.2 * std::log(term1);
1566  G4double xtarg;
1567  if( centerofmassEnergy < 2.0+G4UniformRand() ) // added +2 below, JLC 4Jul97
1568  xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
1569  else
1570  xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
1571  if( xtarg <= 0.0 )xtarg = 0.01;
1572  G4int nuclearExcitationCount = Poisson( xtarg );
1573  if(atomicWeight<1.0001) nuclearExcitationCount = 0;
1574  G4int extraNucleonCount = 0;
1575  G4double extraMass = 0.0;
1576  G4double extraNucleonMass = 0.0;
1577  if( nuclearExcitationCount > 0 )
1578  {
1579  G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );
1580  const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
1581  //
1582  // NOTE: in TWOCLU, these new particles were given negative codes
1583  // here we use NewlyAdded = true instead
1584  //
1585 // G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
1586  for( i=0; i<nuclearExcitationCount; ++i )
1587  {
1588  G4ReactionProduct* pVec = new G4ReactionProduct();
1589  if( G4UniformRand() < nucsup[momentumBin] ) // add proton or neutron
1590  {
1591  if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
1592  // HPW: looks like a gheisha bug
1593  pVec->SetDefinition( aProton );
1594  else
1595  pVec->SetDefinition( aNeutron );
1596  ++backwardNucleonCount;
1597  ++extraNucleonCount;
1598  extraNucleonMass += pVec->GetMass()/GeV;
1599  }
1600  else
1601  { // add a pion
1602  G4double ran = G4UniformRand();
1603  if( ran < 0.3181 )
1604  pVec->SetDefinition( aPiPlus );
1605  else if( ran < 0.6819 )
1606  pVec->SetDefinition( aPiZero );
1607  else
1608  pVec->SetDefinition( aPiMinus );
1609  }
1610  pVec->SetSide( -2 ); // backside particle
1611  extraMass += pVec->GetMass()/GeV;
1612  pVec->SetNewlyAdded( true );
1613  vec.SetElement( vecLen++, pVec );
1614  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1615  }
1616  }
1617  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1618  G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
1619  G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
1620  G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1621  G4bool secondaryDeleted;
1622  G4double pMass;
1623  while( eAvailable <= 0.0 ) // must eliminate a particle
1624  {
1625  secondaryDeleted = false;
1626  for( i=(vecLen-1); i>=0; --i )
1627  {
1628  if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
1629  {
1630  pMass = vec[i]->GetMass()/GeV;
1631  for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1632  --forwardCount;
1633  forwardEnergy += pMass;
1634  forwardMass -= pMass;
1635  secondaryDeleted = true;
1636  break;
1637  }
1638  else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
1639  {
1640  pMass = vec[i]->GetMass()/GeV;
1641  for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1642  --backwardCount;
1643  backwardEnergy += pMass;
1644  backwardMass -= pMass;
1645  secondaryDeleted = true;
1646  break;
1647  }
1648  } // breaks go down to here
1649  if( secondaryDeleted )
1650  {
1651  G4ReactionProduct *temp = vec[vecLen-1];
1652  delete temp;
1653  --vecLen;
1654  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1655  }
1656  else
1657  {
1658  if( vecLen == 0 )
1659  {
1660  return false; // all secondaries have been eliminated
1661  }
1662  if( targetParticle.GetSide() == -1 )
1663  {
1664  pMass = targetParticle.GetMass()/GeV;
1665  targetParticle = *vec[0];
1666  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1667  --backwardCount;
1668  backwardEnergy += pMass;
1669  backwardMass -= pMass;
1670  secondaryDeleted = true;
1671  }
1672  else if( targetParticle.GetSide() == 1 )
1673  {
1674  pMass = targetParticle.GetMass()/GeV;
1675  targetParticle = *vec[0];
1676  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1677  --forwardCount;
1678  forwardEnergy += pMass;
1679  forwardMass -= pMass;
1680  secondaryDeleted = true;
1681  }
1682  if( secondaryDeleted )
1683  {
1684  G4ReactionProduct *temp = vec[vecLen-1];
1685  delete temp;
1686  --vecLen;
1687  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1688  }
1689  else
1690  {
1691  if( currentParticle.GetSide() == -1 )
1692  {
1693  pMass = currentParticle.GetMass()/GeV;
1694  currentParticle = *vec[0];
1695  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1696  --backwardCount;
1697  backwardEnergy += pMass;
1698  backwardMass -= pMass;
1699  secondaryDeleted = true;
1700  }
1701  else if( currentParticle.GetSide() == 1 )
1702  {
1703  pMass = currentParticle.GetMass()/GeV;
1704  currentParticle = *vec[0];
1705  for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1706  --forwardCount;//This line can cause infinite loop
1707  forwardEnergy += pMass;
1708  forwardMass -= pMass;
1709  secondaryDeleted = true;
1710  }
1711  if( secondaryDeleted )
1712  {
1713  G4ReactionProduct *temp = vec[vecLen-1];
1714  delete temp;
1715  --vecLen;
1716  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1717  }
1718  else break;
1719  }
1720  }
1721  eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1722  }
1723  //
1724  // This is the start of the TwoCluster function
1725  // Choose masses for the 3 clusters:
1726  // forward cluster
1727  // backward meson cluster
1728  // backward nucleon cluster
1729  //
1730  G4double rmc = 0.0, rmd = 0.0; // rme = 0.0;
1731  const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
1732  const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
1733 
1734  if( forwardCount == 0) return false;
1735 
1736  if( forwardCount == 1 )rmc = forwardMass;
1737  else
1738  {
1739 // G4int ntc = std::min(5,forwardCount); // check if offset by 1 @@
1740  G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
1741  rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1742  }
1743  if( backwardCount == 1 )rmd = backwardMass;
1744  else
1745  {
1746 // G4int ntc = std::min(5,backwardCount); // check, if offfset by 1 @@
1747  G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
1748  rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1749  }
1750  while( rmc+rmd > centerofmassEnergy )
1751  {
1752  if( (rmc <= forwardMass) && (rmd <= backwardMass) )
1753  {
1754  G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
1755  rmc *= temp;
1756  rmd *= temp;
1757  }
1758  else
1759  {
1760  rmc = 0.1*forwardMass + 0.9*rmc;
1761  rmd = 0.1*backwardMass + 0.9*rmd;
1762  }
1763  }
1764  // note that rme is never used below this section
1765  //
1766  //if( nuclearExcitationCount == 0 )rme = 0.0;
1767  //else if( nuclearExcitationCount == 1 )rme = extraMass;
1768  //else
1769  //{
1770  // G4int ntc = std::min(5,nuclearExcitationCount)-1;
1771  // rme = extraMass + std::pow(-std::log(1.-G4UniformRand()),cpar[ntc])/gpar[ntc];
1772  //}
1773  //
1774  // Set beam, target of first interaction in centre of mass system
1775  //
1776  G4ReactionProduct pseudoParticle[8];
1777  for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
1778 
1779  pseudoParticle[1].SetMass( mOriginal*GeV );
1780  pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
1781  pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1782 
1783  pseudoParticle[2].SetMass( protonMass*MeV );
1784  pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
1785  pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
1786  //
1787  // transform into centre of mass system
1788  //
1789  pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
1790  pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
1791  pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
1792 
1793  const G4double pfMin = 0.0001;
1794  G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
1795  pf *= pf;
1796  pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
1797  pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
1798  //
1799  // set final state masses and energies in centre of mass system
1800  //
1801  pseudoParticle[3].SetMass( rmc*GeV );
1802  pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
1803 
1804  pseudoParticle[4].SetMass( rmd*GeV );
1805  pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
1806  //
1807  // set |T| and |TMIN|
1808  //
1809  const G4double bMin = 0.01;
1810  const G4double b1 = 4.0;
1811  const G4double b2 = 1.6;
1812  G4double t = std::log( 1.0-G4UniformRand() ) / std::max( bMin, b1+b2*std::log(pOriginal) );
1813  G4double t1 =
1814  pseudoParticle[1].GetTotalEnergy()/GeV - pseudoParticle[3].GetTotalEnergy()/GeV;
1815  G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
1816  G4double tacmin = t1*t1 - (pin-pf)*(pin-pf);
1817  //
1818  // calculate (std::sin(teta/2.)^2 and std::cos(teta), set azimuth angle phi
1819  //
1820  const G4double smallValue = 1.0e-10;
1821  G4double dumnve = 4.0*pin*pf;
1822  if( dumnve == 0.0 )dumnve = smallValue;
1823  G4double ctet = std::max( -1.0, std::min( 1.0, 1.0+2.0*(t-tacmin)/dumnve ) );
1824  dumnve = std::max( 0.0, 1.0-ctet*ctet );
1825  G4double stet = std::sqrt(dumnve);
1826  G4double phi = G4UniformRand() * twopi;
1827  //
1828  // calculate final state momenta in centre of mass system
1829  //
1830  pseudoParticle[3].SetMomentum( pf*stet*std::sin(phi)*GeV,
1831  pf*stet*std::cos(phi)*GeV,
1832  pf*ctet*GeV );
1833  pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1834  //
1835  // simulate backward nucleon cluster in lab. system and transform in cms
1836  //
1837  G4double pp, pp1, rthnve, phinve;
1838  if( nuclearExcitationCount > 0 )
1839  {
1840  const G4double ga = 1.2;
1841  G4double ekit1 = 0.04;
1842  G4double ekit2 = 0.6;
1843  if( ekOriginal <= 5.0 )
1844  {
1845  ekit1 *= ekOriginal*ekOriginal/25.0;
1846  ekit2 *= ekOriginal*ekOriginal/25.0;
1847  }
1848  const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
1849  for( i=0; i<vecLen; ++i )
1850  {
1851  if( vec[i]->GetSide() == -2 )
1852  {
1853  G4double kineticE =
1854  std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
1855  vec[i]->SetKineticEnergy( kineticE*GeV );
1856  G4double vMass = vec[i]->GetMass()/MeV;
1857  G4double totalE = kineticE + vMass;
1858  pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
1859  G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
1860  G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
1861  phi = twopi*G4UniformRand();
1862  vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
1863  pp*sint*std::cos(phi)*MeV,
1864  pp*cost*MeV );
1865  vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
1866  }
1867  }
1868  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1869  }
1870  //
1871  // fragmentation of forward cluster and backward meson cluster
1872  //
1873  currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
1874  currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1875 
1876  targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
1877  targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1878 
1879  pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1880  pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
1881  pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1882 
1883  pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
1884  pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
1885  pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1886 
1887  G4double wgt;
1888  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1889  if( forwardCount > 1 ) // tempV will contain the forward particles
1890  {
1891  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
1892  tempV.Initialize( forwardCount );
1893  G4bool constantCrossSection = true;
1894  G4int tempLen = 0;
1895  if( currentParticle.GetSide() == 1 )
1896  tempV.SetElement( tempLen++, &currentParticle );
1897  if( targetParticle.GetSide() == 1 )
1898  tempV.SetElement( tempLen++, &targetParticle );
1899  for( i=0; i<vecLen; ++i )
1900  {
1901  if( vec[i]->GetSide() == 1 )
1902  {
1903  if( tempLen < 18 )
1904  tempV.SetElement( tempLen++, vec[i] );
1905  else
1906  {
1907  vec[i]->SetSide( -1 );
1908  continue;
1909  }
1910  }
1911  }
1912  if( tempLen >= 2 )
1913  {
1914  wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
1915  constantCrossSection, tempV, tempLen );
1916  if( currentParticle.GetSide() == 1 )
1917  currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
1918  if( targetParticle.GetSide() == 1 )
1919  targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
1920  for( i=0; i<vecLen; ++i )
1921  {
1922  if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
1923  }
1924  }
1925  }
1926  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1927  if( backwardCount > 1 ) // tempV will contain the backward particles,
1928  { // but not those created from the intranuclear cascade
1929  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
1930  tempV.Initialize( backwardCount );
1931  G4bool constantCrossSection = true;
1932  G4int tempLen = 0;
1933  if( currentParticle.GetSide() == -1 )
1934  tempV.SetElement( tempLen++, &currentParticle );
1935  if( targetParticle.GetSide() == -1 )
1936  tempV.SetElement( tempLen++, &targetParticle );
1937  for( i=0; i<vecLen; ++i )
1938  {
1939  if( vec[i]->GetSide() == -1 )
1940  {
1941  if( tempLen < 18 )
1942  tempV.SetElement( tempLen++, vec[i] );
1943  else
1944  {
1945  vec[i]->SetSide( -2 );
1946  vec[i]->SetKineticEnergy( 0.0 );
1947  vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
1948  continue;
1949  }
1950  }
1951  }
1952  if( tempLen >= 2 )
1953  {
1954  wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
1955  constantCrossSection, tempV, tempLen );
1956  if( currentParticle.GetSide() == -1 )
1957  currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
1958  if( targetParticle.GetSide() == -1 )
1959  targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1960  for( i=0; i<vecLen; ++i )
1961  {
1962  if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1963  }
1964  }
1965  }
1966  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1967  //
1968  // Lorentz transformation in lab system
1969  //
1970  G4int numberofFinalStateNucleons = 0;
1971  if( currentParticle.GetDefinition() ==aProton ||
1972  currentParticle.GetDefinition() == aNeutron ||
1973  currentParticle.GetDefinition() == aSigmaMinus||
1974  currentParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
1975  currentParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
1976  currentParticle.GetDefinition() == G4XiZero::XiZero()||
1977  currentParticle.GetDefinition() == G4XiMinus::XiMinus()||
1978  currentParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
1979  currentParticle.GetDefinition() == G4Lambda::Lambda()) ++numberofFinalStateNucleons;
1980  currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
1981  if( targetParticle.GetDefinition() ==aProton ||
1982  targetParticle.GetDefinition() == aNeutron ||
1983  targetParticle.GetDefinition() == G4Lambda::Lambda() ||
1984  targetParticle.GetDefinition() == G4XiZero::XiZero()||
1985  targetParticle.GetDefinition() == G4XiMinus::XiMinus()||
1986  targetParticle.GetDefinition() == G4OmegaMinus::OmegaMinus()||
1987  targetParticle.GetDefinition() == G4SigmaZero::SigmaZero()||
1988  targetParticle.GetDefinition() == G4SigmaPlus::SigmaPlus()||
1989  targetParticle.GetDefinition() == aSigmaMinus) ++numberofFinalStateNucleons;
1990  if( targetParticle.GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
1991  if( targetParticle.GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
1992  if( targetParticle.GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
1993  if( targetParticle.GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
1994  if( targetParticle.GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
1995  if( targetParticle.GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
1996  if( targetParticle.GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
1997  if( targetParticle.GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
1998  if( targetParticle.GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
1999  targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
2000  for( i=0; i<vecLen; ++i )
2001  {
2002  if( vec[i]->GetDefinition() ==aProton ||
2003  vec[i]->GetDefinition() == aNeutron ||
2004  vec[i]->GetDefinition() == G4Lambda::Lambda() ||
2005  vec[i]->GetDefinition() == G4XiZero::XiZero() ||
2006  vec[i]->GetDefinition() == G4XiMinus::XiMinus() ||
2007  vec[i]->GetDefinition() == G4OmegaMinus::OmegaMinus() ||
2008  vec[i]->GetDefinition() == G4SigmaPlus::SigmaPlus()||
2009  vec[i]->GetDefinition() == G4SigmaZero::SigmaZero()||
2010  vec[i]->GetDefinition() == aSigmaMinus) ++numberofFinalStateNucleons;
2011  if( vec[i]->GetDefinition() ==G4AntiProton::AntiProton()) --numberofFinalStateNucleons;
2012  if( vec[i]->GetDefinition() ==G4AntiNeutron::AntiNeutron()) --numberofFinalStateNucleons;
2013  if( vec[i]->GetDefinition() ==G4AntiSigmaMinus::AntiSigmaMinus()) --numberofFinalStateNucleons;
2014  if( vec[i]->GetDefinition() ==G4AntiSigmaPlus::AntiSigmaPlus()) --numberofFinalStateNucleons;
2015  if( vec[i]->GetDefinition() ==G4AntiSigmaZero::AntiSigmaZero()) --numberofFinalStateNucleons;
2016  if( vec[i]->GetDefinition() ==G4AntiLambda::AntiLambda()) --numberofFinalStateNucleons;
2017  if( vec[i]->GetDefinition() ==G4AntiXiZero::AntiXiZero()) --numberofFinalStateNucleons;
2018  if( vec[i]->GetDefinition() ==G4AntiXiMinus::AntiXiMinus()) --numberofFinalStateNucleons;
2019  if( vec[i]->GetDefinition() ==G4AntiOmegaMinus::AntiOmegaMinus()) --numberofFinalStateNucleons;
2020  vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
2021  }
2022  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2023  numberofFinalStateNucleons = std::max( 1, numberofFinalStateNucleons );
2024  //
2025  // sometimes the leading strange particle is lost, set it back
2026  //
2027  G4bool dum = true;
2028  if( leadFlag )
2029  {
2030  // leadFlag will be true
2031  // iff original particle is at least as heavy as K+ and not a proton or neutron AND
2032  // if
2033  // incident particle is at least as heavy as K+ and it is not a proton or neutron
2034  // leadFlag is set to the incident particle
2035  // or
2036  // target particle is at least as heavy as K+ and it is not a proton or neutron
2037  // leadFlag is set to the target particle
2038  //
2039  if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
2040  dum = false;
2041  else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
2042  dum = false;
2043  else
2044  {
2045  for( i=0; i<vecLen; ++i )
2046  {
2047  if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
2048  {
2049  dum = false;
2050  break;
2051  }
2052  }
2053  }
2054  if( dum )
2055  {
2056  G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
2057  G4double ekin;
2058  if( ((leadMass < protonMass) && (targetParticle.GetMass()/MeV < protonMass)) ||
2059  ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
2060  {
2061  ekin = targetParticle.GetKineticEnergy()/GeV;
2062  pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
2063  targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
2064  targetParticle.SetKineticEnergy( ekin*GeV );
2065  pp = targetParticle.GetTotalMomentum()/MeV; // new momentum
2066  if( pp1 < 1.0e-3 )
2067  {
2068  rthnve = pi*G4UniformRand();
2069  phinve = twopi*G4UniformRand();
2070  targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(rthnve)*MeV,
2071  pp*std::sin(rthnve)*std::sin(rthnve)*MeV,
2072  pp*std::cos(rthnve)*MeV );
2073  }
2074  else
2075  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2076 
2077  targetHasChanged = true;
2078  }
2079  else
2080  {
2081  ekin = currentParticle.GetKineticEnergy()/GeV;
2082  pp1 = currentParticle.GetMomentum().mag()/MeV;
2083  currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
2084  currentParticle.SetKineticEnergy( ekin*GeV );
2085  pp = currentParticle.GetTotalMomentum()/MeV;
2086  if( pp1 < 1.0e-3 )
2087  {
2088  rthnve = pi*G4UniformRand();
2089  phinve = twopi*G4UniformRand();
2090  currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(rthnve)*MeV,
2091  pp*std::sin(rthnve)*std::sin(rthnve)*MeV,
2092  pp*std::cos(rthnve)*MeV );
2093  }
2094  else
2095  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2096 
2097  incidentHasChanged = true;
2098  }
2099  }
2100  } // end of if( leadFlag )
2101  //
2102  // for various reasons, the energy balance is not sufficient,
2103  // check that, energy balance, angle of final system, etc.
2104  //
2105  pseudoParticle[4].SetMass( mOriginal*GeV );
2106  pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
2107  pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2108 
2109  const G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
2110  G4int diff = 0;
2111  if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() ) diff = 1;
2112  if(numberofFinalStateNucleons == 1) diff = 0;
2113  pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
2114  pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
2115  pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
2116 
2117 // G4double ekin0 = pseudoParticle[4].GetKineticEnergy()/GeV;
2118  G4double theoreticalKinetic =
2119  pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
2120 
2121  pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
2122  pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
2123  pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
2124 
2125  if( vecLen < 16 )
2126  {
2127  G4ReactionProduct tempR[130];
2128  //G4ReactionProduct *tempR = new G4ReactionProduct [vecLen+2];
2129  tempR[0] = currentParticle;
2130  tempR[1] = targetParticle;
2131  for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
2132 
2133  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
2134  tempV.Initialize( vecLen+2 );
2135  G4bool constantCrossSection = true;
2136  G4int tempLen = 0;
2137  for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
2138 
2139  if( tempLen >= 2 )
2140  {
2141  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2142  wgt = GenerateNBodyEvent(
2143  pseudoParticle[4].GetTotalEnergy()/MeV+pseudoParticle[5].GetTotalEnergy()/MeV,
2144  constantCrossSection, tempV, tempLen );
2145  theoreticalKinetic = 0.0;
2146  for( i=0; i<vecLen+2; ++i )
2147  {
2148  pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
2149  pseudoParticle[7].SetMass( tempV[i]->GetMass() );
2150  pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
2151  pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
2152  theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
2153  }
2154  }
2155  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2156  //delete [] tempR;
2157  }
2158  else
2159  {
2160  theoreticalKinetic -=
2161  ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
2162  for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
2163  }
2164  G4double simulatedKinetic =
2165  currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
2166  for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
2167  //
2168  // make sure that kinetic energies are correct
2169  // the backward nucleon cluster is not produced within proper kinematics!!!
2170  //
2171 
2172  if( simulatedKinetic != 0.0 )
2173  {
2174  wgt = (theoreticalKinetic)/simulatedKinetic;
2175  currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
2176  pp = currentParticle.GetTotalMomentum()/MeV;
2177  pp1 = currentParticle.GetMomentum().mag()/MeV;
2178  if( pp1 < 0.001*MeV )
2179  {
2180  rthnve = pi * G4UniformRand();
2181  phinve = twopi * G4UniformRand();
2182  currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
2183  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
2184  pp*std::cos(rthnve)*MeV );
2185  }
2186  else
2187  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2188 
2189  targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
2190  pp = targetParticle.GetTotalMomentum()/MeV;
2191  pp1 = targetParticle.GetMomentum().mag()/MeV;
2192  if( pp1 < 0.001*MeV )
2193  {
2194  rthnve = pi * G4UniformRand();
2195  phinve = twopi * G4UniformRand();
2196  targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
2197  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
2198  pp*std::cos(rthnve)*MeV );
2199  }
2200  else
2201  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2202 
2203  for( i=0; i<vecLen; ++i )
2204  {
2205  vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
2206  pp = vec[i]->GetTotalMomentum()/MeV;
2207  pp1 = vec[i]->GetMomentum().mag()/MeV;
2208  if( pp1 < 0.001 )
2209  {
2210  rthnve = pi * G4UniformRand();
2211  phinve = twopi * G4UniformRand();
2212  vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
2213  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
2214  pp*std::cos(rthnve)*MeV );
2215  }
2216  else
2217  vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2218  }
2219  }
2220  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2221  Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
2222  modifiedOriginal, originalIncident, targetNucleus,
2223  currentParticle, targetParticle, vec, vecLen );
2224  //
2225  // add black track particles
2226  // the total number of particles produced is restricted to 198
2227  // this may have influence on very high energies
2228  //
2229  if( atomicWeight >= 1.5 )
2230  {
2231  // npnb is number of proton/neutron black track particles
2232  // ndta is the number of deuterons, tritons, and alphas produced
2233  // epnb is the kinetic energy available for proton/neutron black track particles
2234  // edta is the kinetic energy available for deuteron/triton/alpha particles
2235  //
2236  G4double epnb, edta;
2237  G4int npnb = 0;
2238  G4int ndta = 0;
2239 
2240  epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
2241  edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
2242  const G4double pnCutOff = 0.001; // GeV
2243  const G4double dtaCutOff = 0.001; // GeV
2244  const G4double kineticMinimum = 1.e-6;
2245  const G4double kineticFactor = -0.005;
2246 
2247  G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2248  const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
2249  if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
2250 
2251  if( epnb >= pnCutOff )
2252  {
2253  npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
2254  if( numberofFinalStateNucleons + npnb > atomicWeight )
2255  npnb = G4int(atomicWeight - numberofFinalStateNucleons);
2256  npnb = std::min( npnb, 127-vecLen );
2257  }
2258  if( edta >= dtaCutOff )
2259  {
2260  ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
2261  ndta = std::min( ndta, 127-vecLen );
2262  }
2263  G4double spall = numberofFinalStateNucleons;
2264  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2265 
2266  AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
2267  modifiedOriginal, spall, targetNucleus,
2268  vec, vecLen );
2269 
2270  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2271  }
2272  //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
2273  // MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2274  //
2275  // calculate time delay for nuclear reactions
2276  //
2277  if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2278  currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2279  else
2280  currentParticle.SetTOF( 1.0 );
2281 
2282  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2283  return true;
2284  }
2285 
2286  void FullModelReactionDynamics::TwoBody(
2287  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2288  G4int &vecLen,
2289  G4ReactionProduct &modifiedOriginal,
2290  const G4DynamicParticle */*originalTarget*/,
2291  G4ReactionProduct &currentParticle,
2292  G4ReactionProduct &targetParticle,
2293  const G4Nucleus &targetNucleus,
2294  G4bool &/* targetHasChanged*/ )
2295  {
2296  // G4cout<<"TwoBody called"<<G4endl;
2297  //
2298  // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
2299  //
2300  // Generation of momenta for elastic and quasi-elastic 2 body reactions
2301  //
2302  // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
2303  // The b values are parametrizations from experimental data.
2304  // Not available values are taken from those of similar reactions.
2305  //
2306  G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2307  G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2308  G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2309  G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
2310  G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
2311  G4ParticleDefinition *aKaonZeroS = G4KaonZeroShort::KaonZeroShort();
2312  G4ParticleDefinition *aKaonZeroL = G4KaonZeroLong::KaonZeroLong();
2313 
2314  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2315  static const G4double expxu = 82.; // upper bound for arg. of exp
2316  static const G4double expxl = -expxu; // lower bound for arg. of exp
2317 
2318  const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
2319 // const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
2320 // const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
2321  const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
2322  G4double currentMass = currentParticle.GetMass()/GeV;
2323  G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
2324 
2325  targetMass = targetParticle.GetMass()/GeV;
2326  const G4double atomicWeight = targetNucleus.GetN_asInt();
2327  // G4cout<<"Atomic weight is found to be: "<<atomicWeight<<G4endl;
2328  G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
2329  G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
2330 
2331  G4double cmEnergy = std::sqrt( currentMass*currentMass +
2332  targetMass*targetMass +
2333  2.0*targetMass*etCurrent ); // in GeV
2334 
2335  //if( (pOriginal < 0.1) ||
2336  // (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
2337  // Continue with original particle, but spend the nuclear evaporation energy
2338  // targetParticle.SetMass( 0.0 ); // flag that the target doesn't exist
2339  //else // Two-body scattering is possible
2340 
2341  if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
2342  {
2343  targetParticle.SetMass( 0.0 ); // flag that the target particle doesn't exist
2344  }
2345  else
2346  {
2347 // moved this if-block to a later stage, i.e. to the assignment of the scattering angle
2348 // @@@@@ double-check.
2349 // if( targetParticle.GetDefinition() == aKaonMinus ||
2350 // targetParticle.GetDefinition() == aKaonZeroL ||
2351 // targetParticle.GetDefinition() == aKaonZeroS ||
2352 // targetParticle.GetDefinition() == aKaonPlus ||
2353 // targetParticle.GetDefinition() == aPiMinus ||
2354 // targetParticle.GetDefinition() == aPiZero ||
2355 // targetParticle.GetDefinition() == aPiPlus )
2356 // {
2357 // if( G4UniformRand() < 0.5 )
2358 // targetParticle.SetDefinitionAndUpdateE( aNeutron );
2359 // else
2360 // targetParticle.SetDefinitionAndUpdateE( aProton );
2361 // targetHasChanged = true;
2362 // targetMass = targetParticle.GetMass()/GeV;
2363 // }
2364  //
2365  // Set masses and momenta for final state particles
2366  //
2367  /*
2368  G4cout<<"Check 0"<<G4endl;
2369  G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()/GeV<<G4endl;
2370  G4cout<<"target mass: "<<targetParticle.GetMass()/GeV<<G4endl;
2371  G4cout<<targetParticle.GetDefinition()->GetParticleName()<<G4endl;
2372  G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()/GeV<<G4endl;
2373  G4cout<<"current mass: "<<currentParticle.GetMass()/GeV<<G4endl;
2374  G4cout<<currentParticle.GetDefinition()->GetParticleName()<<G4endl;
2375  */
2376  G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
2377  pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
2378  // G4cout << "pf: " << pf<< G4endl;
2379 
2380  if( pf <= 0.)// 0.001 )
2381  {
2382  for(G4int i=0; i<vecLen; i++) delete vec[i];
2383  vecLen = 0;
2384  throw G4HadronicException(__FILE__, __LINE__, "FullModelReactionDynamics::TwoBody: pf is too small ");
2385  }
2386 
2387  pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
2388  //
2389  // Set beam and target in centre of mass system
2390  //
2391  G4ReactionProduct pseudoParticle[3];
2392  /* //Marker
2393  if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron")
2394  targetParticle.GetDefinition() == aKaonMinus ||
2395  targetParticle.GetDefinition() == aKaonZeroL ||
2396  targetParticle.GetDefinition() == aKaonZeroS ||
2397  targetParticle.GetDefinition() == aKaonPlus ||
2398  targetParticle.GetDefinition() == aPiMinus ||
2399  targetParticle.GetDefinition() == aPiZero ||
2400  targetParticle.GetDefinition() == aPiPlus )
2401  {
2402  G4cout<<"Particlecheck"<<G4endl;
2403  pseudoParticle[0].SetMass( targetMass*GeV );
2404  G4cout<<pseudoParticle[0].GetMass()<<G4endl;
2405  pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
2406  G4cout<<pseudoParticle[0].GetTotalEnergy()<<G4endl;
2407  pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2408 
2409  pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2410  pseudoParticle[1].SetMass( mOriginal*GeV );
2411  G4cout<<pseudoParticle[1].GetMass()<<G4endl;
2412  pseudoParticle[1].SetKineticEnergy( 0.0 );
2413  G4cout<<pseudoParticle[1].GetTotalEnergy()<<G4endl;
2414  }
2415  else
2416  {*/
2417  pseudoParticle[0].SetMass( currentMass*GeV );
2418  pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
2419  pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
2420 
2421  pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2422  pseudoParticle[1].SetMass( targetMass*GeV );
2423  pseudoParticle[1].SetKineticEnergy( 0.0 );
2424  // }
2425  //
2426  // Transform into centre of mass system
2427  //
2428  pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
2429  pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
2430  pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
2431  //
2432  // Set final state masses and energies in centre of mass system
2433  //
2434  currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
2435  targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
2436  //
2437  // Set |t| and |tmin|
2438  //
2439  const G4double cb = 0.01;
2440  const G4double b1 = 4.225;
2441  const G4double b2 = 1.795;
2442  //
2443  // Calculate slope b for elastic scattering on proton/neutron
2444  //
2445  /*
2446  G4ParticleTable* theParticleTable = G4ParticleTable::GetParticleTable();
2447  G4double ptemp=0;
2448  if(modifiedOriginal.GetDefinition()->GetParticleType()=="rhadron"){
2449  // G4cout<<"Rescaling energy by gluino mass"<<G4endl;
2450  //Getting the mass of the bare gluino:
2451  G4double Mg = theParticleTable->FindParticle("~g")->GetPDGMass();
2452  //Mass of active system:
2453  G4double sysmass = mOriginal-Mg;
2454  ptemp = sqrt(etOriginal*etOriginal/(mOriginal*mOriginal)-1)*sysmass;
2455 
2456  }
2457  */
2458 
2459  G4double b = std::max( cb, b1+b2*std::log(pOriginal) );
2460  // G4double b = std::max( cb, b1+b2*std::log(ptemp) );
2461  G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
2462 
2463  G4double exindt = -1.0;
2464  exindt += std::exp(std::max(-btrang,expxl));
2465  //
2466  // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
2467  //
2468  G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
2469  if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
2470  G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
2471  G4double phi = twopi * G4UniformRand();
2472  //
2473  // Calculate final state momenta in centre of mass system
2474  //
2475  if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron")
2476  targetParticle.GetDefinition() == aKaonMinus ||
2477  targetParticle.GetDefinition() == aKaonZeroL ||
2478  targetParticle.GetDefinition() == aKaonZeroS ||
2479  targetParticle.GetDefinition() == aKaonPlus ||
2480  targetParticle.GetDefinition() == aPiMinus ||
2481  targetParticle.GetDefinition() == aPiZero ||
2482  targetParticle.GetDefinition() == aPiPlus )
2483  {
2484  currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
2485  -pf*stet*std::cos(phi)*GeV,
2486  -pf*ctet*GeV );
2487  }
2488  else
2489  {
2490  currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
2491  pf*stet*std::cos(phi)*GeV,
2492  pf*ctet*GeV );
2493  }
2494  targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
2495  //
2496  // Transform into lab system
2497  //
2498  currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
2499  targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
2500 
2501  /*
2502  G4cout<<"Check 1"<<G4endl;
2503  G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
2504  G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
2505  G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
2506  G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
2507  */
2508 
2509  Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2510 
2511  G4double pp, pp1, ekin;
2512  if( atomicWeight >= 1.5 )
2513  {
2514  const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2515  pp1 = currentParticle.GetMomentum().mag()/MeV;
2516  if( pp1 >= 1.0 )
2517  {
2518  ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
2519  ekin = std::max( 0.0001*GeV, ekin );
2520  currentParticle.SetKineticEnergy( ekin*MeV );
2521  pp = currentParticle.GetTotalMomentum()/MeV;
2522  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2523  }
2524  pp1 = targetParticle.GetMomentum().mag()/MeV;
2525  if( pp1 >= 1.0 )
2526  {
2527  ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
2528  ekin = std::max( 0.0001*GeV, ekin );
2529  targetParticle.SetKineticEnergy( ekin*MeV );
2530  pp = targetParticle.GetTotalMomentum()/MeV;
2531  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2532  }
2533  }
2534  }
2535  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2536  if( atomicWeight >= 1.5 )
2537  {
2538  // Add black track particles
2539  // the procedure is somewhat different than in TwoCluster and GenerateXandPt.
2540  // The reason is that we have to also simulate the nuclear reactions
2541  // at low energies like a(h,p)b, a(h,p p)b, a(h,n)b etc.
2542  //
2543  // npnb is number of proton/neutron black track particles
2544  // ndta is the number of deuterons, tritons, and alphas produced
2545  // epnb is the kinetic energy available for proton/neutron black track particles
2546  // edta is the kinetic energy available for deuteron/triton/alpha particles
2547  //
2548  G4double epnb, edta;
2549  G4int npnb=0, ndta=0;
2550 
2551  epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
2552  edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
2553  const G4double pnCutOff = 0.0001; // GeV
2554  const G4double dtaCutOff = 0.0001; // GeV
2555  const G4double kineticMinimum = 0.0001;
2556  const G4double kineticFactor = -0.010;
2557  G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2558  if( epnb >= pnCutOff )
2559  {
2560  npnb = Poisson( epnb/0.02 );
2561  /*
2562  G4cout<<"A couple of Poisson numbers:"<<G4endl;
2563  for (int n=0;n!=10;n++) G4cout<<Poisson(epnb/0.02)<<", ";
2564  G4cout<<G4endl;
2565  */
2566  if( npnb > atomicWeight )npnb = G4int(atomicWeight);
2567  if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
2568  npnb = std::min( npnb, 127-vecLen );
2569  }
2570  if( edta >= dtaCutOff )
2571  {
2572  ndta = G4int(2.0 * std::log(atomicWeight));
2573  ndta = std::min( ndta, 127-vecLen );
2574  }
2575  G4double spall = 0.0;
2576  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2577 
2578  /*
2579  G4cout<<"Check 2"<<G4endl;
2580  G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
2581  G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
2582  G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
2583  G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
2584 
2585  G4cout<<"------------------------------------------------------------------------"<<G4endl;
2586  G4cout<<"Atomic weight: "<<atomicWeight<<G4endl;
2587  G4cout<<"number of proton/neutron black track particles: "<<npnb<<G4endl;
2588  G4cout<<"number of deuterons, tritons, and alphas produced: "<<ndta <<G4endl;
2589  G4cout<<"kinetic energy available for proton/neutron black track particles: "<<epnb/GeV<<" GeV" <<G4endl;
2590  G4cout<<"kinetic energy available for deuteron/triton/alpha particles: "<<edta/GeV <<" GeV"<<G4endl;
2591  G4cout<<"------------------------------------------------------------------------"<<G4endl;
2592  */
2593 
2594  AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
2595  modifiedOriginal, spall, targetNucleus,
2596  vec, vecLen );
2597 
2598  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2599  }
2600  //
2601  // calculate time delay for nuclear reactions
2602  //
2603  if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2604  currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2605  else
2606  currentParticle.SetTOF( 1.0 );
2607  return;
2608  }
2609 
2610  G4double FullModelReactionDynamics::GenerateNBodyEvent(
2611  const G4double totalEnergy, // MeV
2612  const G4bool constantCrossSection,
2613  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2614  G4int &vecLen )
2615  {
2616 // // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2617  // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
2618  // Returns the weight of the event
2619  //
2620  G4int i;
2621  const G4double expxu = 82.; // upper bound for arg. of exp
2622  const G4double expxl = -expxu; // lower bound for arg. of exp
2623  if( vecLen < 2 )
2624  {
2625  G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
2626  G4cerr << " number of particles < 2" << G4endl;
2627  G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
2628  return -1.0;
2629  }
2630  G4double mass[18]; // mass of each particle
2631  G4double energy[18]; // total energy of each particle
2632  G4double pcm[3][18]; // pcm is an array with 3 rows and vecLen columns
2633  //G4double *mass = new G4double [vecLen]; // mass of each particle
2634  //G4double *energy = new G4double [vecLen]; // total energy of each particle
2635  //G4double **pcm; // pcm is an array with 3 rows and vecLen columns
2636  //pcm = new G4double * [3];
2637  //for( i=0; i<3; ++i )pcm[i] = new G4double [vecLen];
2638 
2639  G4double totalMass = 0.0;
2640  G4double extraMass = 0;
2641  G4double sm[18];
2642  //G4double *sm = new G4double [vecLen];
2643 
2644  for( i=0; i<vecLen; ++i )
2645  {
2646  mass[i] = vec[i]->GetMass()/GeV;
2647  if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
2648  vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
2649  pcm[0][i] = 0.0; // x-momentum of i-th particle
2650  pcm[1][i] = 0.0; // y-momentum of i-th particle
2651  pcm[2][i] = 0.0; // z-momentum of i-th particle
2652  energy[i] = mass[i]; // total energy of i-th particle
2653  totalMass += mass[i];
2654  sm[i] = totalMass;
2655  }
2656  G4double totalE = totalEnergy/GeV;
2657  if( totalMass > totalE )
2658  {
2659  //G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
2660  //G4cerr << " total mass (" << totalMass*GeV << "MeV) > total energy ("
2661  // << totalEnergy << "MeV)" << G4endl;
2662  totalE = totalMass;
2663  //delete [] mass;
2664  //delete [] energy;
2665  //for( i=0; i<3; ++i )delete [] pcm[i];
2666  //delete [] pcm;
2667  //delete [] sm;
2668  return -1.0;
2669  }
2670  G4double kineticEnergy = totalE - totalMass;
2671  G4double emm[18];
2672  //G4double *emm = new G4double [vecLen];
2673  emm[0] = mass[0];
2674  emm[vecLen-1] = totalE;
2675  if( vecLen > 2 ) // the random numbers are sorted
2676  {
2677  G4double ran[18];
2678  for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
2679  for( i=0; i<vecLen-2; ++i )
2680  {
2681  for( G4int j=vecLen-2; j>i; --j )
2682  {
2683  if( ran[i] > ran[j] )
2684  {
2685  G4double temp = ran[i];
2686  ran[i] = ran[j];
2687  ran[j] = temp;
2688  }
2689  }
2690  }
2691  for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
2692  }
2693  // Weight is the sum of logarithms of terms instead of the product of terms
2694  G4bool lzero = true;
2695  G4double wtmax = 0.0;
2696  if( constantCrossSection ) // this is KGENEV=1 in PHASP
2697  {
2698  G4double emmax = kineticEnergy + mass[0];
2699  G4double emmin = 0.0;
2700  for( i=1; i<vecLen; ++i )
2701  {
2702  emmin += mass[i-1];
2703  emmax += mass[i];
2704  G4double wtfc = 0.0;
2705  if( emmax*emmax > 0.0 )
2706  {
2707  G4double arg = emmax*emmax
2708  + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
2709  - 2.0*(emmin*emmin+mass[i]*mass[i]);
2710  if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
2711  }
2712  if( wtfc == 0.0 )
2713  {
2714  lzero = false;
2715  break;
2716  }
2717  wtmax += std::log( wtfc );
2718  }
2719  if( lzero )
2720  wtmax = -wtmax;
2721  else
2722  wtmax = expxu;
2723  }
2724  else
2725  {
2726  // ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
2727  const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
2728  256.3704, 268.4705, 240.9780, 189.2637,
2729  132.1308, 83.0202, 47.4210, 24.8295,
2730  12.0006, 5.3858, 2.2560, 0.8859 };
2731  wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
2732  }
2733  lzero = true;
2734  G4double pd[50];
2735  //G4double *pd = new G4double [vecLen-1];
2736  for( i=0; i<vecLen-1; ++i )
2737  {
2738  pd[i] = 0.0;
2739  if( emm[i+1]*emm[i+1] > 0.0 )
2740  {
2741  G4double arg = emm[i+1]*emm[i+1]
2742  + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
2743  /(emm[i+1]*emm[i+1])
2744  - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
2745  if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
2746  }
2747  if( pd[i] <= 0.0 ) // changed from == on 02 April 98
2748  lzero = false;
2749  else
2750  wtmax += std::log( pd[i] );
2751  }
2752  G4double weight = 0.0; // weight is returned by GenerateNBodyEvent
2753  if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
2754 
2755  G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
2756  pcm[0][0] = 0.0;
2757  pcm[1][0] = pd[0];
2758  pcm[2][0] = 0.0;
2759  for( i=1; i<vecLen; ++i )
2760  {
2761  pcm[0][i] = 0.0;
2762  pcm[1][i] = -pd[i-1];
2763  pcm[2][i] = 0.0;
2764  bang = twopi*G4UniformRand();
2765  cb = std::cos(bang);
2766  sb = std::sin(bang);
2767  c = 2.0*G4UniformRand() - 1.0;
2768  s = std::sqrt( std::fabs( 1.0-c*c ) );
2769  if( i < vecLen-1 )
2770  {
2771  esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
2772  beta = pd[i]/esys;
2773  gama = esys/emm[i];
2774  for( G4int j=0; j<=i; ++j )
2775  {
2776  s0 = pcm[0][j];
2777  s1 = pcm[1][j];
2778  s2 = pcm[2][j];
2779  energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2780  a = s0*c - s1*s; // rotation
2781  pcm[1][j] = s0*s + s1*c;
2782  b = pcm[2][j];
2783  pcm[0][j] = a*cb - b*sb;
2784  pcm[2][j] = a*sb + b*cb;
2785  pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
2786  }
2787  }
2788  else
2789  {
2790  for( G4int j=0; j<=i; ++j )
2791  {
2792  s0 = pcm[0][j];
2793  s1 = pcm[1][j];
2794  s2 = pcm[2][j];
2795  energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2796  a = s0*c - s1*s; // rotation
2797  pcm[1][j] = s0*s + s1*c;
2798  b = pcm[2][j];
2799  pcm[0][j] = a*cb - b*sb;
2800  pcm[2][j] = a*sb + b*cb;
2801  }
2802  }
2803  }
2804  for( i=0; i<vecLen; ++i )
2805  {
2806  vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
2807  vec[i]->SetTotalEnergy( energy[i]*GeV );
2808  }
2809  //delete [] mass;
2810  //delete [] energy;
2811  //for( i=0; i<3; ++i )delete [] pcm[i];
2812  //delete [] pcm;
2813  //delete [] emm;
2814  //delete [] sm;
2815  //delete [] pd;
2816  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2817  return weight;
2818  }
2819 
2820  G4double
2821  FullModelReactionDynamics::normal()
2822  {
2823  G4double ran = -6.0;
2824  for( G4int i=0; i<12; ++i )ran += G4UniformRand();
2825  return ran;
2826  }
2827 
2828  G4int
2829  FullModelReactionDynamics::Poisson( G4double x ) // generation of poisson distribution
2830  {
2831  G4int iran;
2832  G4double ran;
2833 
2834  if( x > 9.9 ) // use normal distribution with sigma^2 = <x>
2835  iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
2836  else {
2837  G4int mm = G4int(5.0*x);
2838  if( mm <= 0 ) // for very small x try iran=1,2,3
2839  {
2840  G4double p1 = x*std::exp(-x);
2841  G4double p2 = x*p1/2.0;
2842  G4double p3 = x*p2/3.0;
2843  ran = G4UniformRand();
2844  if( ran < p3 )
2845  iran = 3;
2846  else if( ran < p2 ) // this is original Geisha, it should be ran < p2+p3
2847  iran = 2;
2848  else if( ran < p1 ) // should be ran < p1+p2+p3
2849  iran = 1;
2850  else
2851  iran = 0;
2852  }
2853  else
2854  {
2855  iran = 0;
2856  G4double r = std::exp(-x);
2857  ran = G4UniformRand();
2858  if( ran > r )
2859  {
2860  G4double rrr;
2861  G4double rr = r;
2862  for( G4int i=1; i<=mm; ++i )
2863  {
2864  iran++;
2865  if( i > 5 ) // Stirling's formula for large numbers
2866  rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
2867  else
2868  rrr = std::pow(x,i)/Factorial(i);
2869  rr += r*rrr;
2870  if( ran <= rr )break;
2871  }
2872  }
2873  }
2874  }
2875  return iran;
2876  }
2877 
2878  G4int
2879  FullModelReactionDynamics::Factorial( G4int n )
2880  { // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
2881  G4int m = std::min(n,10);
2882  G4int result = 1;
2883  if( m <= 1 )return result;
2884  for( G4int i=2; i<=m; ++i )result *= i;
2885  return result;
2886  }
2887 
2888  void FullModelReactionDynamics::Defs1(
2889  const G4ReactionProduct &modifiedOriginal,
2890  G4ReactionProduct &currentParticle,
2891  G4ReactionProduct &targetParticle,
2892  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2893  G4int &vecLen )
2894  {
2895  const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
2896  const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
2897  const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
2898  const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
2899  if( pjx*pjx+pjy*pjy > 0.0 )
2900  {
2901  G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
2902  cost = pjz/p;
2903  sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
2904  if( pjy < 0.0 )
2905  ph = 3*halfpi;
2906  else
2907  ph = halfpi;
2908  if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
2909  cosp = std::cos(ph);
2910  sinp = std::sin(ph);
2911  pix = currentParticle.GetMomentum().x()/MeV;
2912  piy = currentParticle.GetMomentum().y()/MeV;
2913  piz = currentParticle.GetMomentum().z()/MeV;
2914  currentParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2915  cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2916  -sint*pix*MeV + cost*piz*MeV );
2917  pix = targetParticle.GetMomentum().x()/MeV;
2918  piy = targetParticle.GetMomentum().y()/MeV;
2919  piz = targetParticle.GetMomentum().z()/MeV;
2920  targetParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2921  cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2922  -sint*pix*MeV + cost*piz*MeV );
2923  for( G4int i=0; i<vecLen; ++i )
2924  {
2925  pix = vec[i]->GetMomentum().x()/MeV;
2926  piy = vec[i]->GetMomentum().y()/MeV;
2927  piz = vec[i]->GetMomentum().z()/MeV;
2928  vec[i]->SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2929  cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2930  -sint*pix*MeV + cost*piz*MeV );
2931  }
2932  }
2933  else
2934  {
2935  if( pjz < 0.0 )
2936  {
2937  currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
2938  targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
2939  for( G4int i=0; i<vecLen; ++i )
2940  vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
2941  }
2942  }
2943  }
2944 
2945  void FullModelReactionDynamics::Rotate(
2946  const G4double numberofFinalStateNucleons,
2947  const G4ThreeVector &temp,
2948  const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
2949  const G4HadProjectile *originalIncident, // original incident particle
2950  const G4Nucleus &targetNucleus,
2951  G4ReactionProduct &currentParticle,
2952  G4ReactionProduct &targetParticle,
2953  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2954  G4int &vecLen )
2955  {
2956  // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
2957  //
2958  // Rotate in direction of z-axis, this does disturb in some way our
2959  // inclusive distributions, but it is necessary for momentum conservation
2960  //
2961  const G4double atomicWeight = targetNucleus.GetN_asInt();
2962  const G4double logWeight = std::log(atomicWeight);
2963 
2964  G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2965  G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2966  G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2967 
2968  G4int i;
2969  G4ThreeVector pseudoParticle[4];
2970  for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
2971  pseudoParticle[0] = currentParticle.GetMomentum()
2972  + targetParticle.GetMomentum();
2973  for( i=0; i<vecLen; ++i )
2974  pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
2975  //
2976  // Some smearing in transverse direction from Fermi motion
2977  //
2978  G4float pp, pp1;
2979  G4double alekw, p, rthnve, phinve;
2980  G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
2981 
2982  r1 = twopi*G4UniformRand();
2983  r2 = G4UniformRand();
2984  a1 = std::sqrt(-2.0*std::log(r2));
2985  ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
2986  ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
2987  G4ThreeVector fermi(ran1, ran2, 0);
2988 
2989  pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
2990  pseudoParticle[2] = temp; // original in cms system
2991  pseudoParticle[3] = pseudoParticle[0];
2992 
2993  pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
2994  G4double rotation = 2.*pi*G4UniformRand();
2995  pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
2996  pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);
2997  for(G4int ii=1; ii<=3; ii++)
2998  {
2999  p = pseudoParticle[ii].mag();
3000  if( p == 0.0 )
3001  pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
3002  else
3003  pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
3004  }
3005 
3006  pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
3007  pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
3008  pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
3009  currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
3010 
3011  pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
3012  pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
3013  pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
3014  targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
3015 
3016  for( i=0; i<vecLen; ++i )
3017  {
3018  pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
3019  pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
3020  pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
3021  vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
3022  }
3023  //
3024  // Rotate in direction of primary particle, subtract binding energies
3025  // and make some further corrections if required
3026  //
3027  Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
3028  G4double ekin;
3029  G4double dekin = 0.0;
3030  G4double ek1 = 0.0;
3031  G4int npions = 0;
3032  if( atomicWeight >= 1.5 ) // self-absorption in heavy molecules
3033  {
3034  // corrections for single particle spectra (shower particles)
3035  //
3036  const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
3037  const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
3038  alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
3039  exh = 1.0;
3040  if( alekw > alem[0] ) // get energy bin
3041  {
3042  exh = val0[6];
3043  for( G4int j=1; j<7; ++j )
3044  {
3045  if( alekw < alem[j] ) // use linear interpolation/extrapolation
3046  {
3047  G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
3048  exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
3049  break;
3050  }
3051  }
3052  exh = 1.0 - exh;
3053  }
3054  const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
3055  ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
3056  ekin = std::max( 1.0e-6, ekin );
3057  xxh = 1.0;
3058  /* if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3059  (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3060  (currentParticle.GetDefinition() == aPiZero) &&
3061  (G4UniformRand() <= logWeight) )xxh = exh;*/
3062  dekin += ekin*(1.0-xxh);
3063  ekin *= xxh;
3064  /* if( (currentParticle.GetDefinition() == aPiPlus) ||
3065  (currentParticle.GetDefinition() == aPiZero) ||
3066  (currentParticle.GetDefinition() == aPiMinus) )
3067  {
3068  ++npions;
3069  ek1 += ekin;
3070  }*/
3071  currentParticle.SetKineticEnergy( ekin*GeV );
3072  pp = currentParticle.GetTotalMomentum()/MeV;
3073  pp1 = currentParticle.GetMomentum().mag()/MeV;
3074  if( pp1 < 0.001*MeV )
3075  {
3076  rthnve = pi*G4UniformRand();
3077  phinve = twopi*G4UniformRand();
3078  currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3079  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3080  pp*std::cos(rthnve)*MeV );
3081  }
3082  else
3083  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3084  ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
3085  ekin = std::max( 1.0e-6, ekin );
3086  xxh = 1.0;
3087  if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3088  (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3089  (targetParticle.GetDefinition() == aPiZero) &&
3090  (G4UniformRand() < logWeight) )xxh = exh;
3091  dekin += ekin*(1.0-xxh);
3092  ekin *= xxh;
3093  if( (targetParticle.GetDefinition() == aPiPlus) ||
3094  (targetParticle.GetDefinition() == aPiZero) ||
3095  (targetParticle.GetDefinition() == aPiMinus) )
3096  {
3097  ++npions;
3098  ek1 += ekin;
3099  }
3100  targetParticle.SetKineticEnergy( ekin*GeV );
3101  pp = targetParticle.GetTotalMomentum()/MeV;
3102  pp1 = targetParticle.GetMomentum().mag()/MeV;
3103  if( pp1 < 0.001*MeV )
3104  {
3105  rthnve = pi*G4UniformRand();
3106  phinve = twopi*G4UniformRand();
3107  targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3108  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3109  pp*std::cos(rthnve)*MeV );
3110  }
3111  else
3112  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3113  for( i=0; i<vecLen; ++i )
3114  {
3115  ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
3116  ekin = std::max( 1.0e-6, ekin );
3117  xxh = 1.0;
3118  if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3119  (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3120  (vec[i]->GetDefinition() == aPiZero) &&
3121  (G4UniformRand() < logWeight) )xxh = exh;
3122  dekin += ekin*(1.0-xxh);
3123  ekin *= xxh;
3124  if( (vec[i]->GetDefinition() == aPiPlus) ||
3125  (vec[i]->GetDefinition() == aPiZero) ||
3126  (vec[i]->GetDefinition() == aPiMinus) )
3127  {
3128  ++npions;
3129  ek1 += ekin;
3130  }
3131  vec[i]->SetKineticEnergy( ekin*GeV );
3132  pp = vec[i]->GetTotalMomentum()/MeV;
3133  pp1 = vec[i]->GetMomentum().mag()/MeV;
3134  if( pp1 < 0.001*MeV )
3135  {
3136  rthnve = pi*G4UniformRand();
3137  phinve = twopi*G4UniformRand();
3138  vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3139  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3140  pp*std::cos(rthnve)*MeV );
3141  }
3142  else
3143  vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3144  }
3145  }
3146  if( (ek1 != 0.0) && (npions > 0) )
3147  {
3148  dekin = 1.0 + dekin/ek1;
3149  //
3150  // first do the incident particle
3151  //
3152  if( (currentParticle.GetDefinition() == aPiPlus) ||
3153  (currentParticle.GetDefinition() == aPiZero) ||
3154  (currentParticle.GetDefinition() == aPiMinus) )
3155  {
3156  currentParticle.SetKineticEnergy(
3157  std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
3158  pp = currentParticle.GetTotalMomentum()/MeV;
3159  pp1 = currentParticle.GetMomentum().mag()/MeV;
3160  if( pp1 < 0.001 )
3161  {
3162  rthnve = pi*G4UniformRand();
3163  phinve = twopi*G4UniformRand();
3164  currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3165  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3166  pp*std::cos(rthnve)*MeV );
3167  }
3168  else
3169  currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3170  }
3171  /* if( (targetParticle.GetDefinition() == aPiPlus) ||
3172  (targetParticle.GetDefinition() == aPiZero) ||
3173  (targetParticle.GetDefinition() == aPiMinus) )
3174  {
3175  targetParticle.SetKineticEnergy(
3176  std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
3177  pp = targetParticle.GetTotalMomentum()/MeV;
3178  pp1 = targetParticle.GetMomentum().mag()/MeV;
3179  if( pp1 < 0.001 )
3180  {
3181  rthnve = pi*G4UniformRand();
3182  phinve = twopi*G4UniformRand();
3183  targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3184  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3185  pp*std::cos(rthnve)*MeV );
3186  }
3187  else
3188  targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3189  }*/
3190  for( i=0; i<vecLen; ++i )
3191  {
3192  if( (vec[i]->GetDefinition() == aPiPlus) ||
3193  (vec[i]->GetDefinition() == aPiZero) ||
3194  (vec[i]->GetDefinition() == aPiMinus) )
3195  {
3196  vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
3197  pp = vec[i]->GetTotalMomentum()/MeV;
3198  pp1 = vec[i]->GetMomentum().mag()/MeV;
3199  if( pp1 < 0.001 )
3200  {
3201  rthnve = pi*G4UniformRand();
3202  phinve = twopi*G4UniformRand();
3203  vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*MeV,
3204  pp*std::sin(rthnve)*std::sin(phinve)*MeV,
3205  pp*std::cos(rthnve)*MeV );
3206  }
3207  else
3208  vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3209  }
3210  }
3211  }
3212  }
3213 
3214  void FullModelReactionDynamics::AddBlackTrackParticles(
3215  const G4double epnb, // GeV
3216  const G4int npnb,
3217  const G4double edta, // GeV
3218  const G4int ndta,
3219  const G4double sprob,
3220  const G4double kineticMinimum, // GeV
3221  const G4double kineticFactor, // GeV
3222  const G4ReactionProduct &modifiedOriginal,
3223  G4double spall,
3224  const G4Nucleus &targetNucleus,
3225  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3226  G4int &vecLen )
3227  {
3228  // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
3229  //
3230  // npnb is number of proton/neutron black track particles
3231  // ndta is the number of deuterons, tritons, and alphas produced
3232  // epnb is the kinetic energy available for proton/neutron black track particles
3233  // edta is the kinetic energy available for deuteron/triton/alpha particles
3234  //
3235 
3236  G4ParticleDefinition *aProton = G4Proton::Proton();
3237  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3238  G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3239  G4ParticleDefinition *aTriton = G4Triton::Triton();
3240  G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3241 
3242  const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
3243  G4double atomicWeight = targetNucleus.GetN_asInt();
3244  G4double atomicNumber = targetNucleus.GetZ_asInt();
3245 
3246  const G4double ika1 = 3.6;
3247  const G4double ika2 = 35.56;
3248  const G4double ika3 = 6.45;
3249  const G4double sp1 = 1.066;
3250 
3251  G4int i;
3252  G4double pp;
3253  // G4double totalQ = 0;
3254  G4double kinCreated = 0;
3255  G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
3256  if( npnb > 0) // first add protons and neutrons
3257  {
3258  G4double backwardKinetic = 0.0;
3259  G4int local_npnb = npnb;
3260  for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
3261  G4double ekin = epnb/local_npnb;
3262 
3263  for( i=0; i<local_npnb; ++i )
3264  {
3265  G4ReactionProduct * p1 = new G4ReactionProduct();
3266  if( backwardKinetic > epnb )
3267  {
3268  delete p1;
3269  break;
3270  }
3271  G4double ran = G4UniformRand();
3272  G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
3273  if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
3274  backwardKinetic += kinetic;
3275  if( backwardKinetic > epnb )
3276  kinetic = std::max( kineticMinimum, epnb-(backwardKinetic-kinetic) );
3277  if( G4UniformRand() > (1.0-atomicNumber/atomicWeight) )
3278  p1->SetDefinition( aProton );
3279  else
3280  p1->SetDefinition( aNeutron );
3281  vec.SetElement( vecLen, p1 );
3282  ++spall;
3283  G4double cost = G4UniformRand() * 2.0 - 1.0;
3284  G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
3285  G4double phi = twopi * G4UniformRand();
3286  vec[vecLen]->SetNewlyAdded( true );
3287  vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3288  kinCreated+=kinetic;
3289  pp = vec[vecLen]->GetTotalMomentum()/MeV;
3290  vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3291  pp*sint*std::cos(phi)*MeV,
3292  pp*cost*MeV );
3293  vecLen++;
3294  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3295  }
3296  if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
3297  {
3298  G4double ekw = ekOriginal/GeV;
3299  G4int ika, kk = 0;
3300  if( ekw > 1.0 )ekw *= ekw;
3301  ekw = std::max( 0.1, ekw );
3302  ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/atomicWeight-ika2)/ika3)/ekw);
3303  if( ika > 0 )
3304  {
3305  for( i=(vecLen-1); i>=0; --i )
3306  {
3307  if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
3308  {
3309  vec[i]->SetDefinitionAndUpdateE( aNeutron ); // modified 22-Oct-97
3310  if( ++kk > ika )break;
3311  }
3312  }
3313  }
3314  }
3315  }
3316  if( ndta > 0 ) // now, try to add deuterons, tritons and alphas
3317  {
3318  G4double backwardKinetic = 0.0;
3319  G4int local_ndta=ndta;
3320  for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
3321  G4double ekin = edta/local_ndta;
3322 
3323  for( i=0; i<local_ndta; ++i )
3324  {
3325  G4ReactionProduct *p2 = new G4ReactionProduct();
3326  if( backwardKinetic > edta )
3327  {
3328  delete p2;
3329  break;
3330  }
3331  G4double ran = G4UniformRand();
3332  G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
3333  if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
3334  backwardKinetic += kinetic;
3335  if( backwardKinetic > edta )kinetic = edta-(backwardKinetic-kinetic);
3336  if( kinetic < 0.0 )kinetic = kineticMinimum;
3337  G4double cost = 2.0*G4UniformRand() - 1.0;
3338  G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
3339  G4double phi = twopi*G4UniformRand();
3340  ran = G4UniformRand();
3341  if( ran <= 0.60 )
3342  p2->SetDefinition( aDeuteron );
3343  else if( ran <= 0.90 )
3344  p2->SetDefinition( aTriton );
3345  else
3346  p2->SetDefinition( anAlpha );
3347  spall += p2->GetMass()/GeV * sp1;
3348  if( spall > atomicWeight )
3349  {
3350  delete p2;
3351  break;
3352  }
3353  vec.SetElement( vecLen, p2 );
3354  vec[vecLen]->SetNewlyAdded( true );
3355  vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3356  kinCreated+=kinetic;
3357  pp = vec[vecLen]->GetTotalMomentum()/MeV;
3358  vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3359  pp*sint*std::cos(phi)*MeV,
3360  pp*cost*MeV );
3361  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3362  }
3363  }
3364  // G4double delta = epnb+edta - kinCreated;
3365  }
3366 
3367  void FullModelReactionDynamics::MomentumCheck(
3368  const G4ReactionProduct &modifiedOriginal,
3369  G4ReactionProduct &currentParticle,
3370  G4ReactionProduct &targetParticle,
3371  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3372  G4int &vecLen )
3373  {
3374  const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
3375  G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
3376  G4double pMass;
3377  if( testMomentum >= pOriginal )
3378  {
3379  pMass = currentParticle.GetMass()/MeV;
3380  currentParticle.SetTotalEnergy(
3381  std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3382  currentParticle.SetMomentum(
3383  currentParticle.GetMomentum() * (pOriginal/testMomentum) );
3384  }
3385  testMomentum = targetParticle.GetMomentum().mag()/MeV;
3386  if( testMomentum >= pOriginal )
3387  {
3388  pMass = targetParticle.GetMass()/MeV;
3389  targetParticle.SetTotalEnergy(
3390  std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3391  targetParticle.SetMomentum(
3392  targetParticle.GetMomentum() * (pOriginal/testMomentum) );
3393  }
3394  for( G4int i=0; i<vecLen; ++i )
3395  {
3396  testMomentum = vec[i]->GetMomentum().mag()/MeV;
3397  if( testMomentum >= pOriginal )
3398  {
3399  pMass = vec[i]->GetMass()/MeV;
3400  vec[i]->SetTotalEnergy(
3401  std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3402  vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
3403  }
3404  }
3405  }
3406 
3407  void FullModelReactionDynamics::ProduceStrangeParticlePairs(
3408  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3409  G4int &vecLen,
3410  const G4ReactionProduct &modifiedOriginal,
3411  const G4DynamicParticle *originalTarget,
3412  G4ReactionProduct &currentParticle,
3413  G4ReactionProduct &targetParticle,
3414  G4bool &incidentHasChanged,
3415  G4bool &targetHasChanged )
3416  {
3417  // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
3418  //
3419  // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
3420  // K+ Y0, K0 Y+, K0 Y-
3421  // For antibaryon induced reactions half of the cross sections KB YB
3422  // pairs are produced. Charge is not conserved, no experimental data available
3423  // for exclusive reactions, therefore some average behaviour assumed.
3424  // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
3425  //
3426  if( vecLen == 0 )return;
3427  //
3428  // the following protects against annihilation processes
3429  //
3430  if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
3431 
3432  const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
3433  const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
3434  G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
3435  G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
3436  targetMass*targetMass +
3437  2.0*targetMass*etOriginal ); // GeV
3438  G4double currentMass = currentParticle.GetMass()/GeV;
3439  G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
3440  if( availableEnergy <= 1.0 )return;
3441 
3442  G4ParticleDefinition *aProton = G4Proton::Proton();
3443  G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
3444  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3445  G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
3446  G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
3447  G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
3448  G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
3449  G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
3450  G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
3451  G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
3452  G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
3453  G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
3454  G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
3455  G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
3456  G4ParticleDefinition *aLambda = G4Lambda::Lambda();
3457  G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
3458 
3459  const G4double protonMass = aProton->GetPDGMass()/GeV;
3460  const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
3461  //
3462  // determine the center of mass energy bin
3463  //
3464  const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
3465 
3466  G4int ibin, i3, i4;
3467  G4double avk, avy, avn, ran;
3468  G4int i = 1;
3469  while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
3470  if( i == 12 )
3471  ibin = 11;
3472  else
3473  ibin = i;
3474  //
3475  // the fortran code chooses a random replacement of produced kaons
3476  // but does not take into account charge conservation
3477  //
3478  if( vecLen == 1 ) // we know that vecLen > 0
3479  {
3480  i3 = 0;
3481  i4 = 1; // note that we will be adding a new secondary particle in this case only
3482  }
3483  else // otherwise 0 <= i3,i4 < vecLen
3484  {
3485  G4double ran = G4UniformRand();
3486  while( ran == 1.0 )ran = G4UniformRand();
3487  i4 = i3 = G4int( vecLen*ran );
3488  while( i3 == i4 )
3489  {
3490  ran = G4UniformRand();
3491  while( ran == 1.0 )ran = G4UniformRand();
3492  i4 = G4int( vecLen*ran );
3493  }
3494  }
3495  //
3496  // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
3497  //
3498  const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
3499  0.0975, 0.123, 0.28, 0.398, 0.495, 0.573 };
3500  const G4double avky[] = { 0.005, 0.03, 0.064, 0.095, 0.115, 0.13,
3501  0.145, 0.155, 0.20, 0.205, 0.210, 0.212 };
3502  const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
3503  0.04, 0.05, 0.12, 0.15, 0.18, 0.20 };
3504 
3505  avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3506  /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
3507  avk = std::exp(avk);
3508 
3509  avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3510  /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
3511  avy = std::exp(avy);
3512 
3513  avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3514  /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
3515  avn = std::exp(avn);
3516 
3517  if( avk+avy+avn <= 0.0 )return;
3518 
3519  if( currentMass < protonMass )avy /= 2.0;
3520  if( targetMass < protonMass )avy = 0.0;
3521  avy += avk+avn;
3522  avk += avn;
3523  ran = G4UniformRand();
3524  if( ran < avn )
3525  {
3526  if( availableEnergy < 2.0 )return;
3527  if( vecLen == 1 ) // add a new secondary
3528  {
3529  G4ReactionProduct *p1 = new G4ReactionProduct;
3530  if( G4UniformRand() < 0.5 )
3531  {
3532  vec[0]->SetDefinition( aNeutron );
3533  p1->SetDefinition( anAntiNeutron );
3534  (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3535  vec[0]->SetMayBeKilled(false);
3536  p1->SetMayBeKilled(false);
3537  }
3538  else
3539  {
3540  vec[0]->SetDefinition( aProton );
3541  p1->SetDefinition( anAntiProton );
3542  (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3543  vec[0]->SetMayBeKilled(false);
3544  p1->SetMayBeKilled(false);
3545  }
3546  vec.SetElement( vecLen++, p1 );
3547  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3548  }
3549  else
3550  { // replace two secondaries
3551  if( G4UniformRand() < 0.5 )
3552  {
3553  vec[i3]->SetDefinition( aNeutron );
3554  vec[i4]->SetDefinition( anAntiNeutron );
3555  vec[i3]->SetMayBeKilled(false);
3556  vec[i4]->SetMayBeKilled(false);
3557  }
3558  else
3559  {
3560  vec[i3]->SetDefinition( aProton );
3561  vec[i4]->SetDefinition( anAntiProton );
3562  vec[i3]->SetMayBeKilled(false);
3563  vec[i4]->SetMayBeKilled(false);
3564  }
3565  }
3566  }
3567  else if( ran < avk )
3568  {
3569  if( availableEnergy < 1.0 )return;
3570 
3571  const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
3572  0.6875, 0.7500, 0.8750, 1.000 };
3573  const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
3574  const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
3575  ran = G4UniformRand();
3576  i = 0;
3577  while( (i<9) && (ran>=kkb[i]) )++i;
3578  if( i == 9 )return;
3579  //
3580  // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
3581  // charge + - + 0 + 0 0 0 0 0 0 0 0 0 0 - 0 -
3582  //
3583  switch( ipakkb1[i] )
3584  {
3585  case 10:
3586  vec[i3]->SetDefinition( aKaonPlus );
3587  vec[i3]->SetMayBeKilled(false);
3588  break;
3589  case 11:
3590  vec[i3]->SetDefinition( aKaonZS );
3591  vec[i3]->SetMayBeKilled(false);
3592  break;
3593  case 12:
3594  vec[i3]->SetDefinition( aKaonZL );
3595  vec[i3]->SetMayBeKilled(false);
3596  break;
3597  }
3598  if( vecLen == 1 ) // add a secondary
3599  {
3600  G4ReactionProduct *p1 = new G4ReactionProduct;
3601  switch( ipakkb2[i] )
3602  {
3603  case 11:
3604  p1->SetDefinition( aKaonZS );
3605  p1->SetMayBeKilled(false);
3606  break;
3607  case 12:
3608  p1->SetDefinition( aKaonZL );
3609  p1->SetMayBeKilled(false);
3610  break;
3611  case 13:
3612  p1->SetDefinition( aKaonMinus );
3613  p1->SetMayBeKilled(false);
3614  break;
3615  }
3616  (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3617  vec.SetElement( vecLen++, p1 );
3618  // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3619  }
3620  else // replace
3621  {
3622  switch( ipakkb2[i] )
3623  {
3624  case 11:
3625  vec[i4]->SetDefinition( aKaonZS );
3626  vec[i4]->SetMayBeKilled(false);
3627  break;
3628  case 12:
3629  vec[i4]->SetDefinition( aKaonZL );
3630  vec[i4]->SetMayBeKilled(false);
3631  break;
3632  case 13:
3633  vec[i4]->SetDefinition( aKaonMinus );
3634  vec[i4]->SetMayBeKilled(false);
3635  break;
3636  }
3637  }
3638  }
3639  else if( ran < avy )
3640  {
3641  if( availableEnergy < 1.6 )return;
3642 
3643  const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
3644  0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
3645  const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
3646  const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
3647  const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
3648  const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
3649  ran = G4UniformRand();
3650  i = 0;
3651  while( (i<12) && (ran>ky[i]) )++i;
3652  if( i == 12 )return;
3653  if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
3654  {
3655  // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
3656  // 0 + 0 0 0 0 + + + 0 + 0
3657  //
3658  // 21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
3659  // 0 + 0 0 0 0 - + - 0 - 0
3660  switch( ipaky1[i] )
3661  {
3662  case 18:
3663  targetParticle.SetDefinition( aLambda );
3664  break;
3665  case 20:
3666  targetParticle.SetDefinition( aSigmaPlus );
3667  break;
3668  case 21:
3669  targetParticle.SetDefinition( aSigmaZero );
3670  break;
3671  case 22:
3672  targetParticle.SetDefinition( aSigmaMinus );
3673  break;
3674  }
3675  targetHasChanged = true;
3676  switch( ipaky2[i] )
3677  {
3678  case 10:
3679  vec[i3]->SetDefinition( aKaonPlus );
3680  vec[i3]->SetMayBeKilled(false);
3681  break;
3682  case 11:
3683  vec[i3]->SetDefinition( aKaonZS );
3684  vec[i3]->SetMayBeKilled(false);
3685  break;
3686  case 12:
3687  vec[i3]->SetDefinition( aKaonZL );
3688  vec[i3]->SetMayBeKilled(false);
3689  break;
3690  }
3691  }
3692  else // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
3693  {
3694  // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
3695  // 24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
3696  if( (currentParticle.GetDefinition() == anAntiProton) ||
3697  (currentParticle.GetDefinition() == anAntiNeutron) ||
3698  (currentParticle.GetDefinition() == anAntiLambda) ||
3699  (currentMass > sigmaMinusMass) )
3700  {
3701  switch( ipakyb1[i] )
3702  {
3703  case 19:
3704  currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
3705  break;
3706  case 23:
3707  currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
3708  break;
3709  case 24:
3710  currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
3711  break;
3712  case 25:
3713  currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
3714  break;
3715  }
3716  incidentHasChanged = true;
3717  switch( ipakyb2[i] )
3718  {
3719  case 11:
3720  vec[i3]->SetDefinition( aKaonZS );
3721  vec[i3]->SetMayBeKilled(false);
3722  break;
3723  case 12:
3724  vec[i3]->SetDefinition( aKaonZL );
3725  vec[i3]->SetMayBeKilled(false);
3726  break;
3727  case 13:
3728  vec[i3]->SetDefinition( aKaonMinus );
3729  vec[i3]->SetMayBeKilled(false);
3730  break;
3731  }
3732  }
3733  else
3734  {
3735  switch( ipaky1[i] )
3736  {
3737  case 18:
3738  currentParticle.SetDefinitionAndUpdateE( aLambda );
3739  break;
3740  case 20:
3741  currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
3742  break;
3743  case 21:
3744  currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
3745  break;
3746  case 22:
3747  currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
3748  break;
3749  }
3750  incidentHasChanged = true;
3751  switch( ipaky2[i] )
3752  {
3753  case 10:
3754  vec[i3]->SetDefinition( aKaonPlus );
3755  vec[i3]->SetMayBeKilled(false);
3756  break;
3757  case 11:
3758  vec[i3]->SetDefinition( aKaonZS );
3759  vec[i3]->SetMayBeKilled(false);
3760  break;
3761  case 12:
3762  vec[i3]->SetDefinition( aKaonZL );
3763  vec[i3]->SetMayBeKilled(false);
3764  break;
3765  }
3766  }
3767  }
3768  }
3769  else return;
3770  //
3771  // check the available energy
3772  // if there is not enough energy for kkb/ky pair production
3773  // then reduce the number of secondary particles
3774  // NOTE:
3775  // the number of secondaries may have been changed
3776  // the incident and/or target particles may have changed
3777  // charge conservation is ignored (as well as strangness conservation)
3778  //
3779  currentMass = currentParticle.GetMass()/GeV;
3780  targetMass = targetParticle.GetMass()/GeV;
3781 
3782  G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
3783  for( i=0; i<vecLen; ++i )
3784  {
3785  energyCheck -= vec[i]->GetMass()/GeV;
3786  if( energyCheck < 0.0 ) // chop off the secondary List
3787  {
3788  vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
3789  G4int j;
3790  for(j=i; j<vecLen; j++) delete vec[j];
3791  break;
3792  }
3793  }
3794  return;
3795  }
3796 
3797  void
3798  FullModelReactionDynamics::NuclearReaction(
3799  G4FastVector<G4ReactionProduct,4> &vec,
3800  G4int &vecLen,
3801  const G4HadProjectile *originalIncident,
3802  const G4Nucleus &targetNucleus,
3803  const G4double theAtomicMass,
3804  const G4double *mass )
3805  {
3806  // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
3807  //
3808  // Nuclear reaction kinematics at low energies
3809  //
3810  G4ParticleDefinition *aGamma = G4Gamma::Gamma();
3811  G4ParticleDefinition *aProton = G4Proton::Proton();
3812  G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3813  G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3814  G4ParticleDefinition *aTriton = G4Triton::Triton();
3815  G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3816 
3817  const G4double aProtonMass = aProton->GetPDGMass()/MeV;
3818  const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
3819  const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
3820  const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
3821  const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
3822 
3823  G4ReactionProduct currentParticle;
3824  currentParticle = *originalIncident;
3825  //
3826  // Set beam particle, take kinetic energy of current particle as the
3827  // fundamental quantity. Due to the difficult kinematic, all masses have to
3828  // be assigned the best measured values
3829  //
3830  G4double p = currentParticle.GetTotalMomentum();
3831  G4double pp = currentParticle.GetMomentum().mag();
3832  if( pp <= 0.001*MeV )
3833  {
3834  G4double phinve = twopi*G4UniformRand();
3835  G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3836  currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3837  p*std::sin(rthnve)*std::sin(phinve),
3838  p*std::cos(rthnve) );
3839  }
3840  else
3841  currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3842  //
3843  // calculate Q-value of reactions
3844  //
3845  G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
3846  G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
3847  G4double qv = currentKinetic + theAtomicMass + currentMass;
3848 
3849  G4double qval[9];
3850  qval[0] = qv - mass[0];
3851  qval[1] = qv - mass[1] - aNeutronMass;
3852  qval[2] = qv - mass[2] - aProtonMass;
3853  qval[3] = qv - mass[3] - aDeuteronMass;
3854  qval[4] = qv - mass[4] - aTritonMass;
3855  qval[5] = qv - mass[5] - anAlphaMass;
3856  qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
3857  qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
3858  qval[8] = qv - mass[8] - aProtonMass - aProtonMass;
3859 
3860  if( currentParticle.GetDefinition() == aNeutron )
3861  {
3862  const G4double A = targetNucleus.GetN_asInt(); // atomic weight
3863  if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
3864  qval[0] = 0.0;
3865  if( G4UniformRand() >= currentKinetic/7.9254*A )
3866  qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
3867  }
3868  else
3869  qval[0] = 0.0;
3870 
3871  G4int i;
3872  qv = 0.0;
3873  for( i=0; i<9; ++i )
3874  {
3875  if( mass[i] < 500.0*MeV )qval[i] = 0.0;
3876  if( qval[i] < 0.0 )qval[i] = 0.0;
3877  qv += qval[i];
3878  }
3879  G4double qv1 = 0.0;
3880  G4double ran = G4UniformRand();
3881  G4int index;
3882  for( index=0; index<9; ++index )
3883  {
3884  if( qval[index] > 0.0 )
3885  {
3886  qv1 += qval[index]/qv;
3887  if( ran <= qv1 )break;
3888  }
3889  }
3890  if( index == 9 ) // loop continued to the end
3891  {
3892  throw G4HadronicException(__FILE__, __LINE__,
3893  "FullModelReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
3894  }
3895  G4double ke = currentParticle.GetKineticEnergy()/GeV;
3896  G4int nt = 2;
3897  if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
3898 
3899  G4ReactionProduct **v = new G4ReactionProduct * [3];
3900  v[0] = new G4ReactionProduct;
3901  v[1] = new G4ReactionProduct;
3902  v[2] = new G4ReactionProduct;
3903 
3904  v[0]->SetMass( mass[index]*MeV );
3905  switch( index )
3906  {
3907  case 0:
3908  v[1]->SetDefinition( aGamma );
3909  v[2]->SetDefinition( aGamma );
3910  break;
3911  case 1:
3912  v[1]->SetDefinition( aNeutron );
3913  v[2]->SetDefinition( aGamma );
3914  break;
3915  case 2:
3916  v[1]->SetDefinition( aProton );
3917  v[2]->SetDefinition( aGamma );
3918  break;
3919  case 3:
3920  v[1]->SetDefinition( aDeuteron );
3921  v[2]->SetDefinition( aGamma );
3922  break;
3923  case 4:
3924  v[1]->SetDefinition( aTriton );
3925  v[2]->SetDefinition( aGamma );
3926  break;
3927  case 5:
3928  v[1]->SetDefinition( anAlpha );
3929  v[2]->SetDefinition( aGamma );
3930  break;
3931  case 6:
3932  v[1]->SetDefinition( aNeutron );
3933  v[2]->SetDefinition( aNeutron );
3934  break;
3935  case 7:
3936  v[1]->SetDefinition( aNeutron );
3937  v[2]->SetDefinition( aProton );
3938  break;
3939  case 8:
3940  v[1]->SetDefinition( aProton );
3941  v[2]->SetDefinition( aProton );
3942  break;
3943  }
3944  //
3945  // calculate centre of mass energy
3946  //
3947  G4ReactionProduct pseudo1;
3948  pseudo1.SetMass( theAtomicMass*MeV );
3949  pseudo1.SetTotalEnergy( theAtomicMass*MeV );
3950  G4ReactionProduct pseudo2 = currentParticle + pseudo1;
3951  pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
3952  //
3953  // use phase space routine in centre of mass system
3954  //
3955  G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
3956  tempV.Initialize( nt );
3957  G4int tempLen = 0;
3958  tempV.SetElement( tempLen++, v[0] );
3959  tempV.SetElement( tempLen++, v[1] );
3960  if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
3961  G4bool constantCrossSection = true;
3962  GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
3963  v[0]->Lorentz( *v[0], pseudo2 );
3964  v[1]->Lorentz( *v[1], pseudo2 );
3965  if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
3966 
3967  G4bool particleIsDefined = false;
3968  if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
3969  {
3970  v[0]->SetDefinition( aProton );
3971  particleIsDefined = true;
3972  }
3973  else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
3974  {
3975  v[0]->SetDefinition( aNeutron );
3976  particleIsDefined = true;
3977  }
3978  else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
3979  {
3980  v[0]->SetDefinition( aDeuteron );
3981  particleIsDefined = true;
3982  }
3983  else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
3984  {
3985  v[0]->SetDefinition( aTriton );
3986  particleIsDefined = true;
3987  }
3988  else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
3989  {
3990  v[0]->SetDefinition( anAlpha );
3991  particleIsDefined = true;
3992  }
3993  currentParticle.SetKineticEnergy(
3994  std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
3995  p = currentParticle.GetTotalMomentum();
3996  pp = currentParticle.GetMomentum().mag();
3997  if( pp <= 0.001*MeV )
3998  {
3999  G4double phinve = twopi*G4UniformRand();
4000  G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
4001  currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4002  p*std::sin(rthnve)*std::sin(phinve),
4003  p*std::cos(rthnve) );
4004  }
4005  else
4006  currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
4007 
4008  if( particleIsDefined )
4009  {
4010  v[0]->SetKineticEnergy(
4011  std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
4012  p = v[0]->GetTotalMomentum();
4013  pp = v[0]->GetMomentum().mag();
4014  if( pp <= 0.001*MeV )
4015  {
4016  G4double phinve = twopi*G4UniformRand();
4017  G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4018  v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4019  p*std::sin(rthnve)*std::sin(phinve),
4020  p*std::cos(rthnve) );
4021  }
4022  else
4023  v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
4024  }
4025  if( (v[1]->GetDefinition() == aDeuteron) ||
4026  (v[1]->GetDefinition() == aTriton) ||
4027  (v[1]->GetDefinition() == anAlpha) )
4028  v[1]->SetKineticEnergy(
4029  std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
4030  else
4031  v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
4032 
4033  p = v[1]->GetTotalMomentum();
4034  pp = v[1]->GetMomentum().mag();
4035  if( pp <= 0.001*MeV )
4036  {
4037  G4double phinve = twopi*G4UniformRand();
4038  G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4039  v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4040  p*std::sin(rthnve)*std::sin(phinve),
4041  p*std::cos(rthnve) );
4042  }
4043  else
4044  v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
4045 
4046  if( nt == 3 )
4047  {
4048  if( (v[2]->GetDefinition() == aDeuteron) ||
4049  (v[2]->GetDefinition() == aTriton) ||
4050  (v[2]->GetDefinition() == anAlpha) )
4051  v[2]->SetKineticEnergy(
4052  std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
4053  else
4054  v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
4055 
4056  p = v[2]->GetTotalMomentum();
4057  pp = v[2]->GetMomentum().mag();
4058  if( pp <= 0.001*MeV )
4059  {
4060  G4double phinve = twopi*G4UniformRand();
4061  G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4062  v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4063  p*std::sin(rthnve)*std::sin(phinve),
4064  p*std::cos(rthnve) );
4065  }
4066  else
4067  v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
4068  }
4069  G4int del;
4070  for(del=0; del<vecLen; del++) delete vec[del];
4071  vecLen = 0;
4072  if( particleIsDefined )
4073  {
4074  vec.SetElement( vecLen++, v[0] );
4075  }
4076  else
4077  {
4078  delete v[0];
4079  }
4080  vec.SetElement( vecLen++, v[1] );
4081  if( nt == 3 )
4082  {
4083  vec.SetElement( vecLen++, v[2] );
4084  }
4085  else
4086  {
4087  delete v[2];
4088  }
4089  delete [] v;
4090  return;
4091  }
4092 
4093  /* end of file */
4094 
const double beta
int i
Definition: DBlmapReader.cc:9
const double GeV
Definition: MathUtil.h:16
const double protonMass
tuple pp
Definition: createTree.py:15
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
int ii
Definition: cuy.py:588
A arg
Definition: Factorize.h:36
tuple s2
Definition: indexGen.py:106
const Double_t pi
const double fermi
Definition: MathUtil.h:17
const double MeV
T sqrt(T t)
Definition: SSEVec.h:48
tuple result
Definition: query.py:137
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int j
Definition: DBlmapReader.cc:9
T min(T a, T b)
Definition: MathUtil.h:58
double p2[4]
Definition: TauolaWrapper.h:90
int nt
Definition: AMPTWrapper.h:32
double b
Definition: hdecay.h:120
double p1[4]
Definition: TauolaWrapper.h:89
double a
Definition: hdecay.h:121
Square< F >::type sqr(const F &f)
Definition: Square.h:13
dbl * Gamma
Definition: mlp_gen.cc:38
Definition: DDAxes.h:10
int weight
Definition: histoStyle.py:50
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
double p3[4]
Definition: TauolaWrapper.h:91
Definition: DDAxes.h:10