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