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 vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
2205 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
2206 pp*std::cos(rthnve)*CLHEP::MeV );
2207 }
2208 else
2209 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2210 }
2211 }
2212 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2213 Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
2214 modifiedOriginal, originalIncident, targetNucleus,
2215 currentParticle, targetParticle, vec, vecLen );
2216 //
2217 // add black track particles
2218 // the total number of particles produced is restricted to 198
2219 // this may have influence on very high energies
2220 //
2221 if( atomicWeight >= 1.5 )
2222 {
2223 // npnb is number of proton/neutron black track particles
2224 // ndta is the number of deuterons, tritons, and alphas produced
2225 // epnb is the kinetic energy available for proton/neutron black track particles
2226 // edta is the kinetic energy available for deuteron/triton/alpha particles
2227 //
2228 G4double epnb, edta;
2229 G4int npnb = 0;
2230 G4int ndta = 0;
2231
2232 epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
2233 edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
2234 const G4double pnCutOff = 0.001; // GeV
2235 const G4double dtaCutOff = 0.001; // GeV
2236 const G4double kineticMinimum = 1.e-6;
2237 const G4double kineticFactor = -0.005;
2238
2239 G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2240 const G4double ekIncident = originalIncident->GetKineticEnergy()/CLHEP::GeV;
2241 if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
2242
2243 if( epnb >= pnCutOff )
2244 {
2245 npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
2246 if( numberofFinalStateNucleons + npnb > atomicWeight )
2247 npnb = G4int(atomicWeight - numberofFinalStateNucleons);
2248 npnb = std::min( npnb, 127-vecLen );
2249 }
2250 if( edta >= dtaCutOff )
2251 {
2252 ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
2253 ndta = std::min( ndta, 127-vecLen );
2254 }
2255 G4double spall = numberofFinalStateNucleons;
2256 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2257
2258 AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
2259 modifiedOriginal, spall, targetNucleus,
2260 vec, vecLen );
2261
2262 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2263 }
2264 //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
2265 // MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2266 //
2267 // calculate time delay for nuclear reactions
2268 //
2269 if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2270 currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2271 else
2272 currentParticle.SetTOF( 1.0 );
2273
2274 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2275 return true;
2276}
2277
2278void FullModelReactionDynamics::TwoBody(
2279 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2280 G4int &vecLen,
2281 G4ReactionProduct &modifiedOriginal,
2282 const G4DynamicParticle */*originalTarget*/,
2283 G4ReactionProduct &currentParticle,
2284 G4ReactionProduct &targetParticle,
2285 const G4Nucleus &targetNucleus,
2286 G4bool &/* targetHasChanged*/ )
2287{
2288 // G4cout<<"TwoBody called"<<G4endl;
2289 //
2290 // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
2291 //
2292 // Generation of momenta for elastic and quasi-elastic 2 body reactions
2293 //
2294 // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
2295 // The b values are parametrizations from experimental data.
2296 // Not available values are taken from those of similar reactions.
2297 //
2298 G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2299 G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2300 G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2301 G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
2302 G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
2303 G4ParticleDefinition *aKaonZeroS = G4KaonZeroShort::KaonZeroShort();
2304 G4ParticleDefinition *aKaonZeroL = G4KaonZeroLong::KaonZeroLong();
2305
2306 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2307 static const G4double expxu = 82.; // upper bound for arg. of exp
2308 static const G4double expxl = -expxu; // lower bound for arg. of exp
2309
2310 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/CLHEP::GeV;
2311 const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/CLHEP::GeV;
2312 G4double currentMass = currentParticle.GetMass()/CLHEP::GeV;
2313 G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/CLHEP::GeV;
2314
2315 targetMass = targetParticle.GetMass()/CLHEP::GeV;
2316 const G4double atomicWeight = targetNucleus.AtomicMass(targetNucleus.GetA_asInt(),targetNucleus.GetZ_asInt());//targetNucleus.GetN();
2317 // G4cout<<"Atomic weight is found to be: "<<atomicWeight<<G4endl;
2318 G4double etCurrent = currentParticle.GetTotalEnergy()/CLHEP::GeV;
2319 G4double pCurrent = currentParticle.GetTotalMomentum()/CLHEP::GeV;
2320
2321 G4double cmEnergy = std::sqrt( currentMass*currentMass +
2322 targetMass*targetMass +
2323 2.0*targetMass*etCurrent ); // in GeV
2324
2325 //if( (pOriginal < 0.1) ||
2326 // (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
2327 // Continue with original particle, but spend the nuclear evaporation energy
2328 // targetParticle.SetMass( 0.0 ); // flag that the target doesn't exist
2329 //else // Two-body scattering is possible
2330
2331 if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
2332 {
2333 targetParticle.SetMass( 0.0 ); // flag that the target particle doesn't exist
2334 }
2335 else
2336 {
2337 // moved this if-block to a later stage, i.e. to the assignment of the scattering angle
2338 // @@@@@ double-check.
2339 // if( targetParticle.GetDefinition() == aKaonMinus ||
2340 // targetParticle.GetDefinition() == aKaonZeroL ||
2341 // targetParticle.GetDefinition() == aKaonZeroS ||
2342 // targetParticle.GetDefinition() == aKaonPlus ||
2343 // targetParticle.GetDefinition() == aPiMinus ||
2344 // targetParticle.GetDefinition() == aPiZero ||
2345 // targetParticle.GetDefinition() == aPiPlus )
2346 // {
2347 // if( G4UniformRand() < 0.5 )
2348 // targetParticle.SetDefinitionAndUpdateE( aNeutron );
2349 // else
2350 // targetParticle.SetDefinitionAndUpdateE( aProton );
2351 // targetHasChanged = true;
2352 // targetMass = targetParticle.GetMass()/CLHEP::GeV;
2353 // }
2354 //
2355 // Set masses and momenta for final state particles
2356 //
2357 /*
2358 G4cout<<"Check 0"<<G4endl;
2359 G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()/CLHEP::GeV<<G4endl;
2360 G4cout<<"target mass: "<<targetParticle.GetMass()/CLHEP::GeV<<G4endl;
2361 G4cout<<targetParticle.GetDefinition()->GetParticleName()<<G4endl;
2362 G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()/CLHEP::GeV<<G4endl;
2363 G4cout<<"current mass: "<<currentParticle.GetMass()/CLHEP::GeV<<G4endl;
2364 G4cout<<currentParticle.GetDefinition()->GetParticleName()<<G4endl;
2365 */
2366 G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
2367 pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
2368 // G4cout << "pf: " << pf<< G4endl;
2369
2370 if( pf <= 0.)// 0.001 )
2371 {
2372 for(G4int i=0; i<vecLen; i++) delete vec[i];
2373 vecLen = 0;
2374 throw G4HadronicException(__FILE__, __LINE__, "FullModelReactionDynamics::TwoBody: pf is too small ");
2375 }
2376
2377 pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
2378 //
2379 // Set beam and target in centre of mass system
2380 //
2381 G4ReactionProduct pseudoParticle[3];
2382 /* //Marker
2383 if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron")
2384 targetParticle.GetDefinition() == aKaonMinus ||
2385 targetParticle.GetDefinition() == aKaonZeroL ||
2386 targetParticle.GetDefinition() == aKaonZeroS ||
2387 targetParticle.GetDefinition() == aKaonPlus ||
2388 targetParticle.GetDefinition() == aPiMinus ||
2389 targetParticle.GetDefinition() == aPiZero ||
2390 targetParticle.GetDefinition() == aPiPlus )
2391 {
2392 G4cout<<"Particlecheck"<<G4endl;
2393 pseudoParticle[0].SetMass( targetMass*CLHEP::GeV );
2394 G4cout<<pseudoParticle[0].GetMass()<<G4endl;
2395 pseudoParticle[0].SetTotalEnergy( etOriginal*CLHEP::GeV );
2396 G4cout<<pseudoParticle[0].GetTotalEnergy()<<G4endl;
2397 pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*CLHEP::GeV );
2398
2399 pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2400 pseudoParticle[1].SetMass( mOriginal*CLHEP::GeV );
2401 G4cout<<pseudoParticle[1].GetMass()<<G4endl;
2402 pseudoParticle[1].SetKineticEnergy( 0.0 );
2403 G4cout<<pseudoParticle[1].GetTotalEnergy()<<G4endl;
2404 }
2405 else
2406 {*/
2407 pseudoParticle[0].SetMass( currentMass*CLHEP::GeV );
2408 pseudoParticle[0].SetTotalEnergy( etCurrent*CLHEP::GeV );
2409 pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*CLHEP::GeV );
2410
2411 pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2412 pseudoParticle[1].SetMass( targetMass*CLHEP::GeV );
2413 pseudoParticle[1].SetKineticEnergy( 0.0 );
2414 // }
2415 //
2416 // Transform into centre of mass system
2417 //
2418 pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
2419 pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
2420 pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
2421 //
2422 // Set final state masses and energies in centre of mass system
2423 //
2424 currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*CLHEP::GeV );
2425 targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*CLHEP::GeV );
2426 //
2427 // Set |t| and |tmin|
2428 //
2429 const G4double cb = 0.01;
2430 const G4double b1 = 4.225;
2431 const G4double b2 = 1.795;
2432 //
2433 // Calculate slope b for elastic scattering on proton/neutron
2434 //
2435
2436 G4double b = std::max( cb, b1+b2*std::log(pOriginal) );
2437 // G4double b = std::max( cb, b1+b2*std::log(ptemp) );
2438 G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/CLHEP::GeV;
2439
2440 G4double exindt = -1.0;
2441 exindt += std::exp(std::max(-btrang,expxl));
2442 //
2443 // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
2444 //
2445 G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
2446 if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
2447 G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
2448 G4double phi = CLHEP::twopi * G4UniformRand();
2449 //
2450 // Calculate final state momenta in centre of mass system
2451 //
2452 if(//targetParticle.GetDefinition()->GetParticleType()=="rhadron")
2453 targetParticle.GetDefinition() == aKaonMinus ||
2454 targetParticle.GetDefinition() == aKaonZeroL ||
2455 targetParticle.GetDefinition() == aKaonZeroS ||
2456 targetParticle.GetDefinition() == aKaonPlus ||
2457 targetParticle.GetDefinition() == aPiMinus ||
2458 targetParticle.GetDefinition() == aPiZero ||
2459 targetParticle.GetDefinition() == aPiPlus )
2460 {
2461 currentParticle.SetMomentum( -pf*stet*std::sin(phi)*CLHEP::GeV,
2462 -pf*stet*std::cos(phi)*CLHEP::GeV,
2463 -pf*ctet*CLHEP::GeV );
2464 }
2465 else
2466 {
2467 currentParticle.SetMomentum( pf*stet*std::sin(phi)*CLHEP::GeV,
2468 pf*stet*std::cos(phi)*CLHEP::GeV,
2469 pf*ctet*CLHEP::GeV );
2470 }
2471 targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
2472 //
2473 // Transform into lab system
2474 //
2475 currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
2476 targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
2477
2478 /*
2479 G4cout<<"Check 1"<<G4endl;
2480 G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
2481 G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
2482 G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
2483 G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
2484 */
2485
2486 Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2487
2488 G4double pp, pp1, ekin;
2489 if( atomicWeight >= 1.5 )
2490 {
2491 const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2492 pp1 = currentParticle.GetMomentum().mag()/CLHEP::MeV;
2493 if( pp1 >= 1.0 )
2494 {
2495 ekin = currentParticle.GetKineticEnergy()/CLHEP::MeV - cfa*(1.0+0.5*normal())*CLHEP::GeV;
2496 ekin = std::max( 0.0001*CLHEP::GeV, ekin );
2497 currentParticle.SetKineticEnergy( ekin*CLHEP::MeV );
2498 pp = currentParticle.GetTotalMomentum()/CLHEP::MeV;
2499 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2500 }
2501 pp1 = targetParticle.GetMomentum().mag()/CLHEP::MeV;
2502 if( pp1 >= 1.0 )
2503 {
2504 ekin = targetParticle.GetKineticEnergy()/CLHEP::MeV - cfa*(1.0+normal()/2.)*CLHEP::GeV;
2505 ekin = std::max( 0.0001*CLHEP::GeV, ekin );
2506 targetParticle.SetKineticEnergy( ekin*CLHEP::MeV );
2507 pp = targetParticle.GetTotalMomentum()/CLHEP::MeV;
2508 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2509 }
2510 }
2511 }
2512 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2513 if( atomicWeight >= 1.5 )
2514 {
2515 // Add black track particles
2516 // the procedure is somewhat different than in TwoCluster and GenerateXandPt.
2517 // The reason is that we have to also simulate the nuclear reactions
2518 // at low energies like a(h,p)b, a(h,p p)b, a(h,n)b etc.
2519 //
2520 // npnb is number of proton/neutron black track particles
2521 // ndta is the number of deuterons, tritons, and alphas produced
2522 // epnb is the kinetic energy available for proton/neutron black track particles
2523 // edta is the kinetic energy available for deuteron/triton/alpha particles
2524 //
2525 G4double epnb, edta;
2526 G4int npnb=0, ndta=0;
2527
2528 epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
2529 edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
2530 const G4double pnCutOff = 0.0001; // GeV
2531 const G4double dtaCutOff = 0.0001; // GeV
2532 const G4double kineticMinimum = 0.0001;
2533 const G4double kineticFactor = -0.010;
2534 G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2535 if( epnb >= pnCutOff )
2536 {
2537 npnb = Poisson( epnb/0.02 );
2538 /*
2539 G4cout<<"A couple of Poisson numbers:"<<G4endl;
2540 for (int n=0;n!=10;n++) G4cout<<Poisson(epnb/0.02)<<", ";
2541 G4cout<<G4endl;
2542 */
2543 if( npnb > atomicWeight )npnb = G4int(atomicWeight);
2544 if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
2545 npnb = std::min( npnb, 127-vecLen );
2546 }
2547 if( edta >= dtaCutOff )
2548 {
2549 ndta = G4int(2.0 * std::log(atomicWeight));
2550 ndta = std::min( ndta, 127-vecLen );
2551 }
2552 G4double spall = 0.0;
2553 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2554
2555 /*
2556 G4cout<<"Check 2"<<G4endl;
2557 G4cout<<"target E_kin: "<<targetParticle.GetKineticEnergy()<<G4endl;
2558 G4cout<<"target mass: "<<targetParticle.GetMass()<<G4endl;
2559 G4cout<<"current E_kin: "<<currentParticle.GetKineticEnergy()<<G4endl;
2560 G4cout<<"current mass: "<<currentParticle.GetMass()<<G4endl;
2561
2562 G4cout<<"------------------------------------------------------------------------"<<G4endl;
2563 G4cout<<"Atomic weight: "<<atomicWeight<<G4endl;
2564 G4cout<<"number of proton/neutron black track particles: "<<npnb<<G4endl;
2565 G4cout<<"number of deuterons, tritons, and alphas produced: "<<ndta <<G4endl;
2566 G4cout<<"kinetic energy available for proton/neutron black track particles: "<<epnb/CLHEP::GeV<<" GeV" <<G4endl;
2567 G4cout<<"kinetic energy available for deuteron/triton/alpha particles: "<<edta/CLHEP::GeV <<" GeV"<<G4endl;
2568 G4cout<<"------------------------------------------------------------------------"<<G4endl;
2569 */
2570
2571 AddBlackTrackParticles( epnb, npnb, edta, ndta, sprob, kineticMinimum, kineticFactor,
2572 modifiedOriginal, spall, targetNucleus,
2573 vec, vecLen );
2574
2575 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2576 }
2577 //
2578 // calculate time delay for nuclear reactions
2579 //
2580 if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2581 currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2582 else
2583 currentParticle.SetTOF( 1.0 );
2584 return;
2585}
2586
2587G4double FullModelReactionDynamics::GenerateNBodyEvent(
2588 const G4double totalEnergy, // MeV
2589 const G4bool constantCrossSection,
2590 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2591 G4int &vecLen )
2592{
2593 // // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2594 // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
2595 // Returns the weight of the event
2596 //
2597 G4int i;
2598 const G4double expxu = 82.; // upper bound for arg. of exp
2599 const G4double expxl = -expxu; // lower bound for arg. of exp
2600 if( vecLen < 2 )
2601 {
2602 G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
2603 G4cerr << " number of particles < 2" << G4endl;
2604 G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
2605 return -1.0;
2606 }
2607 G4double mass[18]; // mass of each particle
2608 G4double energy[18]; // total energy of each particle
2609 G4double pcm[3][18]; // pcm is an array with 3 rows and vecLen columns
2610 //G4double *mass = new G4double [vecLen]; // mass of each particle
2611 //G4double *energy = new G4double [vecLen]; // total energy of each particle
2612 //G4double **pcm; // pcm is an array with 3 rows and vecLen columns
2613 //pcm = new G4double * [3];
2614 //for( i=0; i<3; ++i )pcm[i] = new G4double [vecLen];
2615
2616 G4double totalMass = 0.0;
2617 G4double sm[18];
2618 //G4double *sm = new G4double [vecLen];
2619
2620 for( i=0; i<vecLen; ++i )
2621 {
2622 mass[i] = vec[i]->GetMass()/CLHEP::GeV;
2623 vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
2624 pcm[0][i] = 0.0; // x-momentum of i-th particle
2625 pcm[1][i] = 0.0; // y-momentum of i-th particle
2626 pcm[2][i] = 0.0; // z-momentum of i-th particle
2627 energy[i] = mass[i]; // total energy of i-th particle
2628 totalMass += mass[i];
2629 sm[i] = totalMass;
2630 }
2631 G4double totalE = totalEnergy/CLHEP::GeV;
2632 if( totalMass > totalE )
2633 {
2634 //G4cerr << "*** Error in FullModelReactionDynamics::GenerateNBodyEvent" << G4endl;
2635 //G4cerr << " total mass (" << totalMass*GeV << "MeV) > total energy ("
2636 // << totalEnergy << "MeV)" << G4endl;
2637 totalE = totalMass;
2638 //delete [] mass;
2639 //delete [] energy;
2640 //for( i=0; i<3; ++i )delete [] pcm[i];
2641 //delete [] pcm;
2642 //delete [] sm;
2643 return -1.0;
2644 }
2645 G4double kineticEnergy = totalE - totalMass;
2646 G4double emm[18];
2647 //G4double *emm = new G4double [vecLen];
2648 emm[0] = mass[0];
2649 emm[vecLen-1] = totalE;
2650 if( vecLen > 2 ) // the random numbers are sorted
2651 {
2652 G4double ran[18];
2653 for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
2654 for( i=0; i<vecLen-2; ++i )
2655 {
2656 for( G4int j=vecLen-2; j>i; --j )
2657 {
2658 if( ran[i] > ran[j] )
2659 {
2660 G4double temp = ran[i];
2661 ran[i] = ran[j];
2662 ran[j] = temp;
2663 }
2664 }
2665 }
2666 for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
2667 }
2668 // Weight is the sum of logarithms of terms instead of the product of terms
2669 G4bool lzero = true;
2670 G4double wtmax = 0.0;
2671 if( constantCrossSection ) // this is KGENEV=1 in PHASP
2672 {
2673 G4double emmax = kineticEnergy + mass[0];
2674 G4double emmin = 0.0;
2675 for( i=1; i<vecLen; ++i )
2676 {
2677 emmin += mass[i-1];
2678 emmax += mass[i];
2679 G4double wtfc = 0.0;
2680 if( emmax*emmax > 0.0 )
2681 {
2682 G4double arg = emmax*emmax
2683 + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
2684 - 2.0*(emmin*emmin+mass[i]*mass[i]);
2685 if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
2686 }
2687 if( wtfc == 0.0 )
2688 {
2689 lzero = false;
2690 break;
2691 }
2692 wtmax += std::log( wtfc );
2693 }
2694 if( lzero )
2695 wtmax = -wtmax;
2696 else
2697 wtmax = expxu;
2698 }
2699 else
2700 {
2701 // ffq(n) = CLHEP::pi*(2*CLHEP::pi)^(n-2)/(n-2)!
2702 const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
2703 256.3704, 268.4705, 240.9780, 189.2637,
2704 132.1308, 83.0202, 47.4210, 24.8295,
2705 12.0006, 5.3858, 2.2560, 0.8859 };
2706 wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
2707 }
2708 lzero = true;
2709 G4double pd[50];
2710 //G4double *pd = new G4double [vecLen-1];
2711 for( i=0; i<vecLen-1; ++i )
2712 {
2713 pd[i] = 0.0;
2714 if( emm[i+1]*emm[i+1] > 0.0 )
2715 {
2716 G4double arg = emm[i+1]*emm[i+1]
2717 + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
2718 /(emm[i+1]*emm[i+1])
2719 - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
2720 if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
2721 }
2722 if( pd[i] <= 0.0 ) // changed from == on 02 April 98
2723 lzero = false;
2724 else
2725 wtmax += std::log( pd[i] );
2726 }
2727 G4double weight = 0.0; // weight is returned by GenerateNBodyEvent
2728 if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
2729
2730 G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
2731 pcm[0][0] = 0.0;
2732 pcm[1][0] = pd[0];
2733 pcm[2][0] = 0.0;
2734 for( i=1; i<vecLen; ++i )
2735 {
2736 pcm[0][i] = 0.0;
2737 pcm[1][i] = -pd[i-1];
2738 pcm[2][i] = 0.0;
2739 bang = CLHEP::twopi*G4UniformRand();
2740 cb = std::cos(bang);
2741 sb = std::sin(bang);
2742 c = 2.0*G4UniformRand() - 1.0;
2743 s = std::sqrt( std::fabs( 1.0-c*c ) );
2744 if( i < vecLen-1 )
2745 {
2746 esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
2747 beta = pd[i]/esys;
2748 gama = esys/emm[i];
2749 for( G4int j=0; j<=i; ++j )
2750 {
2751 s0 = pcm[0][j];
2752 s1 = pcm[1][j];
2753 s2 = pcm[2][j];
2754 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2755 a = s0*c - s1*s; // rotation
2756 pcm[1][j] = s0*s + s1*c;
2757 b = pcm[2][j];
2758 pcm[0][j] = a*cb - b*sb;
2759 pcm[2][j] = a*sb + b*cb;
2760 pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
2761 }
2762 }
2763 else
2764 {
2765 for( G4int j=0; j<=i; ++j )
2766 {
2767 s0 = pcm[0][j];
2768 s1 = pcm[1][j];
2769 s2 = pcm[2][j];
2770 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2771 a = s0*c - s1*s; // rotation
2772 pcm[1][j] = s0*s + s1*c;
2773 b = pcm[2][j];
2774 pcm[0][j] = a*cb - b*sb;
2775 pcm[2][j] = a*sb + b*cb;
2776 }
2777 }
2778 }
2779 for( i=0; i<vecLen; ++i )
2780 {
2781 vec[i]->SetMomentum( pcm[0][i]*CLHEP::GeV, pcm[1][i]*CLHEP::GeV, pcm[2][i]*CLHEP::GeV );
2782 vec[i]->SetTotalEnergy( energy[i]*CLHEP::GeV );
2783 }
2784 //delete [] mass;
2785 //delete [] energy;
2786 //for( i=0; i<3; ++i )delete [] pcm[i];
2787 //delete [] pcm;
2788 //delete [] emm;
2789 //delete [] sm;
2790 //delete [] pd;
2791 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2792 return weight;
2793}
2794
2795G4double
2796FullModelReactionDynamics::normal()
2797{
2798 G4double ran = -6.0;
2799 for( G4int i=0; i<12; ++i )ran += G4UniformRand();
2800 return ran;
2801}
2802
2803G4int
2804FullModelReactionDynamics::Poisson( G4double x ) // generation of poisson distribution
2805{
2806 G4int iran;
2807 G4double ran;
2808
2809 if( x > 9.9 ) // use normal distribution with sigma^2 = <x>
2810 iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
2811 else {
2812 G4int mm = G4int(5.0*x);
2813 if( mm <= 0 ) // for very small x try iran=1,2,3
2814 {
2815 G4double p1 = x*std::exp(-x);
2816 G4double p2 = x*p1/2.0;
2817 G4double p3 = x*p2/3.0;
2818 ran = G4UniformRand();
2819 if( ran < p3 )
2820 iran = 3;
2821 else if( ran < p2 ) // this is original Geisha, it should be ran < p2+p3
2822 iran = 2;
2823 else if( ran < p1 ) // should be ran < p1+p2+p3
2824 iran = 1;
2825 else
2826 iran = 0;
2827 }
2828 else
2829 {
2830 iran = 0;
2831 G4double r = std::exp(-x);
2832 ran = G4UniformRand();
2833 if( ran > r )
2834 {
2835 G4double rrr;
2836 G4double rr = r;
2837 for( G4int i=1; i<=mm; ++i )
2838 {
2839 iran++;
2840 if( i > 5 ) // Stirling's formula for large numbers
2841 rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
2842 else
2843 rrr = std::pow(x,i)/Factorial(i);
2844 rr += r*rrr;
2845 if( ran <= rr )break;
2846 }
2847 }
2848 }
2849 }
2850 return iran;
2851}
2852
2853G4int
2854FullModelReactionDynamics::Factorial( G4int n )
2855{ // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
2856 G4int m = std::min(n,10);
2857 G4int result = 1;
2858 if( m <= 1 )return result;
2859 for( G4int i=2; i<=m; ++i )result *= i;
2860 return result;
2861}
2862
2863void FullModelReactionDynamics::Defs1(
2864 const G4ReactionProduct &modifiedOriginal,
2865 G4ReactionProduct &currentParticle,
2866 G4ReactionProduct &targetParticle,
2867 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2868 G4int &vecLen )
2869{
2870 const G4double pjx = modifiedOriginal.GetMomentum().x()/CLHEP::MeV;
2871 const G4double pjy = modifiedOriginal.GetMomentum().y()/CLHEP::MeV;
2872 const G4double pjz = modifiedOriginal.GetMomentum().z()/CLHEP::MeV;
2873 const G4double p = modifiedOriginal.GetMomentum().mag()/CLHEP::MeV;
2874 if( pjx*pjx+pjy*pjy > 0.0 )
2875 {
2876 G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
2877 cost = pjz/p;
2878 sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
2879 if( pjy < 0.0 )
2880 ph = 3*CLHEP::halfpi;
2881 else
2882 ph = CLHEP::halfpi;
2883 if( std::abs( pjx ) > 0.001*CLHEP::MeV )ph = std::atan2(pjy,pjx);
2884 cosp = std::cos(ph);
2885 sinp = std::sin(ph);
2886 pix = currentParticle.GetMomentum().x()/CLHEP::MeV;
2887 piy = currentParticle.GetMomentum().y()/CLHEP::MeV;
2888 piz = currentParticle.GetMomentum().z()/CLHEP::MeV;
2889 currentParticle.SetMomentum( cost*cosp*pix*CLHEP::MeV - sinp*piy+sint*cosp*piz*CLHEP::MeV,
2890 cost*sinp*pix*CLHEP::MeV + cosp*piy+sint*sinp*piz*CLHEP::MeV,
2891 -sint*pix*CLHEP::MeV + cost*piz*CLHEP::MeV );
2892 pix = targetParticle.GetMomentum().x()/CLHEP::MeV;
2893 piy = targetParticle.GetMomentum().y()/CLHEP::MeV;
2894 piz = targetParticle.GetMomentum().z()/CLHEP::MeV;
2895 targetParticle.SetMomentum( cost*cosp*pix*CLHEP::MeV - sinp*piy+sint*cosp*piz*CLHEP::MeV,
2896 cost*sinp*pix*CLHEP::MeV + cosp*piy+sint*sinp*piz*CLHEP::MeV,
2897 -sint*pix*CLHEP::MeV + cost*piz*CLHEP::MeV );
2898 for( G4int i=0; i<vecLen; ++i )
2899 {
2900 pix = vec[i]->GetMomentum().x()/CLHEP::MeV;
2901 piy = vec[i]->GetMomentum().y()/CLHEP::MeV;
2902 piz = vec[i]->GetMomentum().z()/CLHEP::MeV;
2903 vec[i]->SetMomentum( cost*cosp*pix*CLHEP::MeV - sinp*piy+sint*cosp*piz*CLHEP::MeV,
2904 cost*sinp*pix*CLHEP::MeV + cosp*piy+sint*sinp*piz*CLHEP::MeV,
2905 -sint*pix*CLHEP::MeV + cost*piz*CLHEP::MeV );
2906 }
2907 }
2908 else
2909 {
2910 if( pjz < 0.0 )
2911 {
2912 currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
2913 targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
2914 for( G4int i=0; i<vecLen; ++i )
2915 vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
2916 }
2917 }
2918}
2919
2920void FullModelReactionDynamics::Rotate(
2921 const G4double numberofFinalStateNucleons,
2922 const G4ThreeVector &temp,
2923 const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
2924 const G4HadProjectile *originalIncident, // original incident particle
2925 const G4Nucleus &targetNucleus,
2926 G4ReactionProduct &currentParticle,
2927 G4ReactionProduct &targetParticle,
2928 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
2929 G4int &vecLen )
2930{
2931 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
2932 //
2933 // Rotate in direction of z-axis, this does disturb in some way our
2934 // inclusive distributions, but it is necessary for momentum conservation
2935 //
2936 const G4double atomicWeight = targetNucleus.AtomicMass(targetNucleus.GetA_asInt(),targetNucleus.GetZ_asInt());//targetNucleus.GetN();
2937 const G4double logWeight = std::log(atomicWeight);
2938
2939 G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2940 G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2941 G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2942
2943 G4int i;
2944 G4ThreeVector pseudoParticle[4];
2945 for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
2946 pseudoParticle[0] = currentParticle.GetMomentum()
2947 + targetParticle.GetMomentum();
2948 for( i=0; i<vecLen; ++i )
2949 pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
2950 //
2951 // Some smearing in transverse direction from Fermi motion
2952 //
2953 G4double pp, pp1;
2954 G4double alekw, p, rthnve, phinve;
2955 G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
2956
2957 r1 = CLHEP::twopi*G4UniformRand();
2958 r2 = G4UniformRand();
2959 a1 = std::sqrt(-2.0*std::log(r2));
2960 ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*CLHEP::GeV;
2961 ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*CLHEP::GeV;
2962 G4ThreeVector Fermi(ran1, ran2, 0);
2963
2964 pseudoParticle[0] = pseudoParticle[0]+Fermi; // all particles + Fermi
2965 pseudoParticle[2] = temp; // original in cms system
2966 pseudoParticle[3] = pseudoParticle[0];
2967
2968 pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
2969 G4double rotation = 2.*CLHEP::pi*G4UniformRand();
2970 pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
2971 pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);
2972 for(G4int ii=1; ii<=3; ii++)
2973 {
2974 p = pseudoParticle[ii].mag();
2975 if( p == 0.0 )
2976 pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
2977 else
2978 pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
2979 }
2980
2981 pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
2982 pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
2983 pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
2984 currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2985
2986 pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
2987 pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
2988 pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
2989 targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2990
2991 for( i=0; i<vecLen; ++i )
2992 {
2993 pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
2994 pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
2995 pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
2996 vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
2997 }
2998 //
2999 // Rotate in direction of primary particle, subtract binding energies
3000 // and make some further corrections if required
3001 //
3002 Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
3003 G4double ekin;
3004 G4double dekin = 0.0;
3005 G4double ek1 = 0.0;
3006 G4int npions = 0;
3007 if( atomicWeight >= 1.5 ) // self-absorption in heavy molecules
3008 {
3009 // corrections for single particle spectra (shower particles)
3010 //
3011 const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
3012 const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
3013 alekw = std::log( originalIncident->GetKineticEnergy()/CLHEP::GeV );
3014 exh = 1.0;
3015 if( alekw > alem[0] ) // get energy bin
3016 {
3017 exh = val0[6];
3018 for( G4int j=1; j<7; ++j )
3019 {
3020 if( alekw < alem[j] ) // use linear interpolation/extrapolation
3021 {
3022 G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
3023 exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
3024 break;
3025 }
3026 }
3027 exh = 1.0 - exh;
3028 }
3029 const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
3030 ekin = currentParticle.GetKineticEnergy()/CLHEP::GeV - cfa*(1+normal()/2.0);
3031 ekin = std::max( 1.0e-6, ekin );
3032 xxh = 1.0;
3033 /* if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3034 (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3035 (currentParticle.GetDefinition() == aPiZero) &&
3036 (G4UniformRand() <= logWeight) )xxh = exh;*/
3037 dekin += ekin*(1.0-xxh);
3038 ekin *= xxh;
3039 /* if( (currentParticle.GetDefinition() == aPiPlus) ||
3040 (currentParticle.GetDefinition() == aPiZero) ||
3041 (currentParticle.GetDefinition() == aPiMinus) )
3042 {
3043 ++npions;
3044 ek1 += ekin;
3045 }*/
3046 currentParticle.SetKineticEnergy( ekin*CLHEP::GeV );
3047 pp = currentParticle.GetTotalMomentum()/CLHEP::MeV;
3048 pp1 = currentParticle.GetMomentum().mag()/CLHEP::MeV;
3049 if( pp1 < 0.001*CLHEP::MeV )
3050 {
3051 rthnve = CLHEP::pi*G4UniformRand();
3052 phinve = CLHEP::twopi*G4UniformRand();
3053 currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3054 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3055 pp*std::cos(rthnve)*CLHEP::MeV );
3056 }
3057 else
3058 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3059 ekin = targetParticle.GetKineticEnergy()/CLHEP::GeV - cfa*(1+normal()/2.0);
3060 ekin = std::max( 1.0e-6, ekin );
3061 xxh = 1.0;
3062 if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3063 (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3064 (targetParticle.GetDefinition() == aPiZero) &&
3065 (G4UniformRand() < logWeight) )xxh = exh;
3066 dekin += ekin*(1.0-xxh);
3067 ekin *= xxh;
3068 if( (targetParticle.GetDefinition() == aPiPlus) ||
3069 (targetParticle.GetDefinition() == aPiZero) ||
3070 (targetParticle.GetDefinition() == aPiMinus) )
3071 {
3072 ++npions;
3073 ek1 += ekin;
3074 }
3075 targetParticle.SetKineticEnergy( ekin*CLHEP::GeV );
3076 pp = targetParticle.GetTotalMomentum()/CLHEP::MeV;
3077 pp1 = targetParticle.GetMomentum().mag()/CLHEP::MeV;
3078 if( pp1 < 0.001*CLHEP::MeV )
3079 {
3080 rthnve = CLHEP::pi*G4UniformRand();
3081 phinve = CLHEP::twopi*G4UniformRand();
3082 targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3083 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3084 pp*std::cos(rthnve)*CLHEP::MeV );
3085 }
3086 else
3087 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3088 for( i=0; i<vecLen; ++i )
3089 {
3090 ekin = vec[i]->GetKineticEnergy()/CLHEP::GeV - cfa*(1+normal()/2.0);
3091 ekin = std::max( 1.0e-6, ekin );
3092 xxh = 1.0;
3093 if( ( (modifiedOriginal.GetDefinition() == aPiPlus) ||
3094 (modifiedOriginal.GetDefinition() == aPiMinus) ) &&
3095 (vec[i]->GetDefinition() == aPiZero) &&
3096 (G4UniformRand() < logWeight) )xxh = exh;
3097 dekin += ekin*(1.0-xxh);
3098 ekin *= xxh;
3099 if( (vec[i]->GetDefinition() == aPiPlus) ||
3100 (vec[i]->GetDefinition() == aPiZero) ||
3101 (vec[i]->GetDefinition() == aPiMinus) )
3102 {
3103 ++npions;
3104 ek1 += ekin;
3105 }
3106 vec[i]->SetKineticEnergy( ekin*CLHEP::GeV );
3107 pp = vec[i]->GetTotalMomentum()/CLHEP::MeV;
3108 pp1 = vec[i]->GetMomentum().mag()/CLHEP::MeV;
3109 if( pp1 < 0.001*CLHEP::MeV )
3110 {
3111 rthnve = CLHEP::pi*G4UniformRand();
3112 phinve = CLHEP::twopi*G4UniformRand();
3113 vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3114 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3115 pp*std::cos(rthnve)*CLHEP::MeV );
3116 }
3117 else
3118 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3119 }
3120 }
3121 if( (ek1 != 0.0) && (npions > 0) )
3122 {
3123 dekin = 1.0 + dekin/ek1;
3124 //
3125 // first do the incident particle
3126 //
3127 if( (currentParticle.GetDefinition() == aPiPlus) ||
3128 (currentParticle.GetDefinition() == aPiZero) ||
3129 (currentParticle.GetDefinition() == aPiMinus) )
3130 {
3131 currentParticle.SetKineticEnergy(
3132 std::max( 0.001*CLHEP::MeV, dekin*currentParticle.GetKineticEnergy() ) );
3133 pp = currentParticle.GetTotalMomentum()/CLHEP::MeV;
3134 pp1 = currentParticle.GetMomentum().mag()/CLHEP::MeV;
3135 if( pp1 < 0.001 )
3136 {
3137 rthnve = CLHEP::pi*G4UniformRand();
3138 phinve = CLHEP::twopi*G4UniformRand();
3139 currentParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3140 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3141 pp*std::cos(rthnve)*CLHEP::MeV );
3142 }
3143 else
3144 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3145 }
3146 /* if( (targetParticle.GetDefinition() == aPiPlus) ||
3147 (targetParticle.GetDefinition() == aPiZero) ||
3148 (targetParticle.GetDefinition() == aPiMinus) )
3149 {
3150 targetParticle.SetKineticEnergy(
3151 std::max( 0.001*CLHEP::MeV, dekin*targetParticle.GetKineticEnergy() ) );
3152 pp = targetParticle.GetTotalMomentum()/CLHEP::MeV;
3153 pp1 = targetParticle.GetMomentum().mag()/CLHEP::MeV;
3154 if( pp1 < 0.001 )
3155 {
3156 rthnve = CLHEP::pi*G4UniformRand();
3157 phinve = CLHEP::twopi*G4UniformRand();
3158 targetParticle.SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3159 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3160 pp*std::cos(rthnve)*CLHEP::MeV );
3161 }
3162 else
3163 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3164 }*/
3165 for( i=0; i<vecLen; ++i )
3166 {
3167 if( (vec[i]->GetDefinition() == aPiPlus) ||
3168 (vec[i]->GetDefinition() == aPiZero) ||
3169 (vec[i]->GetDefinition() == aPiMinus) )
3170 {
3171 vec[i]->SetKineticEnergy( std::max( 0.001*CLHEP::MeV, dekin*vec[i]->GetKineticEnergy() ) );
3172 pp = vec[i]->GetTotalMomentum()/CLHEP::MeV;
3173 pp1 = vec[i]->GetMomentum().mag()/CLHEP::MeV;
3174 if( pp1 < 0.001 )
3175 {
3176 rthnve = CLHEP::pi*G4UniformRand();
3177 phinve = CLHEP::twopi*G4UniformRand();
3178 vec[i]->SetMomentum( pp*std::sin(rthnve)*std::cos(phinve)*CLHEP::MeV,
3179 pp*std::sin(rthnve)*std::sin(phinve)*CLHEP::MeV,
3180 pp*std::cos(rthnve)*CLHEP::MeV );
3181 }
3182 else
3183 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3184 }
3185 }
3186 }
3187}
3188
3189void FullModelReactionDynamics::AddBlackTrackParticles(
3190 const G4double epnb, // GeV
3191 const G4int npnb,
3192 const G4double edta, // GeV
3193 const G4int ndta,
3194 const G4double sprob,
3195 const G4double kineticMinimum, // GeV
3196 const G4double kineticFactor, // GeV
3197 const G4ReactionProduct &modifiedOriginal,
3198 G4double spall,
3199 const G4Nucleus &targetNucleus,
3200 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3201 G4int &vecLen )
3202{
3203 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
3204 //
3205 // npnb is number of proton/neutron black track particles
3206 // ndta is the number of deuterons, tritons, and alphas produced
3207 // epnb is the kinetic energy available for proton/neutron black track particles
3208 // edta is the kinetic energy available for deuteron/triton/alpha particles
3209 //
3210
3211 G4ParticleDefinition *aProton = G4Proton::Proton();
3212 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3213 G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3214 G4ParticleDefinition *aTriton = G4Triton::Triton();
3215 G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3216
3217 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/CLHEP::MeV;
3218 const G4double atomicWeight = targetNucleus.AtomicMass(targetNucleus.GetA_asInt(),targetNucleus.GetZ_asInt());
3219 //std::cout<<"atomicWeight "<<atomicWeight<<" and GetN_asInt "<<targetNucleus.GetN_asInt()<<" and GetA_asInt "<<targetNucleus.GetA_asInt()<<" for GetN "<<targetNucleus.GetN()<<std::endl;
3220 const G4double atomicNumber = targetNucleus.GetZ_asInt();
3221 //std::cout<<"atomicNumber "<<atomicNumber<<" for GetZ "<<targetNucleus.GetZ()<<std::endl;
3222
3223 const G4double ika1 = 3.6;
3224 const G4double ika2 = 35.56;
3225 const G4double ika3 = 6.45;
3226 const G4double sp1 = 1.066;
3227
3228 G4int i;
3229 G4double pp;
3230 // G4double totalQ = 0;
3231 // G4double kinCreated = 0;
3232 G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
3233 if( npnb > 0) // first add protons and neutrons
3234 {
3235 G4double backwardKinetic = 0.0;
3236 G4int local_npnb = npnb;
3237 for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
3238 G4double ekin = epnb/local_npnb;
3239
3240 for( i=0; i<local_npnb; ++i )
3241 {
3242 G4ReactionProduct * p1 = new G4ReactionProduct();
3243 if( backwardKinetic > epnb )
3244 {
3245 delete p1;
3246 break;
3247 }
3248 G4double ran = G4UniformRand();
3249 G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
3250 if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
3251 backwardKinetic += kinetic;
3252 if( backwardKinetic > epnb )
3253 kinetic = std::max( kineticMinimum, epnb-(backwardKinetic-kinetic) );
3254 if( G4UniformRand() > (1.0-atomicNumber/atomicWeight) )
3255 p1->SetDefinition( aProton );
3256 else
3257 p1->SetDefinition( aNeutron );
3258 vec.SetElement( vecLen, p1 );
3259 ++spall;
3260 G4double cost = G4UniformRand() * 2.0 - 1.0;
3261 G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
3262 G4double phi = CLHEP::twopi * G4UniformRand();
3263 vec[vecLen]->SetNewlyAdded( true );
3264 vec[vecLen]->SetKineticEnergy( kinetic*CLHEP::GeV );
3265 // kinCreated+=kinetic;
3266 pp = vec[vecLen]->GetTotalMomentum()/CLHEP::MeV;
3267 vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*CLHEP::MeV,
3268 pp*sint*std::cos(phi)*CLHEP::MeV,
3269 pp*cost*CLHEP::MeV );
3270 vecLen++;
3271 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3272 }
3273 if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*CLHEP::GeV) )
3274 {
3275 G4double ekw = ekOriginal/CLHEP::GeV;
3276 G4int ika, kk = 0;
3277 if( ekw > 1.0 )ekw *= ekw;
3278 ekw = std::max( 0.1, ekw );
3279 ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/atomicWeight-ika2)/ika3)/ekw);
3280 if( ika > 0 )
3281 {
3282 for( i=(vecLen-1); i>=0; --i )
3283 {
3284 if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
3285 {
3286 vec[i]->SetDefinitionAndUpdateE( aNeutron ); // modified 22-Oct-97
3287 if( ++kk > ika )break;
3288 }
3289 }
3290 }
3291 }
3292 }
3293 if( ndta > 0 ) // now, try to add deuterons, tritons and alphas
3294 {
3295 G4double backwardKinetic = 0.0;
3296 G4int local_ndta=ndta;
3297 for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
3298 G4double ekin = edta/local_ndta;
3299
3300 for( i=0; i<local_ndta; ++i )
3301 {
3302 G4ReactionProduct *p2 = new G4ReactionProduct();
3303 if( backwardKinetic > edta )
3304 {
3305 delete p2;
3306 break;
3307 }
3308 G4double ran = G4UniformRand();
3309 G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
3310 if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
3311 backwardKinetic += kinetic;
3312 if( backwardKinetic > edta )kinetic = edta-(backwardKinetic-kinetic);
3313 if( kinetic < 0.0 )kinetic = kineticMinimum;
3314 G4double cost = 2.0*G4UniformRand() - 1.0;
3315 G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
3316 G4double phi = CLHEP::twopi*G4UniformRand();
3317 ran = G4UniformRand();
3318 if( ran <= 0.60 )
3319 p2->SetDefinition( aDeuteron );
3320 else if( ran <= 0.90 )
3321 p2->SetDefinition( aTriton );
3322 else
3323 p2->SetDefinition( anAlpha );
3324 spall += p2->GetMass()/CLHEP::GeV * sp1;
3325 if( spall > atomicWeight )
3326 {
3327 delete p2;
3328 break;
3329 }
3330 vec.SetElement( vecLen, p2 );
3331 vec[vecLen]->SetNewlyAdded( true );
3332 vec[vecLen]->SetKineticEnergy( kinetic*CLHEP::GeV );
3333 // kinCreated+=kinetic;
3334 pp = vec[vecLen]->GetTotalMomentum()/CLHEP::MeV;
3335 vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*CLHEP::MeV,
3336 pp*sint*std::cos(phi)*CLHEP::MeV,
3337 pp*cost*CLHEP::MeV );
3338 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3339 }
3340 }
3341 // G4double delta = epnb+edta - kinCreated;
3342}
3343
3344void FullModelReactionDynamics::MomentumCheck(
3345 const G4ReactionProduct &modifiedOriginal,
3346 G4ReactionProduct &currentParticle,
3347 G4ReactionProduct &targetParticle,
3348 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3349 G4int &vecLen )
3350{
3351 const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/CLHEP::MeV;
3352 G4double testMomentum = currentParticle.GetMomentum().mag()/CLHEP::MeV;
3353 G4double pMass;
3354 if( testMomentum >= pOriginal )
3355 {
3356 pMass = currentParticle.GetMass()/CLHEP::MeV;
3357 currentParticle.SetTotalEnergy(
3358 std::sqrt( pMass*pMass + pOriginal*pOriginal )*CLHEP::MeV );
3359 currentParticle.SetMomentum(
3360 currentParticle.GetMomentum() * (pOriginal/testMomentum) );
3361 }
3362 testMomentum = targetParticle.GetMomentum().mag()/CLHEP::MeV;
3363 if( testMomentum >= pOriginal )
3364 {
3365 pMass = targetParticle.GetMass()/CLHEP::MeV;
3366 targetParticle.SetTotalEnergy(
3367 std::sqrt( pMass*pMass + pOriginal*pOriginal )*CLHEP::MeV );
3368 targetParticle.SetMomentum(
3369 targetParticle.GetMomentum() * (pOriginal/testMomentum) );
3370 }
3371 for( G4int i=0; i<vecLen; ++i )
3372 {
3373 testMomentum = vec[i]->GetMomentum().mag()/CLHEP::MeV;
3374 if( testMomentum >= pOriginal )
3375 {
3376 pMass = vec[i]->GetMass()/CLHEP::MeV;
3377 vec[i]->SetTotalEnergy(
3378 std::sqrt( pMass*pMass + pOriginal*pOriginal )*CLHEP::MeV );
3379 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
3380 }
3381 }
3382}
3383
3384void FullModelReactionDynamics::ProduceStrangeParticlePairs(
3385 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> &vec,
3386 G4int &vecLen,
3387 const G4ReactionProduct &modifiedOriginal,
3388 const G4DynamicParticle *originalTarget,
3389 G4ReactionProduct &currentParticle,
3390 G4ReactionProduct &targetParticle,
3391 G4bool &incidentHasChanged,
3392 G4bool &targetHasChanged )
3393{
3394 // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
3395 //
3396 // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
3397 // K+ Y0, K0 Y+, K0 Y-
3398 // For antibaryon induced reactions half of the cross sections KB YB
3399 // pairs are produced. Charge is not conserved, no experimental data available
3400 // for exclusive reactions, therefore some average behaviour assumed.
3401 // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
3402 //
3403 if( vecLen == 0 )return;
3404 //
3405 // the following protects against annihilation processes
3406 //
3407 if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
3408
3409 const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/CLHEP::GeV;
3410 const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/CLHEP::GeV;
3411 G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/CLHEP::GeV;
3412 G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
3413 targetMass*targetMass +
3414 2.0*targetMass*etOriginal ); // GeV
3415 G4double currentMass = currentParticle.GetMass()/CLHEP::GeV;
3416 G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
3417 if( availableEnergy <= 1.0 )return;
3418
3419 G4ParticleDefinition *aProton = G4Proton::Proton();
3420 G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
3421 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3422 G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
3423 G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
3424 G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
3425 G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
3426 G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
3427 G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
3428 G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
3429 G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
3430 G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
3431 G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
3432 G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
3433 G4ParticleDefinition *aLambda = G4Lambda::Lambda();
3434 G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
3435
3436 const G4double protonMass = aProton->GetPDGMass()/CLHEP::GeV;
3437 const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/CLHEP::GeV;
3438 //
3439 // determine the center of mass energy bin
3440 //
3441 const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
3442
3443 G4int ibin, i3, i4;
3444 G4double avk, avy, avn, ran;
3445 G4int i = 1;
3446 while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
3447 if( i == 12 )
3448 ibin = 11;
3449 else
3450 ibin = i;
3451 //
3452 // the fortran code chooses a random replacement of produced kaons
3453 // but does not take into account charge conservation
3454 //
3455 if( vecLen == 1 ) // we know that vecLen > 0
3456 {
3457 i3 = 0;
3458 i4 = 1; // note that we will be adding a new secondary particle in this case only
3459 }
3460 else // otherwise 0 <= i3,i4 < vecLen
3461 {
3462 G4double ran = G4UniformRand();
3463 while( ran == 1.0 )ran = G4UniformRand();
3464 i4 = i3 = G4int( vecLen*ran );
3465 while( i3 == i4 )
3466 {
3467 ran = G4UniformRand();
3468 while( ran == 1.0 )ran = G4UniformRand();
3469 i4 = G4int( vecLen*ran );
3470 }
3471 }
3472 //
3473 // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
3474 //
3475 const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
3476 0.0975, 0.123, 0.28, 0.398, 0.495, 0.573 };
3477 const G4double avky[] = { 0.005, 0.03, 0.064, 0.095, 0.115, 0.13,
3478 0.145, 0.155, 0.20, 0.205, 0.210, 0.212 };
3479 const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
3480 0.04, 0.05, 0.12, 0.15, 0.18, 0.20 };
3481
3482 avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3483 /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
3484 avk = std::exp(avk);
3485
3486 avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3487 /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
3488 avy = std::exp(avy);
3489
3490 avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3491 /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
3492 avn = std::exp(avn);
3493
3494 if( avk+avy+avn <= 0.0 )return;
3495
3496 if( currentMass < protonMass )avy /= 2.0;
3497 if( targetMass < protonMass )avy = 0.0;
3498 avy += avk+avn;
3499 avk += avn;
3500 ran = G4UniformRand();
3501 if( ran < avn )
3502 {
3503 if( availableEnergy < 2.0 )return;
3504 if( vecLen == 1 ) // add a new secondary
3505 {
3506 G4ReactionProduct *p1 = new G4ReactionProduct;
3507 if( G4UniformRand() < 0.5 )
3508 {
3509 vec[0]->SetDefinition( aNeutron );
3510 p1->SetDefinition( anAntiNeutron );
3511 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3512 vec[0]->SetMayBeKilled(false);
3513 p1->SetMayBeKilled(false);
3514 }
3515 else
3516 {
3517 vec[0]->SetDefinition( aProton );
3518 p1->SetDefinition( anAntiProton );
3519 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3520 vec[0]->SetMayBeKilled(false);
3521 p1->SetMayBeKilled(false);
3522 }
3523 vec.SetElement( vecLen++, p1 );
3524 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3525 }
3526 else
3527 { // replace two secondaries
3528 if( G4UniformRand() < 0.5 )
3529 {
3530 vec[i3]->SetDefinition( aNeutron );
3531 vec[i4]->SetDefinition( anAntiNeutron );
3532 vec[i3]->SetMayBeKilled(false);
3533 vec[i4]->SetMayBeKilled(false);
3534 }
3535 else
3536 {
3537 vec[i3]->SetDefinition( aProton );
3538 vec[i4]->SetDefinition( anAntiProton );
3539 vec[i3]->SetMayBeKilled(false);
3540 vec[i4]->SetMayBeKilled(false);
3541 }
3542 }
3543 }
3544 else if( ran < avk )
3545 {
3546 if( availableEnergy < 1.0 )return;
3547
3548 const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
3549 0.6875, 0.7500, 0.8750, 1.000 };
3550 const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
3551 const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
3552 ran = G4UniformRand();
3553 i = 0;
3554 while( (i<9) && (ran>=kkb[i]) )++i;
3555 if( i == 9 )return;
3556 //
3557 // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
3558 // charge + - + 0 + 0 0 0 0 0 0 0 0 0 0 - 0 -
3559 //
3560 switch( ipakkb1[i] )
3561 {
3562 case 10:
3563 vec[i3]->SetDefinition( aKaonPlus );
3564 vec[i3]->SetMayBeKilled(false);
3565 break;
3566 case 11:
3567 vec[i3]->SetDefinition( aKaonZS );
3568 vec[i3]->SetMayBeKilled(false);
3569 break;
3570 case 12:
3571 vec[i3]->SetDefinition( aKaonZL );
3572 vec[i3]->SetMayBeKilled(false);
3573 break;
3574 }
3575 if( vecLen == 1 ) // add a secondary
3576 {
3577 G4ReactionProduct *p1 = new G4ReactionProduct;
3578 switch( ipakkb2[i] )
3579 {
3580 case 11:
3581 p1->SetDefinition( aKaonZS );
3582 p1->SetMayBeKilled(false);
3583 break;
3584 case 12:
3585 p1->SetDefinition( aKaonZL );
3586 p1->SetMayBeKilled(false);
3587 break;
3588 case 13:
3589 p1->SetDefinition( aKaonMinus );
3590 p1->SetMayBeKilled(false);
3591 break;
3592 }
3593 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3594 vec.SetElement( vecLen++, p1 );
3595 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3596 }
3597 else // replace
3598 {
3599 switch( ipakkb2[i] )
3600 {
3601 case 11:
3602 vec[i4]->SetDefinition( aKaonZS );
3603 vec[i4]->SetMayBeKilled(false);
3604 break;
3605 case 12:
3606 vec[i4]->SetDefinition( aKaonZL );
3607 vec[i4]->SetMayBeKilled(false);
3608 break;
3609 case 13:
3610 vec[i4]->SetDefinition( aKaonMinus );
3611 vec[i4]->SetMayBeKilled(false);
3612 break;
3613 }
3614 }
3615 }
3616 else if( ran < avy )
3617 {
3618 if( availableEnergy < 1.6 )return;
3619
3620 const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
3621 0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
3622 const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
3623 const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
3624 const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
3625 const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
3626 ran = G4UniformRand();
3627 i = 0;
3628 while( (i<12) && (ran>ky[i]) )++i;
3629 if( i == 12 )return;
3630 if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
3631 {
3632 // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
3633 // 0 + 0 0 0 0 + + + 0 + 0
3634 //
3635 // 21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
3636 // 0 + 0 0 0 0 - + - 0 - 0
3637 switch( ipaky1[i] )
3638 {
3639 case 18:
3640 targetParticle.SetDefinition( aLambda );
3641 break;
3642 case 20:
3643 targetParticle.SetDefinition( aSigmaPlus );
3644 break;
3645 case 21:
3646 targetParticle.SetDefinition( aSigmaZero );
3647 break;
3648 case 22:
3649 targetParticle.SetDefinition( aSigmaMinus );
3650 break;
3651 }
3652 targetHasChanged = true;
3653 switch( ipaky2[i] )
3654 {
3655 case 10:
3656 vec[i3]->SetDefinition( aKaonPlus );
3657 vec[i3]->SetMayBeKilled(false);
3658 break;
3659 case 11:
3660 vec[i3]->SetDefinition( aKaonZS );
3661 vec[i3]->SetMayBeKilled(false);
3662 break;
3663 case 12:
3664 vec[i3]->SetDefinition( aKaonZL );
3665 vec[i3]->SetMayBeKilled(false);
3666 break;
3667 }
3668 }
3669 else // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
3670 {
3671 // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
3672 // 24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
3673 if( (currentParticle.GetDefinition() == anAntiProton) ||
3674 (currentParticle.GetDefinition() == anAntiNeutron) ||
3675 (currentParticle.GetDefinition() == anAntiLambda) ||
3676 (currentMass > sigmaMinusMass) )
3677 {
3678 switch( ipakyb1[i] )
3679 {
3680 case 19:
3681 currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
3682 break;
3683 case 23:
3684 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
3685 break;
3686 case 24:
3687 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
3688 break;
3689 case 25:
3690 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
3691 break;
3692 }
3693 incidentHasChanged = true;
3694 switch( ipakyb2[i] )
3695 {
3696 case 11:
3697 vec[i3]->SetDefinition( aKaonZS );
3698 vec[i3]->SetMayBeKilled(false);
3699 break;
3700 case 12:
3701 vec[i3]->SetDefinition( aKaonZL );
3702 vec[i3]->SetMayBeKilled(false);
3703 break;
3704 case 13:
3705 vec[i3]->SetDefinition( aKaonMinus );
3706 vec[i3]->SetMayBeKilled(false);
3707 break;
3708 }
3709 }
3710 else
3711 {
3712 switch( ipaky1[i] )
3713 {
3714 case 18:
3715 currentParticle.SetDefinitionAndUpdateE( aLambda );
3716 break;
3717 case 20:
3718 currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
3719 break;
3720 case 21:
3721 currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
3722 break;
3723 case 22:
3724 currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
3725 break;
3726 }
3727 incidentHasChanged = true;
3728 switch( ipaky2[i] )
3729 {
3730 case 10:
3731 vec[i3]->SetDefinition( aKaonPlus );
3732 vec[i3]->SetMayBeKilled(false);
3733 break;
3734 case 11:
3735 vec[i3]->SetDefinition( aKaonZS );
3736 vec[i3]->SetMayBeKilled(false);
3737 break;
3738 case 12:
3739 vec[i3]->SetDefinition( aKaonZL );
3740 vec[i3]->SetMayBeKilled(false);
3741 break;
3742 }
3743 }
3744 }
3745 }
3746 else return;
3747 //
3748 // check the available energy
3749 // if there is not enough energy for kkb/ky pair production
3750 // then reduce the number of secondary particles
3751 // NOTE:
3752 // the number of secondaries may have been changed
3753 // the incident and/or target particles may have changed
3754 // charge conservation is ignored (as well as strangness conservation)
3755 //
3756 currentMass = currentParticle.GetMass()/CLHEP::GeV;
3757 targetMass = targetParticle.GetMass()/CLHEP::GeV;
3758
3759 G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
3760 for( i=0; i<vecLen; ++i )
3761 {
3762 energyCheck -= vec[i]->GetMass()/CLHEP::GeV;
3763 if( energyCheck < 0.0 ) // chop off the secondary List
3764 {
3765 vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
3766 G4int j;
3767 for(j=i; j<vecLen; j++) delete vec[j];
3768 break;
3769 }
3770 }
3771 return;
3772}
3773
3774void
3775FullModelReactionDynamics::NuclearReaction(
3776 G4FastVector<G4ReactionProduct,4> &vec,
3777 G4int &vecLen,
3778 const G4HadProjectile *originalIncident,
3779 const G4Nucleus &targetNucleus,
3780 const G4double theAtomicMass,
3781 const G4double *mass )
3782{
3783 // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
3784 //
3785 // Nuclear reaction kinematics at low energies
3786 //
3787 G4ParticleDefinition *aGamma = G4Gamma::Gamma();
3788 G4ParticleDefinition *aProton = G4Proton::Proton();
3789 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3790 G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3791 G4ParticleDefinition *aTriton = G4Triton::Triton();
3792 G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3793
3794 const G4double aProtonMass = aProton->GetPDGMass()/CLHEP::MeV;
3795 const G4double aNeutronMass = aNeutron->GetPDGMass()/CLHEP::MeV;
3796 const G4double aDeuteronMass = aDeuteron->GetPDGMass()/CLHEP::MeV;
3797 const G4double aTritonMass = aTriton->GetPDGMass()/CLHEP::MeV;
3798 const G4double anAlphaMass = anAlpha->GetPDGMass()/CLHEP::MeV;
3799
3800 G4ReactionProduct currentParticle;
3801 currentParticle = *originalIncident;
3802 //
3803 // Set beam particle, take kinetic energy of current particle as the
3804 // fundamental quantity. Due to the difficult kinematic, all masses have to
3805 // be assigned the best measured values
3806 //
3807 G4double p = currentParticle.GetTotalMomentum();
3808 G4double pp = currentParticle.GetMomentum().mag();
3809 if( pp <= 0.001*CLHEP::MeV )
3810 {
3811 G4double phinve = CLHEP::twopi*G4UniformRand();
3812 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3813 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3814 p*std::sin(rthnve)*std::sin(phinve),
3815 p*std::cos(rthnve) );
3816 }
3817 else
3818 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3819 //
3820 // calculate Q-value of reactions
3821 //
3822 G4double currentKinetic = currentParticle.GetKineticEnergy()/CLHEP::MeV;
3823 G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/CLHEP::MeV;
3824 G4double qv = currentKinetic + theAtomicMass + currentMass;
3825
3826 G4double qval[9];
3827 qval[0] = qv - mass[0];
3828 qval[1] = qv - mass[1] - aNeutronMass;
3829 qval[2] = qv - mass[2] - aProtonMass;
3830 qval[3] = qv - mass[3] - aDeuteronMass;
3831 qval[4] = qv - mass[4] - aTritonMass;
3832 qval[5] = qv - mass[5] - anAlphaMass;
3833 qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
3834 qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
3835 qval[8] = qv - mass[8] - aProtonMass - aProtonMass;
3836
3837 if( currentParticle.GetDefinition() == aNeutron )
3838 {
3839 // atomic weight
3840 const G4double A = targetNucleus.AtomicMass(targetNucleus.GetA_asInt(),targetNucleus.GetZ_asInt());//targetNucleus.GetN();
3841 if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
3842 qval[0] = 0.0;
3843 if( G4UniformRand() >= currentKinetic/7.9254*A )
3844 qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
3845 }
3846 else
3847 qval[0] = 0.0;
3848
3849 G4int i;
3850 qv = 0.0;
3851 for( i=0; i<9; ++i )
3852 {
3853 if( mass[i] < 500.0*CLHEP::MeV )qval[i] = 0.0;
3854 if( qval[i] < 0.0 )qval[i] = 0.0;
3855 qv += qval[i];
3856 }
3857 G4double qv1 = 0.0;
3858 G4double ran = G4UniformRand();
3859 G4int index;
3860 for( index=0; index<9; ++index )
3861 {
3862 if( qval[index] > 0.0 )
3863 {
3864 qv1 += qval[index]/qv;
3865 if( ran <= qv1 )break;
3866 }
3867 }
3868 if( index == 9 ) // loop continued to the end
3869 {
3870 throw G4HadronicException(__FILE__, __LINE__,
3871 "FullModelReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
3872 }
3873 G4double ke = currentParticle.GetKineticEnergy()/CLHEP::GeV;
3874 G4int nt = 2;
3875 if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
3876
3877 G4ReactionProduct **v = new G4ReactionProduct * [3];
3878 v[0] = new G4ReactionProduct;
3879 v[1] = new G4ReactionProduct;
3880 v[2] = new G4ReactionProduct;
3881
3882 v[0]->SetMass( mass[index]*CLHEP::MeV );
3883 switch( index )
3884 {
3885 case 0:
3886 v[1]->SetDefinition( aGamma );
3887 v[2]->SetDefinition( aGamma );
3888 break;
3889 case 1:
3890 v[1]->SetDefinition( aNeutron );
3891 v[2]->SetDefinition( aGamma );
3892 break;
3893 case 2:
3894 v[1]->SetDefinition( aProton );
3895 v[2]->SetDefinition( aGamma );
3896 break;
3897 case 3:
3898 v[1]->SetDefinition( aDeuteron );
3899 v[2]->SetDefinition( aGamma );
3900 break;
3901 case 4:
3902 v[1]->SetDefinition( aTriton );
3903 v[2]->SetDefinition( aGamma );
3904 break;
3905 case 5:
3906 v[1]->SetDefinition( anAlpha );
3907 v[2]->SetDefinition( aGamma );
3908 break;
3909 case 6:
3910 v[1]->SetDefinition( aNeutron );
3911 v[2]->SetDefinition( aNeutron );
3912 break;
3913 case 7:
3914 v[1]->SetDefinition( aNeutron );
3915 v[2]->SetDefinition( aProton );
3916 break;
3917 case 8:
3918 v[1]->SetDefinition( aProton );
3919 v[2]->SetDefinition( aProton );
3920 break;
3921 }
3922 //
3923 // calculate centre of mass energy
3924 //
3925 G4ReactionProduct pseudo1;
3926 pseudo1.SetMass( theAtomicMass*CLHEP::MeV );
3927 pseudo1.SetTotalEnergy( theAtomicMass*CLHEP::MeV );
3928 G4ReactionProduct pseudo2 = currentParticle + pseudo1;
3929 pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
3930 //
3931 // use phase space routine in centre of mass system
3932 //
3933 G4FastVector<G4ReactionProduct,MYGHADLISTSIZE> tempV;
3934 tempV.Initialize( nt );
3935 G4int tempLen = 0;
3936 tempV.SetElement( tempLen++, v[0] );
3937 tempV.SetElement( tempLen++, v[1] );
3938 if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
3939 G4bool constantCrossSection = true;
3940 GenerateNBodyEvent( pseudo2.GetMass()/CLHEP::MeV, constantCrossSection, tempV, tempLen );
3941 v[0]->Lorentz( *v[0], pseudo2 );
3942 v[1]->Lorentz( *v[1], pseudo2 );
3943 if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
3944
3945 G4bool particleIsDefined = false;
3946 if( v[0]->GetMass()/CLHEP::MeV - aProtonMass < 0.1 )
3947 {
3948 v[0]->SetDefinition( aProton );
3949 particleIsDefined = true;
3950 }
3951 else if( v[0]->GetMass()/CLHEP::MeV - aNeutronMass < 0.1 )
3952 {
3953 v[0]->SetDefinition( aNeutron );
3954 particleIsDefined = true;
3955 }
3956 else if( v[0]->GetMass()/CLHEP::MeV - aDeuteronMass < 0.1 )
3957 {
3958 v[0]->SetDefinition( aDeuteron );
3959 particleIsDefined = true;
3960 }
3961 else if( v[0]->GetMass()/CLHEP::MeV - aTritonMass < 0.1 )
3962 {
3963 v[0]->SetDefinition( aTriton );
3964 particleIsDefined = true;
3965 }
3966 else if( v[0]->GetMass()/CLHEP::MeV - anAlphaMass < 0.1 )
3967 {
3968 v[0]->SetDefinition( anAlpha );
3969 particleIsDefined = true;
3970 }
3971 currentParticle.SetKineticEnergy(
3972 std::max( 0.001, currentParticle.GetKineticEnergy()/CLHEP::MeV ) );
3973 p = currentParticle.GetTotalMomentum();
3974 pp = currentParticle.GetMomentum().mag();
3975 if( pp <= 0.001*CLHEP::MeV )
3976 {
3977 G4double phinve = CLHEP::twopi*G4UniformRand();
3978 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3979 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3980 p*std::sin(rthnve)*std::sin(phinve),
3981 p*std::cos(rthnve) );
3982 }
3983 else
3984 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3985
3986 if( particleIsDefined )
3987 {
3988 v[0]->SetKineticEnergy(
3989 std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/CLHEP::MeV ) );
3990 p = v[0]->GetTotalMomentum();
3991 pp = v[0]->GetMomentum().mag();
3992 if( pp <= 0.001*CLHEP::MeV )
3993 {
3994 G4double phinve = CLHEP::twopi*G4UniformRand();
3995 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
3996 v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3997 p*std::sin(rthnve)*std::sin(phinve),
3998 p*std::cos(rthnve) );
3999 }
4000 else
4001 v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
4002 }
4003 if( (v[1]->GetDefinition() == aDeuteron) ||
4004 (v[1]->GetDefinition() == aTriton) ||
4005 (v[1]->GetDefinition() == anAlpha) )
4006 v[1]->SetKineticEnergy(
4007 std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/CLHEP::MeV ) );
4008 else
4009 v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/CLHEP::MeV ) );
4010
4011 p = v[1]->GetTotalMomentum();
4012 pp = v[1]->GetMomentum().mag();
4013 if( pp <= 0.001*CLHEP::MeV )
4014 {
4015 G4double phinve = CLHEP::twopi*G4UniformRand();
4016 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4017 v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4018 p*std::sin(rthnve)*std::sin(phinve),
4019 p*std::cos(rthnve) );
4020 }
4021 else
4022 v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
4023
4024 if( nt == 3 )
4025 {
4026 if( (v[2]->GetDefinition() == aDeuteron) ||
4027 (v[2]->GetDefinition() == aTriton) ||
4028 (v[2]->GetDefinition() == anAlpha) )
4029 v[2]->SetKineticEnergy(
4030 std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/CLHEP::MeV ) );
4031 else
4032 v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/CLHEP::MeV ) );
4033
4034 p = v[2]->GetTotalMomentum();
4035 pp = v[2]->GetMomentum().mag();
4036 if( pp <= 0.001*CLHEP::MeV )
4037 {
4038 G4double phinve = CLHEP::twopi*G4UniformRand();
4039 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4040 v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4041 p*std::sin(rthnve)*std::sin(phinve),
4042 p*std::cos(rthnve) );
4043 }
4044 else
4045 v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
4046 }
4047 G4int del;
4048 for(del=0; del<vecLen; del++) delete vec[del];
4049 vecLen = 0;
4050 if( particleIsDefined )
4051 {
4052 vec.SetElement( vecLen++, v[0] );
4053 }
4054 else
4055 {
4056 delete v[0];
4057 }
4058 vec.SetElement( vecLen++, v[1] );
4059 if( nt == 3 )
4060 {
4061 vec.SetElement( vecLen++, v[2] );
4062 }
4063 else
4064 {
4065 delete v[2];
4066 }
4067 delete [] v;
4068 return;
4069}
4070
4071/* end of file */
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.
Definition index.py:1
hold the test vectors and ease the comparison
Extra patterns decribing particle interation process.