source: trunk/source/processes/hadronic/util/src/G4ReactionDynamics.cc@ 1199

Last change on this file since 1199 was 962, checked in by garnier, 17 years ago

update processes

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