CMS 3D CMS Logo

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