CMS 3D CMS Logo

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