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