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