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

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

import all except CVS

File size: 154.0 KB
Line 
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 );
554 x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
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 );
738 x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
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 );
806 x = std::min( 1.0, pt*(binl[l-1] + G4UniformRand()*(binl[l]-binl[l-1])/2.) );
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
919
920// if( eliminateThisParticle ) // not enough energy, eliminate target
921// {
922// G4cerr << "Warning: eliminating target particle" << G4endl;
923// exit( EXIT_FAILURE );
924// }
925 }
926 //
927 // Target particle finished.
928 //
929 // Now produce backward nucleons with a cluster model
930 //
931 pseudoParticle[6].Lorentz( pseudoParticle[3], pseudoParticle[2] );
932 pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[4];
933 pseudoParticle[6] = pseudoParticle[6] - pseudoParticle[5];
934 if( backwardNucleonCount == 1 ) // target particle is the only backward nucleon
935 {
936 G4double ekin =
937 std::min( backwardEnergy-backwardKinetic, centerofmassEnergy/2.0-protonMass/GeV );
938
939 if( ekin < 0.04 )ekin = 0.04 * std::fabs( normal() );
940 vecMass = targetParticle.GetMass()/GeV;
941 totalEnergy = ekin+vecMass;
942 targetParticle.SetTotalEnergy( totalEnergy*GeV );
943 pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
944 pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
945 if( pp1 < 1.0e-6*GeV )
946 {
947 G4double costheta = 2.*G4UniformRand() - 1.;
948 G4double sintheta = std::sqrt(1. - costheta*costheta);
949 G4double phi = twopi*G4UniformRand();
950 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
951 pp*sintheta*std::sin(phi)*MeV,
952 pp*costheta*MeV ) ;
953 } else {
954 targetParticle.SetMomentum( pseudoParticle[6].GetMomentum() * (pp/pp1) );
955 }
956 pseudoParticle[5] = pseudoParticle[5] + targetParticle;
957 }
958 else // more than one backward nucleon
959 {
960 const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
961 const G4double gpar[] = { 2.6, 2.6, 1.80, 1.30, 1.20 };
962 // Replaced the following min function to get correct behaviour on DEC.
963 // G4int tempCount = std::min( 5, backwardNucleonCount ) - 1;
964 G4int tempCount;
965 if (backwardNucleonCount < 5)
966 {
967 tempCount = backwardNucleonCount;
968 }
969 else
970 {
971 tempCount = 5;
972 }
973 tempCount--;
974 //cout << "backwardNucleonCount " << backwardNucleonCount << G4endl;
975 //cout << "tempCount " << tempCount << G4endl;
976 G4double rmb0 = 0.0;
977 if( targetParticle.GetSide() == -3 )
978 rmb0 += targetParticle.GetMass()/GeV;
979 for( i=0; i<vecLen; ++i )
980 {
981 if( vec[i]->GetSide() == -3 )rmb0 += vec[i]->GetMass()/GeV;
982 }
983 rmb = rmb0 + std::pow(-std::log(1.0-G4UniformRand()),cpar[tempCount]) / gpar[tempCount];
984 totalEnergy = pseudoParticle[6].GetTotalEnergy()/GeV;
985 vecMass = std::min( rmb, totalEnergy );
986 pseudoParticle[6].SetMass( vecMass*GeV );
987 pp = std::sqrt( std::abs( totalEnergy*totalEnergy - vecMass*vecMass ) )*GeV;
988 pp1 = pseudoParticle[6].GetMomentum().mag()/MeV;
989 if( pp1 < 1.0e-6*GeV )
990 {
991 G4double costheta = 2.*G4UniformRand() - 1.;
992 G4double sintheta = std::sqrt(1. - costheta*costheta);
993 G4double phi = twopi*G4UniformRand();
994 pseudoParticle[6].SetMomentum( -pp*sintheta*std::cos(phi)*MeV,
995 -pp*sintheta*std::sin(phi)*MeV,
996 -pp*costheta*MeV ) ;
997 }
998 else
999 pseudoParticle[6].SetMomentum( pseudoParticle[6].GetMomentum() * (-pp/pp1) );
1000
1001 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV; // tempV contains the backward nucleons
1002 tempV.Initialize( backwardNucleonCount );
1003 G4int tempLen = 0;
1004 if( targetParticle.GetSide() == -3 )tempV.SetElement( tempLen++, &targetParticle );
1005 for( i=0; i<vecLen; ++i )
1006 {
1007 if( vec[i]->GetSide() == -3 )tempV.SetElement( tempLen++, vec[i] );
1008 }
1009 if( tempLen != backwardNucleonCount )
1010 {
1011 G4cerr << "tempLen is not the same as backwardNucleonCount" << G4endl;
1012 G4cerr << "tempLen = " << tempLen;
1013 G4cerr << ", backwardNucleonCount = " << backwardNucleonCount << G4endl;
1014 G4cerr << "targetParticle side = " << targetParticle.GetSide() << G4endl;
1015 G4cerr << "currentParticle side = " << currentParticle.GetSide() << G4endl;
1016 for( i=0; i<vecLen; ++i )
1017 G4cerr << "particle #" << i << " side = " << vec[i]->GetSide() << G4endl;
1018 exit( EXIT_FAILURE );
1019 }
1020 constantCrossSection = true;
1021 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1022 if( tempLen >= 2 )
1023 {
1024 wgt = GenerateNBodyEvent(
1025 pseudoParticle[6].GetMass(), constantCrossSection, tempV, tempLen );
1026 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1027 if( targetParticle.GetSide() == -3 )
1028 {
1029 targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1030 // tempV contains the real stuff
1031 pseudoParticle[5] = pseudoParticle[5] + targetParticle;
1032 }
1033 for( i=0; i<vecLen; ++i )
1034 {
1035 if( vec[i]->GetSide() == -3 )
1036 {
1037 vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1038 pseudoParticle[5] = pseudoParticle[5] + (*vec[i]);
1039 }
1040 }
1041 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1042 }
1043 }
1044 //
1045 // Lorentz transformation in lab system
1046 //
1047 if( vecLen == 0 )return false; // all the secondaries have been eliminated
1048 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1049
1050 currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
1051 targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
1052 for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[1] );
1053
1054 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1055 //
1056 // leadFlag will be true
1057 // iff original particle is at least as heavy as K+ and not a proton or
1058 // neutron AND if incident particle is at least as heavy as K+ and it is
1059 // not a proton or neutron leadFlag is set to the incident particle
1060 // or
1061 // target particle is at least as heavy as K+ and it is not a proton or
1062 // neutron leadFlag is set to the target particle
1063 //
1064 G4bool leadingStrangeParticleHasChanged = true;
1065 if( leadFlag )
1066 {
1067 if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1068 leadingStrangeParticleHasChanged = false;
1069 if( leadingStrangeParticleHasChanged &&
1070 ( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() ) )
1071 leadingStrangeParticleHasChanged = false;
1072 if( leadingStrangeParticleHasChanged )
1073 {
1074 for( i=0; i<vecLen; i++ )
1075 {
1076 if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1077 {
1078 leadingStrangeParticleHasChanged = false;
1079 break;
1080 }
1081 }
1082 }
1083 if( leadingStrangeParticleHasChanged )
1084 {
1085 G4bool leadTest =
1086 (leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1087 leadingStrangeParticle.GetDefinition()->GetParticleSubType() == "pi");
1088 G4bool targetTest =
1089 (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
1090 targetParticle.GetDefinition()->GetParticleSubType() == "pi");
1091
1092 // following modified by JLC 22-Oct-97
1093
1094 if( (leadTest&&targetTest) || !(leadTest||targetTest) ) // both true or both false
1095 {
1096 targetParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1097 targetHasChanged = true;
1098 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1099 }
1100 else
1101 {
1102 currentParticle.SetDefinitionAndUpdateE( leadingStrangeParticle.GetDefinition() );
1103 incidentHasChanged = false;
1104 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1105 }
1106 }
1107 } // end of if( leadFlag )
1108
1109 // Get number of final state nucleons and nucleons remaining in
1110 // target nucleus
1111
1112 std::pair<G4int, G4int> finalStateNucleons =
1113 GetFinalStateNucleons(originalTarget, vec, vecLen);
1114
1115 G4int protonsInFinalState = finalStateNucleons.first;
1116 G4int neutronsInFinalState = finalStateNucleons.second;
1117
1118 G4int numberofFinalStateNucleons =
1119 protonsInFinalState + neutronsInFinalState;
1120
1121 if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1122 targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
1123 originalIncident->GetDefinition()->GetPDGMass() <
1124 G4Lambda::Lambda()->GetPDGMass())
1125 numberofFinalStateNucleons++;
1126
1127 numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
1128
1129 G4int PinNucleus = std::max(0,
1130 G4int(targetNucleus.GetZ()) - protonsInFinalState);
1131 G4int NinNucleus = std::max(0,
1132 G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
1133
1134 pseudoParticle[3].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1135 pseudoParticle[3].SetMass( mOriginal*GeV );
1136 pseudoParticle[3].SetTotalEnergy(
1137 std::sqrt( pOriginal*pOriginal + mOriginal*mOriginal )*GeV );
1138
1139 G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
1140 G4int diff = 0;
1141 if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() ) diff = 1;
1142 if(numberofFinalStateNucleons == 1) diff = 0;
1143 pseudoParticle[4].SetMomentum( 0.0, 0.0, 0.0 );
1144 pseudoParticle[4].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1145 pseudoParticle[4].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV );
1146
1147 G4double theoreticalKinetic =
1148 pseudoParticle[3].GetTotalEnergy()/MeV +
1149 pseudoParticle[4].GetTotalEnergy()/MeV -
1150 currentParticle.GetMass()/MeV -
1151 targetParticle.GetMass()/MeV;
1152
1153 G4double simulatedKinetic =
1154 currentParticle.GetKineticEnergy()/MeV + targetParticle.GetKineticEnergy()/MeV;
1155
1156 pseudoParticle[5] = pseudoParticle[3] + pseudoParticle[4];
1157 pseudoParticle[3].Lorentz( pseudoParticle[3], pseudoParticle[5] );
1158 pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[5] );
1159
1160 pseudoParticle[7].SetZero();
1161 pseudoParticle[7] = pseudoParticle[7] + currentParticle;
1162 pseudoParticle[7] = pseudoParticle[7] + targetParticle;
1163
1164 for( i=0; i<vecLen; ++i )
1165 {
1166 pseudoParticle[7] = pseudoParticle[7] + *vec[i];
1167 simulatedKinetic += vec[i]->GetKineticEnergy()/MeV;
1168 theoreticalKinetic -= vec[i]->GetMass()/MeV;
1169 }
1170
1171 if( vecLen <= 16 && vecLen > 0 )
1172 {
1173 // must create a new set of ReactionProducts here because GenerateNBody will
1174 // modify the momenta for the particles, and we don't want to do this
1175 //
1176 G4ReactionProduct tempR[130];
1177 tempR[0] = currentParticle;
1178 tempR[1] = targetParticle;
1179 for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
1180 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1181 tempV.Initialize( vecLen+2 );
1182 G4int tempLen = 0;
1183 for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
1184 constantCrossSection = true;
1185
1186 wgt = GenerateNBodyEvent( pseudoParticle[3].GetTotalEnergy()/MeV+
1187 pseudoParticle[4].GetTotalEnergy()/MeV,
1188 constantCrossSection, tempV, tempLen );
1189 if (wgt == -1) {
1190 G4double Qvalue = 0;
1191 for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
1192 wgt = GenerateNBodyEvent( Qvalue/MeV,
1193 constantCrossSection, tempV, tempLen );
1194 }
1195 if(wgt>-.5)
1196 {
1197 theoreticalKinetic = 0.0;
1198 for( i=0; i<tempLen; ++i )
1199 {
1200 pseudoParticle[6].Lorentz( *tempV[i], pseudoParticle[4] );
1201 theoreticalKinetic += pseudoParticle[6].GetKineticEnergy()/MeV;
1202 }
1203 }
1204 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1205 }
1206 //
1207 // Make sure, that the kinetic energies are correct
1208 //
1209 if( simulatedKinetic != 0.0 )
1210 {
1211 wgt = (theoreticalKinetic)/simulatedKinetic;
1212 theoreticalKinetic = currentParticle.GetKineticEnergy()/MeV * wgt;
1213 simulatedKinetic = theoreticalKinetic;
1214 currentParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1215 pp = currentParticle.GetTotalMomentum()/MeV;
1216 pp1 = currentParticle.GetMomentum().mag()/MeV;
1217 if( pp1 < 1.0e-6*GeV )
1218 {
1219 G4double costheta = 2.*G4UniformRand() - 1.;
1220 G4double sintheta = std::sqrt(1. - costheta*costheta);
1221 G4double phi = twopi*G4UniformRand();
1222 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1223 pp*sintheta*std::sin(phi)*MeV,
1224 pp*costheta*MeV ) ;
1225 }
1226 else
1227 {
1228 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
1229 }
1230 theoreticalKinetic = targetParticle.GetKineticEnergy()/MeV * wgt;
1231 targetParticle.SetKineticEnergy( theoreticalKinetic*MeV );
1232 simulatedKinetic += theoreticalKinetic;
1233 pp = targetParticle.GetTotalMomentum()/MeV;
1234 pp1 = targetParticle.GetMomentum().mag()/MeV;
1235 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1236 if( pp1 < 1.0e-6*GeV )
1237 {
1238 G4double costheta = 2.*G4UniformRand() - 1.;
1239 G4double sintheta = std::sqrt(1. - costheta*costheta);
1240 G4double phi = twopi*G4UniformRand();
1241 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1242 pp*sintheta*std::sin(phi)*MeV,
1243 pp*costheta*MeV ) ;
1244 } else {
1245 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1246 }
1247 for( i=0; i<vecLen; ++i )
1248 {
1249 theoreticalKinetic = vec[i]->GetKineticEnergy()/MeV * wgt;
1250 simulatedKinetic += theoreticalKinetic;
1251 vec[i]->SetKineticEnergy( theoreticalKinetic*MeV );
1252 pp = vec[i]->GetTotalMomentum()/MeV;
1253 pp1 = vec[i]->GetMomentum().mag()/MeV;
1254 if( pp1 < 1.0e-6*GeV )
1255 {
1256 G4double costheta = 2.*G4UniformRand() - 1.;
1257 G4double sintheta = std::sqrt(1. - costheta*costheta);
1258 G4double phi = twopi*G4UniformRand();
1259 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1260 pp*sintheta*std::sin(phi)*MeV,
1261 pp*costheta*MeV ) ;
1262 }
1263 else
1264 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
1265 }
1266 }
1267 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1268
1269 Rotate( numberofFinalStateNucleons, pseudoParticle[3].GetMomentum(),
1270 modifiedOriginal, originalIncident, targetNucleus,
1271 currentParticle, targetParticle, vec, vecLen );
1272 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1273 //
1274 // add black track particles
1275 // the total number of particles produced is restricted to 198
1276 // this may have influence on very high energies
1277 //
1278 if( atomicWeight >= 1.5 )
1279 {
1280 // npnb is number of proton/neutron black track particles
1281 // ndta is the number of deuterons, tritons, and alphas produced
1282 // epnb is the kinetic energy available for proton/neutron black track particles
1283 // edta is the kinetic energy available for deuteron/triton/alpha particles
1284 //
1285 G4int npnb = 0;
1286 G4int ndta = 0;
1287
1288 G4double epnb, edta;
1289 if (veryForward) {
1290 epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
1291 edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
1292 } else {
1293 epnb = targetNucleus.GetPNBlackTrackEnergy();
1294 edta = targetNucleus.GetDTABlackTrackEnergy();
1295 }
1296
1297 const G4double pnCutOff = 0.001;
1298 const G4double dtaCutOff = 0.001;
1299 const G4double kineticMinimum = 1.e-6;
1300 const G4double kineticFactor = -0.010;
1301 G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
1302 const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
1303 if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
1304 if( epnb >= pnCutOff )
1305 {
1306 npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
1307 if( numberofFinalStateNucleons + npnb > atomicWeight )
1308 npnb = G4int(atomicWeight+0.00001 - numberofFinalStateNucleons);
1309 npnb = std::min( npnb, 127-vecLen );
1310 }
1311 if( edta >= dtaCutOff )
1312 {
1313 ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
1314 ndta = std::min( ndta, 127-vecLen );
1315 }
1316 if (npnb == 0 && ndta == 0) npnb = 1;
1317
1318 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1319
1320 AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum,
1321 kineticFactor, modifiedOriginal,
1322 PinNucleus, NinNucleus, targetNucleus,
1323 vec, vecLen);
1324
1325 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1326 }
1327 //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
1328 // MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
1329 //
1330 // calculate time delay for nuclear reactions
1331 //
1332 if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
1333 currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
1334 else
1335 currentParticle.SetTOF( 1.0 );
1336 return true;
1337 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1338 }
1339
1340 void G4ReactionDynamics::SuppressChargedPions(
1341 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1342 G4int &vecLen,
1343 const G4ReactionProduct &modifiedOriginal,
1344 G4ReactionProduct &currentParticle,
1345 G4ReactionProduct &targetParticle,
1346 const G4Nucleus &targetNucleus,
1347 G4bool &incidentHasChanged,
1348 G4bool &targetHasChanged )
1349 {
1350 // this code was originally in the fortran code TWOCLU
1351 //
1352 // suppress charged pions, for various reasons
1353 //
1354 G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1355 G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1356 G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1357 G4double cmEnergy = std::sqrt( mOriginal*mOriginal + targetMass*targetMass +
1358 2.0*targetMass*etOriginal );
1359 G4double eAvailable = cmEnergy - mOriginal - targetMass;
1360 for (G4int i = 0; i < vecLen; i++) eAvailable -= vec[i]->GetMass()/GeV;
1361
1362 const G4double atomicWeight = targetNucleus.GetN();
1363 const G4double atomicNumber = targetNucleus.GetZ();
1364 const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/GeV;
1365
1366 G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1367 G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1368 G4ParticleDefinition* aPiZero = G4PionZero::PionZero();
1369 G4ParticleDefinition *aProton = G4Proton::Proton();
1370 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1371 G4double piMass = aPiPlus->GetPDGMass()/GeV;
1372 G4double nucleonMass = aNeutron->GetPDGMass()/GeV;
1373
1374 const G4bool antiTest =
1375 modifiedOriginal.GetDefinition() != G4AntiProton::AntiProton() &&
1376 modifiedOriginal.GetDefinition() != G4AntiNeutron::AntiNeutron() &&
1377 modifiedOriginal.GetDefinition() != G4AntiLambda::AntiLambda() &&
1378 modifiedOriginal.GetDefinition() != G4AntiSigmaPlus::AntiSigmaPlus() &&
1379 modifiedOriginal.GetDefinition() != G4AntiSigmaMinus::AntiSigmaMinus() &&
1380 modifiedOriginal.GetDefinition() != G4AntiXiZero::AntiXiZero() &&
1381 modifiedOriginal.GetDefinition() != G4AntiXiMinus::AntiXiMinus() &&
1382 modifiedOriginal.GetDefinition() != G4AntiOmegaMinus::AntiOmegaMinus();
1383
1384 if( antiTest && (
1385 currentParticle.GetDefinition() == aPiPlus ||
1386 currentParticle.GetDefinition() == aPiZero ||
1387 currentParticle.GetDefinition() == aPiMinus ) &&
1388 ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1389 ( G4UniformRand() <= atomicWeight/300.0 ) )
1390 {
1391 if (eAvailable > nucleonMass - piMass) {
1392 if( G4UniformRand() > atomicNumber/atomicWeight )
1393 currentParticle.SetDefinitionAndUpdateE( aNeutron );
1394 else
1395 currentParticle.SetDefinitionAndUpdateE( aProton );
1396 incidentHasChanged = true;
1397 }
1398 }
1399 if( antiTest && (
1400 targetParticle.GetDefinition() == aPiPlus ||
1401 targetParticle.GetDefinition() == aPiZero ||
1402 targetParticle.GetDefinition() == aPiMinus ) &&
1403 ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1404 ( G4UniformRand() <= atomicWeight/300.0 ) )
1405 {
1406 if (eAvailable > nucleonMass - piMass) {
1407 if( G4UniformRand() > atomicNumber/atomicWeight )
1408 targetParticle.SetDefinitionAndUpdateE( aNeutron );
1409 else
1410 targetParticle.SetDefinitionAndUpdateE( aProton );
1411 targetHasChanged = true;
1412 }
1413 }
1414 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1415 for( G4int i=0; i<vecLen; ++i )
1416 {
1417 if( antiTest && (
1418 vec[i]->GetDefinition() == aPiPlus ||
1419 vec[i]->GetDefinition() == aPiZero ||
1420 vec[i]->GetDefinition() == aPiMinus ) &&
1421 ( G4UniformRand() <= (10.0-pOriginal)/6.0 ) &&
1422 ( G4UniformRand() <= atomicWeight/300.0 ) )
1423 {
1424 if (eAvailable > nucleonMass - piMass) {
1425 if( G4UniformRand() > atomicNumber/atomicWeight )
1426 vec[i]->SetDefinitionAndUpdateE( aNeutron );
1427 else
1428 vec[i]->SetDefinitionAndUpdateE( aProton );
1429 }
1430 }
1431 }
1432 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1433 }
1434
1435 G4bool G4ReactionDynamics::TwoCluster(
1436 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
1437 G4int &vecLen,
1438 G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effects included
1439 const G4HadProjectile *originalIncident, // the original incident particle
1440 G4ReactionProduct &currentParticle,
1441 G4ReactionProduct &targetParticle,
1442 const G4DynamicParticle* originalTarget,
1443 const G4Nucleus &targetNucleus,
1444 G4bool &incidentHasChanged,
1445 G4bool &targetHasChanged,
1446 G4bool leadFlag,
1447 G4ReactionProduct &leadingStrangeParticle )
1448 {
1449 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1450 // derived from original FORTRAN code TWOCLU by H. Fesefeldt (11-Oct-1987)
1451 //
1452 // Generation of X- and PT- values for incident, target, and all secondary particles
1453 //
1454 // A simple two cluster model is used.
1455 // This should be sufficient for low energy interactions.
1456 //
1457
1458 // + debugging
1459 // raise(SIGSEGV);
1460 // - debugging
1461
1462 G4int i;
1463 G4ParticleDefinition *aProton = G4Proton::Proton();
1464 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
1465 G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
1466 G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
1467 G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
1468 G4bool veryForward = false;
1469
1470 const G4double protonMass = aProton->GetPDGMass()/MeV;
1471 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
1472 const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
1473 const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
1474 const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
1475 G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
1476 G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
1477 targetMass*targetMass +
1478 2.0*targetMass*etOriginal ); // GeV
1479 G4double currentMass = currentParticle.GetMass()/GeV;
1480 targetMass = targetParticle.GetMass()/GeV;
1481
1482 if( currentMass == 0.0 && targetMass == 0.0 )
1483 {
1484 G4double ek = currentParticle.GetKineticEnergy();
1485 G4ThreeVector m = currentParticle.GetMomentum();
1486 currentParticle = *vec[0];
1487 targetParticle = *vec[1];
1488 for( i=0; i<(vecLen-2); ++i )*vec[i] = *vec[i+2];
1489 if(vecLen<2)
1490 {
1491 for(G4int i=0; i<vecLen; i++) delete vec[i];
1492 vecLen = 0;
1493 throw G4HadReentrentException(__FILE__, __LINE__,
1494 "G4ReactionDynamics::TwoCluster: Negative number of particles");
1495 }
1496 delete vec[vecLen-1];
1497 delete vec[vecLen-2];
1498 vecLen -= 2;
1499 currentMass = currentParticle.GetMass()/GeV;
1500 targetMass = targetParticle.GetMass()/GeV;
1501 incidentHasChanged = true;
1502 targetHasChanged = true;
1503 currentParticle.SetKineticEnergy( ek );
1504 currentParticle.SetMomentum( m );
1505 veryForward = true;
1506 }
1507
1508 const G4double atomicWeight = targetNucleus.GetN();
1509 const G4double atomicNumber = targetNucleus.GetZ();
1510 //
1511 // particles have been distributed in forward and backward hemispheres
1512 // in center of mass system of the hadron nucleon interaction
1513 //
1514 // incident is always in forward hemisphere
1515 G4int forwardCount = 1; // number of particles in forward hemisphere
1516 currentParticle.SetSide( 1 );
1517 G4double forwardMass = currentParticle.GetMass()/GeV;
1518 G4double cMass = forwardMass;
1519
1520 // target is always in backward hemisphere
1521 G4int backwardCount = 1; // number of particles in backward hemisphere
1522 G4int backwardNucleonCount = 1; // number of nucleons in backward hemisphere
1523 targetParticle.SetSide( -1 );
1524 G4double backwardMass = targetParticle.GetMass()/GeV;
1525 G4double bMass = backwardMass;
1526
1527 for( i=0; i<vecLen; ++i )
1528 {
1529 if( vec[i]->GetSide() < 0 )vec[i]->SetSide( -1 ); // added by JLC, 2Jul97
1530 // to take care of the case where vec has been preprocessed by GenerateXandPt
1531 // and some of them have been set to -2 or -3
1532 if( vec[i]->GetSide() == -1 )
1533 {
1534 ++backwardCount;
1535 backwardMass += vec[i]->GetMass()/GeV;
1536 }
1537 else
1538 {
1539 ++forwardCount;
1540 forwardMass += vec[i]->GetMass()/GeV;
1541 }
1542 }
1543 //
1544 // nucleons and some pions from intranuclear cascade
1545 //
1546 G4double term1 = std::log(centerofmassEnergy*centerofmassEnergy);
1547 if(term1 < 0) term1 = 0.0001; // making sure xtarg<0;
1548 const G4double afc = 0.312 + 0.2 * std::log(term1);
1549 G4double xtarg;
1550 if( centerofmassEnergy < 2.0+G4UniformRand() ) // added +2 below, JLC 4Jul97
1551 xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount+vecLen+2)/2.0;
1552 else
1553 xtarg = afc * (std::pow(atomicWeight,0.33)-1.0) * (2*backwardCount);
1554 if( xtarg <= 0.0 )xtarg = 0.01;
1555 G4int nuclearExcitationCount = Poisson( xtarg );
1556 if(atomicWeight<1.0001) nuclearExcitationCount = 0;
1557 G4int extraNucleonCount = 0;
1558 G4double extraMass = 0.0;
1559 G4double extraNucleonMass = 0.0;
1560 if( nuclearExcitationCount > 0 )
1561 {
1562 G4int momentumBin = std::min( 4, G4int(pOriginal/3.0) );
1563 const G4double nucsup[] = { 1.0, 0.8, 0.6, 0.5, 0.4 };
1564 //
1565 // NOTE: in TWOCLU, these new particles were given negative codes
1566 // here we use NewlyAdded = true instead
1567 //
1568// G4ReactionProduct *pVec = new G4ReactionProduct [nuclearExcitationCount];
1569 for( i=0; i<nuclearExcitationCount; ++i )
1570 {
1571 G4ReactionProduct* pVec = new G4ReactionProduct();
1572 if( G4UniformRand() < nucsup[momentumBin] ) // add proton or neutron
1573 {
1574 if( G4UniformRand() > 1.0-atomicNumber/atomicWeight )
1575 pVec->SetDefinition( aProton );
1576 else
1577 pVec->SetDefinition( aNeutron );
1578 ++backwardNucleonCount;
1579 ++extraNucleonCount;
1580 extraNucleonMass += pVec->GetMass()/GeV;
1581 }
1582 else
1583 { // add a pion
1584 G4double ran = G4UniformRand();
1585 if( ran < 0.3181 )
1586 pVec->SetDefinition( aPiPlus );
1587 else if( ran < 0.6819 )
1588 pVec->SetDefinition( aPiZero );
1589 else
1590 pVec->SetDefinition( aPiMinus );
1591 }
1592 pVec->SetSide( -2 ); // backside particle
1593 extraMass += pVec->GetMass()/GeV;
1594 pVec->SetNewlyAdded( true );
1595 vec.SetElement( vecLen++, pVec );
1596 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1597 }
1598 }
1599 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1600 G4double forwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +cMass - forwardMass;
1601 G4double backwardEnergy = (centerofmassEnergy-cMass-bMass)/2.0 +bMass - backwardMass;
1602 G4double eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1603 G4bool secondaryDeleted;
1604 G4double pMass;
1605
1606 while( eAvailable <= 0.0 ) // must eliminate a particle
1607 {
1608 secondaryDeleted = false;
1609 for( i=(vecLen-1); i>=0; --i )
1610 {
1611 if( vec[i]->GetSide() == 1 && vec[i]->GetMayBeKilled())
1612 {
1613 pMass = vec[i]->GetMass()/GeV;
1614 for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1615 --forwardCount;
1616 forwardEnergy += pMass;
1617 forwardMass -= pMass;
1618 secondaryDeleted = true;
1619 break;
1620 }
1621 else if( vec[i]->GetSide() == -1 && vec[i]->GetMayBeKilled())
1622 {
1623 pMass = vec[i]->GetMass()/GeV;
1624 for( G4int j=i; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1625 --backwardCount;
1626 backwardEnergy += pMass;
1627 backwardMass -= pMass;
1628 secondaryDeleted = true;
1629 break;
1630 }
1631 } // breaks go down to here
1632 if( secondaryDeleted )
1633 {
1634 delete vec[vecLen-1];
1635 --vecLen;
1636 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1637 }
1638 else
1639 {
1640 if( vecLen == 0 )
1641 {
1642 return false; // all secondaries have been eliminated
1643 }
1644 if( targetParticle.GetSide() == -1 )
1645 {
1646 pMass = targetParticle.GetMass()/GeV;
1647 targetParticle = *vec[0];
1648 for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1649 --backwardCount;
1650 backwardEnergy += pMass;
1651 backwardMass -= pMass;
1652 secondaryDeleted = true;
1653 }
1654 else if( targetParticle.GetSide() == 1 )
1655 {
1656 pMass = targetParticle.GetMass()/GeV;
1657 targetParticle = *vec[0];
1658 for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1659 --forwardCount;
1660 forwardEnergy += pMass;
1661 forwardMass -= pMass;
1662 secondaryDeleted = true;
1663 }
1664 if( secondaryDeleted )
1665 {
1666 delete vec[vecLen-1];
1667 --vecLen;
1668 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1669 }
1670 else
1671 {
1672 if( currentParticle.GetSide() == -1 )
1673 {
1674 pMass = currentParticle.GetMass()/GeV;
1675 currentParticle = *vec[0];
1676 for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1677 --backwardCount;
1678 backwardEnergy += pMass;
1679 backwardMass -= pMass;
1680 secondaryDeleted = true;
1681 }
1682 else if( currentParticle.GetSide() == 1 )
1683 {
1684 pMass = currentParticle.GetMass()/GeV;
1685 currentParticle = *vec[0];
1686 for( G4int j=0; j<(vecLen-1); ++j )*vec[j] = *vec[j+1]; // shift up
1687 --forwardCount;
1688 forwardEnergy += pMass;
1689 forwardMass -= pMass;
1690 secondaryDeleted = true;
1691 }
1692 if( secondaryDeleted )
1693 {
1694 delete vec[vecLen-1];
1695 --vecLen;
1696 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1697 }
1698 else break;
1699 }
1700 }
1701 eAvailable = centerofmassEnergy - (forwardMass+backwardMass);
1702 }
1703 //
1704 // This is the start of the TwoCluster function
1705 // Choose masses for the 3 clusters:
1706 // forward cluster
1707 // backward meson cluster
1708 // backward nucleon cluster
1709 //
1710 G4double rmc = 0.0, rmd = 0.0;
1711 const G4double cpar[] = { 0.6, 0.6, 0.35, 0.15, 0.10 };
1712 const G4double gpar[] = { 2.6, 2.6, 1.8, 1.30, 1.20 };
1713
1714 if (forwardCount <= 0 || backwardCount <= 0) return false; // array bounds protection
1715
1716 if (forwardCount == 1) rmc = forwardMass;
1717 else
1718 {
1719 G4int ntc = std::max(1, std::min(5,forwardCount))-1; // check if offset by 1 @@
1720 rmc = forwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1721 }
1722
1723 if (backwardCount == 1) rmd = backwardMass;
1724 else
1725 {
1726 G4int ntc = std::max(1, std::min(5,backwardCount)); // check, if offfset by 1 @@
1727 rmd = backwardMass + std::pow(-std::log(1.0-G4UniformRand()),cpar[ntc-1])/gpar[ntc-1];
1728 }
1729
1730 while( rmc+rmd > centerofmassEnergy )
1731 {
1732 if( (rmc <= forwardMass) && (rmd <= backwardMass) )
1733 {
1734 G4double temp = 0.999*centerofmassEnergy/(rmc+rmd);
1735 rmc *= temp;
1736 rmd *= temp;
1737 }
1738 else
1739 {
1740 rmc = 0.1*forwardMass + 0.9*rmc;
1741 rmd = 0.1*backwardMass + 0.9*rmd;
1742 }
1743 }
1744
1745 G4ReactionProduct pseudoParticle[8];
1746 for( i=0; i<8; ++i )pseudoParticle[i].SetZero();
1747
1748 pseudoParticle[1].SetMass( mOriginal*GeV );
1749 pseudoParticle[1].SetTotalEnergy( etOriginal*GeV );
1750 pseudoParticle[1].SetMomentum( 0.0, 0.0, pOriginal*GeV );
1751
1752 pseudoParticle[2].SetMass( protonMass*MeV );
1753 pseudoParticle[2].SetTotalEnergy( protonMass*MeV );
1754 pseudoParticle[2].SetMomentum( 0.0, 0.0, 0.0 );
1755 //
1756 // transform into centre of mass system
1757 //
1758 pseudoParticle[0] = pseudoParticle[1] + pseudoParticle[2];
1759 pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[0] );
1760 pseudoParticle[2].Lorentz( pseudoParticle[2], pseudoParticle[0] );
1761
1762 const G4double pfMin = 0.0001;
1763 G4double pf = (centerofmassEnergy*centerofmassEnergy+rmd*rmd-rmc*rmc);
1764 pf *= pf;
1765 pf -= 4*centerofmassEnergy*centerofmassEnergy*rmd*rmd;
1766 pf = std::sqrt( std::max(pf,pfMin) )/(2.0*centerofmassEnergy);
1767 //
1768 // set final state masses and energies in centre of mass system
1769 //
1770 pseudoParticle[3].SetMass( rmc*GeV );
1771 pseudoParticle[3].SetTotalEnergy( std::sqrt(pf*pf+rmc*rmc)*GeV );
1772
1773 pseudoParticle[4].SetMass( rmd*GeV );
1774 pseudoParticle[4].SetTotalEnergy( std::sqrt(pf*pf+rmd*rmd)*GeV );
1775 //
1776 // set |T| and |TMIN|
1777 //
1778 const G4double bMin = 0.01;
1779 const G4double b1 = 4.0;
1780 const G4double b2 = 1.6;
1781
1782 G4double pin = pseudoParticle[1].GetMomentum().mag()/GeV;
1783 G4double dtb = 4.0*pin*pf*std::max( bMin, b1+b2*std::log(pOriginal) );
1784 G4double factor = 1.0 - std::exp(-dtb);
1785 G4double costheta = 1.0 + 2.0*std::log(1.0 - G4UniformRand()*factor) / dtb;
1786 costheta = std::max(-1.0, std::min(1.0, costheta));
1787 G4double sintheta = std::sqrt(1.0-costheta*costheta);
1788 G4double phi = G4UniformRand() * twopi;
1789
1790 //
1791 // calculate final state momenta in centre of mass system
1792 //
1793 pseudoParticle[3].SetMomentum( pf*sintheta*std::cos(phi)*GeV,
1794 pf*sintheta*std::sin(phi)*GeV,
1795 pf*costheta*GeV );
1796
1797 pseudoParticle[4].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1798 //
1799 // simulate backward nucleon cluster in lab. system and transform in cms
1800 //
1801 G4double pp, pp1;
1802 if( nuclearExcitationCount > 0 )
1803 {
1804 const G4double ga = 1.2;
1805 G4double ekit1 = 0.04;
1806 G4double ekit2 = 0.6;
1807 if( ekOriginal <= 5.0 )
1808 {
1809 ekit1 *= ekOriginal*ekOriginal/25.0;
1810 ekit2 *= ekOriginal*ekOriginal/25.0;
1811 }
1812 const G4double a = (1.0-ga)/(std::pow(ekit2,(1.0-ga)) - std::pow(ekit1,(1.0-ga)));
1813 for( i=0; i<vecLen; ++i )
1814 {
1815 if( vec[i]->GetSide() == -2 )
1816 {
1817 G4double kineticE =
1818 std::pow( (G4UniformRand()*(1.0-ga)/a+std::pow(ekit1,(1.0-ga))), (1.0/(1.0-ga)) );
1819 vec[i]->SetKineticEnergy( kineticE*GeV );
1820 G4double vMass = vec[i]->GetMass()/MeV;
1821 G4double totalE = kineticE*GeV + vMass;
1822 pp = std::sqrt( std::abs(totalE*totalE-vMass*vMass) );
1823 G4double cost = std::min( 1.0, std::max( -1.0, std::log(2.23*G4UniformRand()+0.383)/0.96 ) );
1824 G4double sint = std::sqrt( std::max( 0.0, (1.0-cost*cost) ) );
1825 phi = twopi*G4UniformRand();
1826 vec[i]->SetMomentum( pp*sint*std::sin(phi)*MeV,
1827 pp*sint*std::cos(phi)*MeV,
1828 pp*cost*MeV );
1829 vec[i]->Lorentz( *vec[i], pseudoParticle[0] );
1830 }
1831 }
1832 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1833 }
1834 //
1835 // fragmentation of forward cluster and backward meson cluster
1836 //
1837 currentParticle.SetMomentum( pseudoParticle[3].GetMomentum() );
1838 currentParticle.SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1839
1840 targetParticle.SetMomentum( pseudoParticle[4].GetMomentum() );
1841 targetParticle.SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1842
1843 pseudoParticle[5].SetMomentum( pseudoParticle[3].GetMomentum() * (-1.0) );
1844 pseudoParticle[5].SetMass( pseudoParticle[3].GetMass() );
1845 pseudoParticle[5].SetTotalEnergy( pseudoParticle[3].GetTotalEnergy() );
1846
1847 pseudoParticle[6].SetMomentum( pseudoParticle[4].GetMomentum() * (-1.0) );
1848 pseudoParticle[6].SetMass( pseudoParticle[4].GetMass() );
1849 pseudoParticle[6].SetTotalEnergy( pseudoParticle[4].GetTotalEnergy() );
1850
1851 G4double wgt;
1852 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1853 if( forwardCount > 1 ) // tempV will contain the forward particles
1854 {
1855 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1856 tempV.Initialize( forwardCount );
1857 G4bool constantCrossSection = true;
1858 G4int tempLen = 0;
1859 if( currentParticle.GetSide() == 1 )
1860 tempV.SetElement( tempLen++, &currentParticle );
1861 if( targetParticle.GetSide() == 1 )
1862 tempV.SetElement( tempLen++, &targetParticle );
1863 for( i=0; i<vecLen; ++i )
1864 {
1865 if( vec[i]->GetSide() == 1 )
1866 {
1867 if( tempLen < 18 )
1868 tempV.SetElement( tempLen++, vec[i] );
1869 else
1870 {
1871 vec[i]->SetSide( -1 );
1872 continue;
1873 }
1874 }
1875 }
1876 if( tempLen >= 2 )
1877 {
1878 wgt = GenerateNBodyEvent( pseudoParticle[3].GetMass()/MeV,
1879 constantCrossSection, tempV, tempLen );
1880 if( currentParticle.GetSide() == 1 )
1881 currentParticle.Lorentz( currentParticle, pseudoParticle[5] );
1882 if( targetParticle.GetSide() == 1 )
1883 targetParticle.Lorentz( targetParticle, pseudoParticle[5] );
1884 for( i=0; i<vecLen; ++i )
1885 {
1886 if( vec[i]->GetSide() == 1 )vec[i]->Lorentz( *vec[i], pseudoParticle[5] );
1887 }
1888 }
1889 }
1890 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1891 if( backwardCount > 1 ) // tempV will contain the backward particles,
1892 { // but not those created from the intranuclear cascade
1893 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
1894 tempV.Initialize( backwardCount );
1895 G4bool constantCrossSection = true;
1896 G4int tempLen = 0;
1897 if( currentParticle.GetSide() == -1 )
1898 tempV.SetElement( tempLen++, &currentParticle );
1899 if( targetParticle.GetSide() == -1 )
1900 tempV.SetElement( tempLen++, &targetParticle );
1901 for( i=0; i<vecLen; ++i )
1902 {
1903 if( vec[i]->GetSide() == -1 )
1904 {
1905 if( tempLen < 18 )
1906 tempV.SetElement( tempLen++, vec[i] );
1907 else
1908 {
1909 vec[i]->SetSide( -2 );
1910 vec[i]->SetKineticEnergy( 0.0 );
1911 vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
1912 continue;
1913 }
1914 }
1915 }
1916 if( tempLen >= 2 )
1917 {
1918 wgt = GenerateNBodyEvent( pseudoParticle[4].GetMass()/MeV,
1919 constantCrossSection, tempV, tempLen );
1920 if( currentParticle.GetSide() == -1 )
1921 currentParticle.Lorentz( currentParticle, pseudoParticle[6] );
1922 if( targetParticle.GetSide() == -1 )
1923 targetParticle.Lorentz( targetParticle, pseudoParticle[6] );
1924 for( i=0; i<vecLen; ++i )
1925 {
1926 if( vec[i]->GetSide() == -1 )vec[i]->Lorentz( *vec[i], pseudoParticle[6] );
1927 }
1928 }
1929 }
1930 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1931 //
1932 // Lorentz transformation in lab system
1933 //
1934 currentParticle.Lorentz( currentParticle, pseudoParticle[2] );
1935 targetParticle.Lorentz( targetParticle, pseudoParticle[2] );
1936 for( i=0; i<vecLen; ++i ) vec[i]->Lorentz( *vec[i], pseudoParticle[2] );
1937
1938 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
1939 //
1940 // sometimes the leading strange particle is lost, set it back
1941 //
1942 G4bool dum = true;
1943 if( leadFlag )
1944 {
1945 // leadFlag will be true
1946 // iff original particle is at least as heavy as K+ and not a proton or
1947 // neutron AND if incident particle is at least as heavy as K+ and it is
1948 // not a proton or neutron leadFlag is set to the incident particle
1949 // or
1950 // target particle is at least as heavy as K+ and it is not a proton or
1951 // neutron leadFlag is set to the target particle
1952 //
1953 if( currentParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1954 dum = false;
1955 else if( targetParticle.GetDefinition() == leadingStrangeParticle.GetDefinition() )
1956 dum = false;
1957 else
1958 {
1959 for( i=0; i<vecLen; ++i )
1960 {
1961 if( vec[i]->GetDefinition() == leadingStrangeParticle.GetDefinition() )
1962 {
1963 dum = false;
1964 break;
1965 }
1966 }
1967 }
1968 if( dum )
1969 {
1970 G4double leadMass = leadingStrangeParticle.GetMass()/MeV;
1971 G4double ekin;
1972 if( ((leadMass < protonMass) && (targetParticle.GetMass()/MeV < protonMass)) ||
1973 ((leadMass >= protonMass) && (targetParticle.GetMass()/MeV >= protonMass)) )
1974 {
1975 ekin = targetParticle.GetKineticEnergy()/GeV;
1976 pp1 = targetParticle.GetMomentum().mag()/MeV; // old momentum
1977 targetParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1978 targetParticle.SetKineticEnergy( ekin*GeV );
1979 pp = targetParticle.GetTotalMomentum()/MeV; // new momentum
1980 if( pp1 < 1.0e-3 )
1981 {
1982 G4double costheta = 2.*G4UniformRand() - 1.;
1983 G4double sintheta = std::sqrt(1. - costheta*costheta);
1984 G4double phi = twopi*G4UniformRand();
1985 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1986 pp*sintheta*std::sin(phi)*MeV,
1987 pp*costheta*MeV ) ;
1988 }
1989 else
1990 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
1991
1992 targetHasChanged = true;
1993 }
1994 else
1995 {
1996 ekin = currentParticle.GetKineticEnergy()/GeV;
1997 pp1 = currentParticle.GetMomentum().mag()/MeV;
1998 currentParticle.SetDefinition( leadingStrangeParticle.GetDefinition() );
1999 currentParticle.SetKineticEnergy( ekin*GeV );
2000 pp = currentParticle.GetTotalMomentum()/MeV;
2001 if( pp1 < 1.0e-3 )
2002 {
2003 G4double costheta = 2.*G4UniformRand() - 1.;
2004 G4double sintheta = std::sqrt(1. - costheta*costheta);
2005 G4double phi = twopi*G4UniformRand();
2006 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2007 pp*sintheta*std::sin(phi)*MeV,
2008 pp*costheta*MeV ) ;
2009 }
2010 else
2011 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2012
2013 incidentHasChanged = true;
2014 }
2015 }
2016 } // end of if( leadFlag )
2017
2018 // Get number of final state nucleons and nucleons remaining in
2019 // target nucleus
2020
2021 std::pair<G4int, G4int> finalStateNucleons =
2022 GetFinalStateNucleons(originalTarget, vec, vecLen);
2023
2024 G4int protonsInFinalState = finalStateNucleons.first;
2025 G4int neutronsInFinalState = finalStateNucleons.second;
2026
2027 G4int numberofFinalStateNucleons =
2028 protonsInFinalState + neutronsInFinalState;
2029
2030 if (currentParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2031 targetParticle.GetDefinition()->GetBaryonNumber() == 1 &&
2032 originalIncident->GetDefinition()->GetPDGMass() <
2033 G4Lambda::Lambda()->GetPDGMass())
2034 numberofFinalStateNucleons++;
2035
2036 numberofFinalStateNucleons = std::max(1, numberofFinalStateNucleons);
2037
2038 G4int PinNucleus = std::max(0,
2039 G4int(targetNucleus.GetZ()) - protonsInFinalState);
2040 G4int NinNucleus = std::max(0,
2041 G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
2042 //
2043 // for various reasons, the energy balance is not sufficient,
2044 // check that, energy balance, angle of final system, etc.
2045 //
2046 pseudoParticle[4].SetMass( mOriginal*GeV );
2047 pseudoParticle[4].SetTotalEnergy( etOriginal*GeV );
2048 pseudoParticle[4].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2049
2050 G4ParticleDefinition * aOrgDef = modifiedOriginal.GetDefinition();
2051 G4int diff = 0;
2052 if(aOrgDef == G4Proton::Proton() || aOrgDef == G4Neutron::Neutron() ) diff = 1;
2053 if(numberofFinalStateNucleons == 1) diff = 0;
2054 pseudoParticle[5].SetMomentum( 0.0, 0.0, 0.0 );
2055 pseudoParticle[5].SetMass( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2056 pseudoParticle[5].SetTotalEnergy( protonMass*(numberofFinalStateNucleons-diff)*MeV);
2057
2058 G4double theoreticalKinetic =
2059 pseudoParticle[4].GetTotalEnergy()/GeV + pseudoParticle[5].GetTotalEnergy()/GeV;
2060
2061 pseudoParticle[6] = pseudoParticle[4] + pseudoParticle[5];
2062 pseudoParticle[4].Lorentz( pseudoParticle[4], pseudoParticle[6] );
2063 pseudoParticle[5].Lorentz( pseudoParticle[5], pseudoParticle[6] );
2064
2065 if( vecLen < 16 )
2066 {
2067 G4ReactionProduct tempR[130];
2068 tempR[0] = currentParticle;
2069 tempR[1] = targetParticle;
2070 for( i=0; i<vecLen; ++i )tempR[i+2] = *vec[i];
2071
2072 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
2073 tempV.Initialize( vecLen+2 );
2074 G4bool constantCrossSection = true;
2075 G4int tempLen = 0;
2076 for( i=0; i<vecLen+2; ++i )tempV.SetElement( tempLen++, &tempR[i] );
2077
2078 if( tempLen >= 2 )
2079 {
2080 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2081 wgt = GenerateNBodyEvent( pseudoParticle[4].GetTotalEnergy()/MeV +
2082 pseudoParticle[5].GetTotalEnergy()/MeV,
2083 constantCrossSection, tempV, tempLen );
2084 if (wgt == -1) {
2085 G4double Qvalue = 0;
2086 for (i = 0; i < tempLen; i++) Qvalue += tempV[i]->GetMass();
2087 wgt = GenerateNBodyEvent( Qvalue/MeV,
2088 constantCrossSection, tempV, tempLen );
2089 }
2090 theoreticalKinetic = 0.0;
2091 for( i=0; i<vecLen+2; ++i )
2092 {
2093 pseudoParticle[7].SetMomentum( tempV[i]->GetMomentum() );
2094 pseudoParticle[7].SetMass( tempV[i]->GetMass() );
2095 pseudoParticle[7].SetTotalEnergy( tempV[i]->GetTotalEnergy() );
2096 pseudoParticle[7].Lorentz( pseudoParticle[7], pseudoParticle[5] );
2097 theoreticalKinetic += pseudoParticle[7].GetKineticEnergy()/GeV;
2098 }
2099 }
2100 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2101 }
2102 else
2103 {
2104 theoreticalKinetic -=
2105 ( currentParticle.GetMass()/GeV + targetParticle.GetMass()/GeV );
2106 for( i=0; i<vecLen; ++i )theoreticalKinetic -= vec[i]->GetMass()/GeV;
2107 }
2108 G4double simulatedKinetic =
2109 currentParticle.GetKineticEnergy()/GeV + targetParticle.GetKineticEnergy()/GeV;
2110 for( i=0; i<vecLen; ++i )simulatedKinetic += vec[i]->GetKineticEnergy()/GeV;
2111 //
2112 // make sure that kinetic energies are correct
2113 // the backward nucleon cluster is not produced within proper kinematics!!!
2114 //
2115
2116 if( simulatedKinetic != 0.0 )
2117 {
2118 wgt = (theoreticalKinetic)/simulatedKinetic;
2119 currentParticle.SetKineticEnergy( wgt*currentParticle.GetKineticEnergy() );
2120 pp = currentParticle.GetTotalMomentum()/MeV;
2121 pp1 = currentParticle.GetMomentum().mag()/MeV;
2122 if( pp1 < 0.001*MeV )
2123 {
2124 G4double costheta = 2.*G4UniformRand() - 1.;
2125 G4double sintheta = std::sqrt(1. - costheta*costheta);
2126 G4double phi = twopi*G4UniformRand();
2127 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2128 pp*sintheta*std::sin(phi)*MeV,
2129 pp*costheta*MeV ) ;
2130 }
2131 else
2132 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2133
2134 targetParticle.SetKineticEnergy( wgt*targetParticle.GetKineticEnergy() );
2135 pp = targetParticle.GetTotalMomentum()/MeV;
2136 pp1 = targetParticle.GetMomentum().mag()/MeV;
2137 if( pp1 < 0.001*MeV )
2138 {
2139 G4double costheta = 2.*G4UniformRand() - 1.;
2140 G4double sintheta = std::sqrt(1. - costheta*costheta);
2141 G4double phi = twopi*G4UniformRand();
2142 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2143 pp*sintheta*std::sin(phi)*MeV,
2144 pp*costheta*MeV ) ;
2145 }
2146 else
2147 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2148
2149 for( i=0; i<vecLen; ++i )
2150 {
2151 vec[i]->SetKineticEnergy( wgt*vec[i]->GetKineticEnergy() );
2152 pp = vec[i]->GetTotalMomentum()/MeV;
2153 pp1 = vec[i]->GetMomentum().mag()/MeV;
2154 if( pp1 < 0.001 )
2155 {
2156 G4double costheta = 2.*G4UniformRand() - 1.;
2157 G4double sintheta = std::sqrt(1. - costheta*costheta);
2158 G4double phi = twopi*G4UniformRand();
2159 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2160 pp*sintheta*std::sin(phi)*MeV,
2161 pp*costheta*MeV ) ;
2162 }
2163 else
2164 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
2165 }
2166 }
2167 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2168
2169 Rotate( numberofFinalStateNucleons, pseudoParticle[4].GetMomentum(),
2170 modifiedOriginal, originalIncident, targetNucleus,
2171 currentParticle, targetParticle, vec, vecLen );
2172 //
2173 // add black track particles
2174 // the total number of particles produced is restricted to 198
2175 // this may have influence on very high energies
2176 //
2177 if( atomicWeight >= 1.5 )
2178 {
2179 // npnb is number of proton/neutron black track particles
2180 // ndta is the number of deuterons, tritons, and alphas produced
2181 // epnb is the kinetic energy available for proton/neutron black track
2182 // particles
2183 // edta is the kinetic energy available for deuteron/triton/alpha
2184 // particles
2185
2186 G4int npnb = 0;
2187 G4int ndta = 0;
2188
2189 G4double epnb, edta;
2190 if (veryForward) {
2191 epnb = targetNucleus.GetAnnihilationPNBlackTrackEnergy();
2192 edta = targetNucleus.GetAnnihilationDTABlackTrackEnergy();
2193 } else {
2194 epnb = targetNucleus.GetPNBlackTrackEnergy();
2195 edta = targetNucleus.GetDTABlackTrackEnergy();
2196 }
2197
2198 const G4double pnCutOff = 0.001; // GeV
2199 const G4double dtaCutOff = 0.001; // GeV
2200 const G4double kineticMinimum = 1.e-6;
2201 const G4double kineticFactor = -0.005;
2202
2203 G4double sprob = 0.0; // sprob = probability of self-absorption in
2204 // heavy molecules
2205 const G4double ekIncident = originalIncident->GetKineticEnergy()/GeV;
2206 if( ekIncident >= 5.0 )sprob = std::min( 1.0, 0.6*std::log(ekIncident-4.0) );
2207
2208 if( epnb >= pnCutOff )
2209 {
2210 npnb = Poisson((1.5+1.25*numberofFinalStateNucleons)*epnb/(epnb+edta));
2211 if( numberofFinalStateNucleons + npnb > atomicWeight )
2212 npnb = G4int(atomicWeight - numberofFinalStateNucleons);
2213 npnb = std::min( npnb, 127-vecLen );
2214 }
2215 if( edta >= dtaCutOff )
2216 {
2217 ndta = Poisson( (1.5+1.25*numberofFinalStateNucleons)*edta/(epnb+edta) );
2218 ndta = std::min( ndta, 127-vecLen );
2219 }
2220 if (npnb == 0 && ndta == 0) npnb = 1;
2221
2222 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2223
2224 AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum,
2225 kineticFactor, modifiedOriginal,
2226 PinNucleus, NinNucleus, targetNucleus,
2227 vec, vecLen );
2228 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2229 }
2230 //if( centerofmassEnergy <= (4.0+G4UniformRand()) )
2231 // MomentumCheck( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2232 //
2233 // calculate time delay for nuclear reactions
2234 //
2235 if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2236 currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2237 else
2238 currentParticle.SetTOF( 1.0 );
2239
2240 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2241 return true;
2242 }
2243
2244 void G4ReactionDynamics::TwoBody(
2245 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2246 G4int &vecLen,
2247 G4ReactionProduct &modifiedOriginal,
2248 const G4DynamicParticle* originalTarget,
2249 G4ReactionProduct &currentParticle,
2250 G4ReactionProduct &targetParticle,
2251 const G4Nucleus &targetNucleus,
2252 G4bool &/* targetHasChanged*/ )
2253 {
2254 //
2255 // derived from original FORTRAN code TWOB by H. Fesefeldt (15-Sep-1987)
2256 //
2257 // Generation of momenta for elastic and quasi-elastic 2 body reactions
2258 //
2259 // The simple formula ds/d|t| = s0* std::exp(-b*|t|) is used.
2260 // The b values are parametrizations from experimental data.
2261 // Not available values are taken from those of similar reactions.
2262 //
2263
2264 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2265 static const G4double expxu = 82.; // upper bound for arg. of exp
2266 static const G4double expxl = -expxu; // lower bound for arg. of exp
2267
2268 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/GeV;
2269 const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
2270 const G4double mOriginal = modifiedOriginal.GetMass()/GeV;
2271 const G4double pOriginal = modifiedOriginal.GetMomentum().mag()/GeV;
2272 G4double currentMass = currentParticle.GetMass()/GeV;
2273 G4double targetMass = targetParticle.GetDefinition()->GetPDGMass()/GeV;
2274
2275 targetMass = targetParticle.GetMass()/GeV;
2276 const G4double atomicWeight = targetNucleus.GetN();
2277
2278 G4double etCurrent = currentParticle.GetTotalEnergy()/GeV;
2279 G4double pCurrent = currentParticle.GetTotalMomentum()/GeV;
2280
2281 G4double cmEnergy = std::sqrt( currentMass*currentMass +
2282 targetMass*targetMass +
2283 2.0*targetMass*etCurrent ); // in GeV
2284
2285 //if( (pOriginal < 0.1) ||
2286 // (centerofmassEnergy < 0.01) ) // 2-body scattering not possible
2287 // Continue with original particle, but spend the nuclear evaporation energy
2288 // targetParticle.SetMass( 0.0 ); // flag that the target doesn't exist
2289 //else // Two-body scattering is possible
2290
2291 if( (pCurrent < 0.1) || (cmEnergy < 0.01) ) // 2-body scattering not possible
2292 {
2293 targetParticle.SetMass( 0.0 ); // flag that the target particle doesn't exist
2294 }
2295 else
2296 {
2297// moved this if-block to a later stage, i.e. to the assignment of the scattering angle
2298// @@@@@ double-check.
2299// if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2300// targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2301// if( G4UniformRand() < 0.5 )
2302// targetParticle.SetDefinitionAndUpdateE( aNeutron );
2303// else
2304// targetParticle.SetDefinitionAndUpdateE( aProton );
2305// targetHasChanged = true;
2306// targetMass = targetParticle.GetMass()/GeV;
2307// }
2308 //
2309 // Set masses and momenta for final state particles
2310 //
2311 G4double pf = cmEnergy*cmEnergy + targetMass*targetMass - currentMass*currentMass;
2312 pf = pf*pf - 4*cmEnergy*cmEnergy*targetMass*targetMass;
2313
2314 if( pf < 0.001 )
2315 {
2316 for(G4int i=0; i<vecLen; i++) delete vec[i];
2317 vecLen = 0;
2318 throw G4HadronicException(__FILE__, __LINE__, "G4ReactionDynamics::TwoBody: pf is too small ");
2319 }
2320
2321 pf = std::sqrt( pf ) / ( 2.0*cmEnergy );
2322 //
2323 // Set beam and target in centre of mass system
2324 //
2325 G4ReactionProduct pseudoParticle[3];
2326
2327 if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2328 targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2329 pseudoParticle[0].SetMass( targetMass*GeV );
2330 pseudoParticle[0].SetTotalEnergy( etOriginal*GeV );
2331 pseudoParticle[0].SetMomentum( 0.0, 0.0, pOriginal*GeV );
2332
2333 pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2334 pseudoParticle[1].SetMass( mOriginal*GeV );
2335 pseudoParticle[1].SetKineticEnergy( 0.0 );
2336
2337 } else {
2338 pseudoParticle[0].SetMass( currentMass*GeV );
2339 pseudoParticle[0].SetTotalEnergy( etCurrent*GeV );
2340 pseudoParticle[0].SetMomentum( 0.0, 0.0, pCurrent*GeV );
2341
2342 pseudoParticle[1].SetMomentum( 0.0, 0.0, 0.0 );
2343 pseudoParticle[1].SetMass( targetMass*GeV );
2344 pseudoParticle[1].SetKineticEnergy( 0.0 );
2345 }
2346 //
2347 // Transform into centre of mass system
2348 //
2349 pseudoParticle[2] = pseudoParticle[0] + pseudoParticle[1];
2350 pseudoParticle[0].Lorentz( pseudoParticle[0], pseudoParticle[2] );
2351 pseudoParticle[1].Lorentz( pseudoParticle[1], pseudoParticle[2] );
2352 //
2353 // Set final state masses and energies in centre of mass system
2354 //
2355 currentParticle.SetTotalEnergy( std::sqrt(pf*pf+currentMass*currentMass)*GeV );
2356 targetParticle.SetTotalEnergy( std::sqrt(pf*pf+targetMass*targetMass)*GeV );
2357 //
2358 // Set |t| and |tmin|
2359 //
2360 const G4double cb = 0.01;
2361 const G4double b1 = 4.225;
2362 const G4double b2 = 1.795;
2363 //
2364 // Calculate slope b for elastic scattering on proton/neutron
2365 //
2366 G4double b = std::max( cb, b1+b2*std::log(pOriginal) );
2367 G4double btrang = b * 4.0 * pf * pseudoParticle[0].GetMomentum().mag()/GeV;
2368
2369 G4double exindt = -1.0;
2370 exindt += std::exp(std::max(-btrang,expxl));
2371 //
2372 // Calculate sqr(std::sin(teta/2.) and std::cos(teta), set azimuth angle phi
2373 //
2374 G4double ctet = 1.0 + 2*std::log( 1.0+G4UniformRand()*exindt ) / btrang;
2375 if( std::fabs(ctet) > 1.0 )ctet > 0.0 ? ctet = 1.0 : ctet = -1.0;
2376 G4double stet = std::sqrt( (1.0-ctet)*(1.0+ctet) );
2377 G4double phi = twopi * G4UniformRand();
2378 //
2379 // Calculate final state momenta in centre of mass system
2380 //
2381 if (targetParticle.GetDefinition()->GetParticleSubType() == "kaon" ||
2382 targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2383
2384 currentParticle.SetMomentum( -pf*stet*std::sin(phi)*GeV,
2385 -pf*stet*std::cos(phi)*GeV,
2386 -pf*ctet*GeV );
2387 } else {
2388
2389 currentParticle.SetMomentum( pf*stet*std::sin(phi)*GeV,
2390 pf*stet*std::cos(phi)*GeV,
2391 pf*ctet*GeV );
2392 }
2393 targetParticle.SetMomentum( currentParticle.GetMomentum() * (-1.0) );
2394 //
2395 // Transform into lab system
2396 //
2397 currentParticle.Lorentz( currentParticle, pseudoParticle[1] );
2398 targetParticle.Lorentz( targetParticle, pseudoParticle[1] );
2399
2400 Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2401
2402 G4double pp, pp1, ekin;
2403 if( atomicWeight >= 1.5 )
2404 {
2405 const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2406 pp1 = currentParticle.GetMomentum().mag()/MeV;
2407 if( pp1 >= 1.0 )
2408 {
2409 ekin = currentParticle.GetKineticEnergy()/MeV - cfa*(1.0+0.5*normal())*GeV;
2410 ekin = std::max( 0.0001*GeV, ekin );
2411 currentParticle.SetKineticEnergy( ekin*MeV );
2412 pp = currentParticle.GetTotalMomentum()/MeV;
2413 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2414 }
2415 pp1 = targetParticle.GetMomentum().mag()/MeV;
2416 if( pp1 >= 1.0 )
2417 {
2418 ekin = targetParticle.GetKineticEnergy()/MeV - cfa*(1.0+normal()/2.)*GeV;
2419 ekin = std::max( 0.0001*GeV, ekin );
2420 targetParticle.SetKineticEnergy( ekin*MeV );
2421 pp = targetParticle.GetTotalMomentum()/MeV;
2422 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2423 }
2424 }
2425 }
2426
2427 // Get number of final state nucleons and nucleons remaining in
2428 // target nucleus
2429
2430 std::pair<G4int, G4int> finalStateNucleons =
2431 GetFinalStateNucleons(originalTarget, vec, vecLen);
2432 G4int protonsInFinalState = finalStateNucleons.first;
2433 G4int neutronsInFinalState = finalStateNucleons.second;
2434
2435 G4int PinNucleus = std::max(0,
2436 G4int(targetNucleus.GetZ()) - protonsInFinalState);
2437 G4int NinNucleus = std::max(0,
2438 G4int(targetNucleus.GetN()-targetNucleus.GetZ()) - neutronsInFinalState);
2439
2440 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2441 if( atomicWeight >= 1.5 )
2442 {
2443 // Add black track particles
2444 // npnb is number of proton/neutron black track particles
2445 // ndta is the number of deuterons, tritons, and alphas produced
2446 // epnb is the kinetic energy available for proton/neutron black track particles
2447 // edta is the kinetic energy available for deuteron/triton/alpha particles
2448 //
2449 G4double epnb, edta;
2450 G4int npnb=0, ndta=0;
2451
2452 epnb = targetNucleus.GetPNBlackTrackEnergy(); // was enp1 in fortran code
2453 edta = targetNucleus.GetDTABlackTrackEnergy(); // was enp3 in fortran code
2454 const G4double pnCutOff = 0.0001; // GeV
2455 const G4double dtaCutOff = 0.0001; // GeV
2456 const G4double kineticMinimum = 0.0001;
2457 const G4double kineticFactor = -0.010;
2458 G4double sprob = 0.0; // sprob = probability of self-absorption in heavy molecules
2459 if( epnb >= pnCutOff )
2460 {
2461 npnb = Poisson( epnb/0.02 );
2462 if( npnb > atomicWeight )npnb = G4int(atomicWeight);
2463 if( (epnb > pnCutOff) && (npnb <= 0) )npnb = 1;
2464 npnb = std::min( npnb, 127-vecLen );
2465 }
2466 if( edta >= dtaCutOff )
2467 {
2468 ndta = G4int(2.0 * std::log(atomicWeight));
2469 ndta = std::min( ndta, 127-vecLen );
2470 }
2471
2472 if (npnb == 0 && ndta == 0) npnb = 1;
2473
2474 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2475
2476 AddBlackTrackParticles(epnb, npnb, edta, ndta, sprob, kineticMinimum,
2477 kineticFactor, modifiedOriginal,
2478 PinNucleus, NinNucleus, targetNucleus,
2479 vec, vecLen);
2480 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2481 }
2482 //
2483 // calculate time delay for nuclear reactions
2484 //
2485 if( (atomicWeight >= 1.5) && (atomicWeight <= 230.0) && (ekOriginal <= 0.2) )
2486 currentParticle.SetTOF( 1.0-500.0*std::exp(-ekOriginal/0.04)*std::log(G4UniformRand()) );
2487 else
2488 currentParticle.SetTOF( 1.0 );
2489 return;
2490 }
2491
2492 G4double G4ReactionDynamics::GenerateNBodyEvent(
2493 const G4double totalEnergy, // MeV
2494 const G4bool constantCrossSection,
2495 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2496 G4int &vecLen )
2497 {
2498 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2499 // derived from original FORTRAN code PHASP by H. Fesefeldt (02-Dec-1986)
2500 // Returns the weight of the event
2501 //
2502 G4int i;
2503 const G4double expxu = 82.; // upper bound for arg. of exp
2504 const G4double expxl = -expxu; // lower bound for arg. of exp
2505 if( vecLen < 2 )
2506 {
2507 G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2508 G4cerr << " number of particles < 2" << G4endl;
2509 G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
2510 return -1.0;
2511 }
2512 G4double mass[18]; // mass of each particle
2513 G4double energy[18]; // total energy of each particle
2514 G4double pcm[3][18]; // pcm is an array with 3 rows and vecLen columns
2515
2516 G4double totalMass = 0.0;
2517 G4double extraMass = 0;
2518 G4double sm[18];
2519
2520 for( i=0; i<vecLen; ++i )
2521 {
2522 mass[i] = vec[i]->GetMass()/GeV;
2523 if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
2524 vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
2525 pcm[0][i] = 0.0; // x-momentum of i-th particle
2526 pcm[1][i] = 0.0; // y-momentum of i-th particle
2527 pcm[2][i] = 0.0; // z-momentum of i-th particle
2528 energy[i] = mass[i]; // total energy of i-th particle
2529 totalMass += mass[i];
2530 sm[i] = totalMass;
2531 }
2532 G4double totalE = totalEnergy/GeV;
2533 if( totalMass > totalE )
2534 {
2535 //G4cerr << "*** Error in G4ReactionDynamics::GenerateNBodyEvent" << G4endl;
2536 //G4cerr << " total mass (" << totalMass*GeV << "MeV) > total energy ("
2537 // << totalEnergy << "MeV)" << G4endl;
2538 totalE = totalMass;
2539 return -1.0;
2540 }
2541 G4double kineticEnergy = totalE - totalMass;
2542 G4double emm[18];
2543 //G4double *emm = new G4double [vecLen];
2544 emm[0] = mass[0];
2545 emm[vecLen-1] = totalE;
2546 if( vecLen > 2 ) // the random numbers are sorted
2547 {
2548 G4double ran[18];
2549 for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
2550 for( i=0; i<vecLen-2; ++i )
2551 {
2552 for( G4int j=vecLen-2; j>i; --j )
2553 {
2554 if( ran[i] > ran[j] )
2555 {
2556 G4double temp = ran[i];
2557 ran[i] = ran[j];
2558 ran[j] = temp;
2559 }
2560 }
2561 }
2562 for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
2563 }
2564 // Weight is the sum of logarithms of terms instead of the product of terms
2565 G4bool lzero = true;
2566 G4double wtmax = 0.0;
2567 if( constantCrossSection ) // this is KGENEV=1 in PHASP
2568 {
2569 G4double emmax = kineticEnergy + mass[0];
2570 G4double emmin = 0.0;
2571 for( i=1; i<vecLen; ++i )
2572 {
2573 emmin += mass[i-1];
2574 emmax += mass[i];
2575 G4double wtfc = 0.0;
2576 if( emmax*emmax > 0.0 )
2577 {
2578 G4double arg = emmax*emmax
2579 + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
2580 - 2.0*(emmin*emmin+mass[i]*mass[i]);
2581 if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
2582 }
2583 if( wtfc == 0.0 )
2584 {
2585 lzero = false;
2586 break;
2587 }
2588 wtmax += std::log( wtfc );
2589 }
2590 if( lzero )
2591 wtmax = -wtmax;
2592 else
2593 wtmax = expxu;
2594 }
2595 else
2596 {
2597 // ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
2598 const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
2599 256.3704, 268.4705, 240.9780, 189.2637,
2600 132.1308, 83.0202, 47.4210, 24.8295,
2601 12.0006, 5.3858, 2.2560, 0.8859 };
2602 wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
2603 }
2604 lzero = true;
2605 G4double pd[50];
2606 //G4double *pd = new G4double [vecLen-1];
2607 for( i=0; i<vecLen-1; ++i )
2608 {
2609 pd[i] = 0.0;
2610 if( emm[i+1]*emm[i+1] > 0.0 )
2611 {
2612 G4double arg = emm[i+1]*emm[i+1]
2613 + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
2614 /(emm[i+1]*emm[i+1])
2615 - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
2616 if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
2617 }
2618 if( pd[i] <= 0.0 ) // changed from == on 02 April 98
2619 lzero = false;
2620 else
2621 wtmax += std::log( pd[i] );
2622 }
2623 G4double weight = 0.0; // weight is returned by GenerateNBodyEvent
2624 if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
2625
2626 G4double bang, cb, sb, s0, s1, s2, c, s, esys, a, b, gama, beta;
2627 pcm[0][0] = 0.0;
2628 pcm[1][0] = pd[0];
2629 pcm[2][0] = 0.0;
2630 for( i=1; i<vecLen; ++i )
2631 {
2632 pcm[0][i] = 0.0;
2633 pcm[1][i] = -pd[i-1];
2634 pcm[2][i] = 0.0;
2635 bang = twopi*G4UniformRand();
2636 cb = std::cos(bang);
2637 sb = std::sin(bang);
2638 c = 2.0*G4UniformRand() - 1.0;
2639 s = std::sqrt( std::fabs( 1.0-c*c ) );
2640 if( i < vecLen-1 )
2641 {
2642 esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
2643 beta = pd[i]/esys;
2644 gama = esys/emm[i];
2645 for( G4int j=0; j<=i; ++j )
2646 {
2647 s0 = pcm[0][j];
2648 s1 = pcm[1][j];
2649 s2 = pcm[2][j];
2650 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2651 a = s0*c - s1*s; // rotation
2652 pcm[1][j] = s0*s + s1*c;
2653 b = pcm[2][j];
2654 pcm[0][j] = a*cb - b*sb;
2655 pcm[2][j] = a*sb + b*cb;
2656 pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
2657 }
2658 }
2659 else
2660 {
2661 for( G4int j=0; j<=i; ++j )
2662 {
2663 s0 = pcm[0][j];
2664 s1 = pcm[1][j];
2665 s2 = pcm[2][j];
2666 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
2667 a = s0*c - s1*s; // rotation
2668 pcm[1][j] = s0*s + s1*c;
2669 b = pcm[2][j];
2670 pcm[0][j] = a*cb - b*sb;
2671 pcm[2][j] = a*sb + b*cb;
2672 }
2673 }
2674 }
2675 for( i=0; i<vecLen; ++i )
2676 {
2677 vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
2678 vec[i]->SetTotalEnergy( energy[i]*GeV );
2679 }
2680
2681 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
2682 return weight;
2683 }
2684
2685 G4double
2686 G4ReactionDynamics::normal()
2687 {
2688 G4double ran = -6.0;
2689 for( G4int i=0; i<12; ++i )ran += G4UniformRand();
2690 return ran;
2691 }
2692
2693 G4int
2694 G4ReactionDynamics::Poisson( G4double x ) // generation of poisson distribution
2695 {
2696 G4int iran;
2697 G4double ran;
2698
2699 if( x > 9.9 ) // use normal distribution with sigma^2 = <x>
2700 iran = static_cast<G4int>(std::max( 0.0, x+normal()*std::sqrt(x) ) );
2701 else {
2702 G4int mm = G4int(5.0*x);
2703 if( mm <= 0 ) // for very small x try iran=1,2,3
2704 {
2705 G4double p1 = x*std::exp(-x);
2706 G4double p2 = x*p1/2.0;
2707 G4double p3 = x*p2/3.0;
2708 ran = G4UniformRand();
2709 if( ran < p3 )
2710 iran = 3;
2711 else if( ran < p2 ) // this is original Geisha, it should be ran < p2+p3
2712 iran = 2;
2713 else if( ran < p1 ) // should be ran < p1+p2+p3
2714 iran = 1;
2715 else
2716 iran = 0;
2717 }
2718 else
2719 {
2720 iran = 0;
2721 G4double r = std::exp(-x);
2722 ran = G4UniformRand();
2723 if( ran > r )
2724 {
2725 G4double rrr;
2726 G4double rr = r;
2727 for( G4int i=1; i<=mm; ++i )
2728 {
2729 iran++;
2730 if( i > 5 ) // Stirling's formula for large numbers
2731 rrr = std::exp(i*std::log(x)-(i+0.5)*std::log((G4double)i)+i-0.9189385);
2732 else
2733 rrr = std::pow(x,i)/Factorial(i);
2734 rr += r*rrr;
2735 if( ran <= rr )break;
2736 }
2737 }
2738 }
2739 }
2740 return iran;
2741 }
2742
2743 G4int
2744 G4ReactionDynamics::Factorial( G4int n )
2745 { // calculates factorial( n ) = n*(n-1)*(n-2)*...*1
2746 G4int m = std::min(n,10);
2747 G4int result = 1;
2748 if( m <= 1 )return result;
2749 for( G4int i=2; i<=m; ++i )result *= i;
2750 return result;
2751 }
2752
2753 void G4ReactionDynamics::Defs1(
2754 const G4ReactionProduct &modifiedOriginal,
2755 G4ReactionProduct &currentParticle,
2756 G4ReactionProduct &targetParticle,
2757 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2758 G4int &vecLen )
2759 {
2760 const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
2761 const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
2762 const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
2763 const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
2764 if( pjx*pjx+pjy*pjy > 0.0 )
2765 {
2766 G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
2767 cost = pjz/p;
2768 sint = 0.5 * ( std::sqrt(std::abs((1.0-cost)*(1.0+cost))) + std::sqrt(pjx*pjx+pjy*pjy)/p );
2769 if( pjy < 0.0 )
2770 ph = 3*halfpi;
2771 else
2772 ph = halfpi;
2773 if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
2774 cosp = std::cos(ph);
2775 sinp = std::sin(ph);
2776 pix = currentParticle.GetMomentum().x()/MeV;
2777 piy = currentParticle.GetMomentum().y()/MeV;
2778 piz = currentParticle.GetMomentum().z()/MeV;
2779 currentParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2780 cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2781 -sint*pix*MeV + cost*piz*MeV );
2782 pix = targetParticle.GetMomentum().x()/MeV;
2783 piy = targetParticle.GetMomentum().y()/MeV;
2784 piz = targetParticle.GetMomentum().z()/MeV;
2785 targetParticle.SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2786 cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2787 -sint*pix*MeV + cost*piz*MeV );
2788 for( G4int i=0; i<vecLen; ++i )
2789 {
2790 pix = vec[i]->GetMomentum().x()/MeV;
2791 piy = vec[i]->GetMomentum().y()/MeV;
2792 piz = vec[i]->GetMomentum().z()/MeV;
2793 vec[i]->SetMomentum( cost*cosp*pix*MeV - sinp*piy+sint*cosp*piz*MeV,
2794 cost*sinp*pix*MeV + cosp*piy+sint*sinp*piz*MeV,
2795 -sint*pix*MeV + cost*piz*MeV );
2796 }
2797 }
2798 else
2799 {
2800 if( pjz < 0.0 )
2801 {
2802 currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
2803 targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
2804 for( G4int i=0; i<vecLen; ++i )
2805 vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
2806 }
2807 }
2808 }
2809
2810 void G4ReactionDynamics::Rotate(
2811 const G4double numberofFinalStateNucleons,
2812 const G4ThreeVector &temp,
2813 const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
2814 const G4HadProjectile *originalIncident, // original incident particle
2815 const G4Nucleus &targetNucleus,
2816 G4ReactionProduct &currentParticle,
2817 G4ReactionProduct &targetParticle,
2818 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
2819 G4int &vecLen )
2820 {
2821 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
2822 //
2823 // Rotate in direction of z-axis, this does disturb in some way our
2824 // inclusive distributions, but it is necessary for momentum conservation
2825 //
2826 const G4double atomicWeight = targetNucleus.GetN();
2827 const G4double logWeight = std::log(atomicWeight);
2828
2829 G4ParticleDefinition *aPiMinus = G4PionMinus::PionMinus();
2830 G4ParticleDefinition *aPiPlus = G4PionPlus::PionPlus();
2831 G4ParticleDefinition *aPiZero = G4PionZero::PionZero();
2832
2833 G4int i;
2834 G4ThreeVector pseudoParticle[4];
2835 for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
2836 pseudoParticle[0] = currentParticle.GetMomentum()
2837 + targetParticle.GetMomentum();
2838 for( i=0; i<vecLen; ++i )
2839 pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
2840 //
2841 // Some smearing in transverse direction from Fermi motion
2842 //
2843 G4float pp, pp1;
2844 G4double alekw, p;
2845 G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
2846
2847 r1 = twopi*G4UniformRand();
2848 r2 = G4UniformRand();
2849 a1 = std::sqrt(-2.0*std::log(r2));
2850 ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
2851 ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
2852 G4ThreeVector fermi(ran1, ran2, 0);
2853
2854 pseudoParticle[0] = pseudoParticle[0]+fermi; // all particles + fermi
2855 pseudoParticle[2] = temp; // original in cms system
2856 pseudoParticle[3] = pseudoParticle[0];
2857
2858 pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
2859 G4double rotation = 2.*pi*G4UniformRand();
2860 pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
2861 pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);
2862 for(G4int ii=1; ii<=3; ii++)
2863 {
2864 p = pseudoParticle[ii].mag();
2865 if( p == 0.0 )
2866 pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
2867 else
2868 pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
2869 }
2870
2871 pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
2872 pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
2873 pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
2874 currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2875
2876 pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
2877 pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
2878 pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
2879 targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
2880
2881 for( i=0; i<vecLen; ++i )
2882 {
2883 pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
2884 pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
2885 pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
2886 vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
2887 }
2888 //
2889 // Rotate in direction of primary particle, subtract binding energies
2890 // and make some further corrections if required
2891 //
2892 Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
2893 G4double ekin;
2894 G4double dekin = 0.0;
2895 G4double ek1 = 0.0;
2896 G4int npions = 0;
2897 if( atomicWeight >= 1.5 ) // self-absorption in heavy molecules
2898 {
2899 // corrections for single particle spectra (shower particles)
2900 //
2901 const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
2902 const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
2903 alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
2904 exh = 1.0;
2905 if( alekw > alem[0] ) // get energy bin
2906 {
2907 exh = val0[6];
2908 for( G4int j=1; j<7; ++j )
2909 {
2910 if( alekw < alem[j] ) // use linear interpolation/extrapolation
2911 {
2912 G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
2913 exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
2914 break;
2915 }
2916 }
2917 exh = 1.0 - exh;
2918 }
2919 const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
2920 ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2921 ekin = std::max( 1.0e-6, ekin );
2922 xxh = 1.0;
2923 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2924 modifiedOriginal.GetDefinition() == aPiMinus) &&
2925 currentParticle.GetDefinition() == aPiZero &&
2926 G4UniformRand() <= logWeight) xxh = exh;
2927 dekin += ekin*(1.0-xxh);
2928 ekin *= xxh;
2929 if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
2930 ++npions;
2931 ek1 += ekin;
2932 }
2933 currentParticle.SetKineticEnergy( ekin*GeV );
2934 pp = currentParticle.GetTotalMomentum()/MeV;
2935 pp1 = currentParticle.GetMomentum().mag()/MeV;
2936 if( pp1 < 0.001*MeV )
2937 {
2938 G4double costheta = 2.*G4UniformRand() - 1.;
2939 G4double sintheta = std::sqrt(1. - costheta*costheta);
2940 G4double phi = twopi*G4UniformRand();
2941 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2942 pp*sintheta*std::sin(phi)*MeV,
2943 pp*costheta*MeV ) ;
2944 }
2945 else
2946 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
2947 ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2948 ekin = std::max( 1.0e-6, ekin );
2949 xxh = 1.0;
2950 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2951 modifiedOriginal.GetDefinition() == aPiMinus) &&
2952 targetParticle.GetDefinition() == aPiZero &&
2953 G4UniformRand() < logWeight) xxh = exh;
2954 dekin += ekin*(1.0-xxh);
2955 ekin *= xxh;
2956 if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
2957 ++npions;
2958 ek1 += ekin;
2959 }
2960 targetParticle.SetKineticEnergy( ekin*GeV );
2961 pp = targetParticle.GetTotalMomentum()/MeV;
2962 pp1 = targetParticle.GetMomentum().mag()/MeV;
2963 if( pp1 < 0.001*MeV )
2964 {
2965 G4double costheta = 2.*G4UniformRand() - 1.;
2966 G4double sintheta = std::sqrt(1. - costheta*costheta);
2967 G4double phi = twopi*G4UniformRand();
2968 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2969 pp*sintheta*std::sin(phi)*MeV,
2970 pp*costheta*MeV ) ;
2971 }
2972 else
2973 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
2974 for( i=0; i<vecLen; ++i )
2975 {
2976 ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
2977 ekin = std::max( 1.0e-6, ekin );
2978 xxh = 1.0;
2979 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
2980 modifiedOriginal.GetDefinition() == aPiMinus) &&
2981 vec[i]->GetDefinition() == aPiZero &&
2982 G4UniformRand() < logWeight) xxh = exh;
2983 dekin += ekin*(1.0-xxh);
2984 ekin *= xxh;
2985 if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
2986 ++npions;
2987 ek1 += ekin;
2988 }
2989 vec[i]->SetKineticEnergy( ekin*GeV );
2990 pp = vec[i]->GetTotalMomentum()/MeV;
2991 pp1 = vec[i]->GetMomentum().mag()/MeV;
2992 if( pp1 < 0.001*MeV )
2993 {
2994 G4double costheta = 2.*G4UniformRand() - 1.;
2995 G4double sintheta = std::sqrt(1. - costheta*costheta);
2996 G4double phi = twopi*G4UniformRand();
2997 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
2998 pp*sintheta*std::sin(phi)*MeV,
2999 pp*costheta*MeV ) ;
3000 }
3001 else
3002 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3003 }
3004 }
3005 if( (ek1 != 0.0) && (npions > 0) )
3006 {
3007 dekin = 1.0 + dekin/ek1;
3008 //
3009 // first do the incident particle
3010 //
3011 if (currentParticle.GetDefinition()->GetParticleSubType() == "pi")
3012 {
3013 currentParticle.SetKineticEnergy(
3014 std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
3015 pp = currentParticle.GetTotalMomentum()/MeV;
3016 pp1 = currentParticle.GetMomentum().mag()/MeV;
3017 if( pp1 < 0.001 )
3018 {
3019 G4double costheta = 2.*G4UniformRand() - 1.;
3020 G4double sintheta = std::sqrt(1. - costheta*costheta);
3021 G4double phi = twopi*G4UniformRand();
3022 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3023 pp*sintheta*std::sin(phi)*MeV,
3024 pp*costheta*MeV ) ;
3025 } else {
3026 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
3027 }
3028 }
3029
3030 if (targetParticle.GetDefinition()->GetParticleSubType() == "pi")
3031 {
3032 targetParticle.SetKineticEnergy(
3033 std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
3034 pp = targetParticle.GetTotalMomentum()/MeV;
3035 pp1 = targetParticle.GetMomentum().mag()/MeV;
3036 if( pp1 < 0.001 )
3037 {
3038 G4double costheta = 2.*G4UniformRand() - 1.;
3039 G4double sintheta = std::sqrt(1. - costheta*costheta);
3040 G4double phi = twopi*G4UniformRand();
3041 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3042 pp*sintheta*std::sin(phi)*MeV,
3043 pp*costheta*MeV ) ;
3044 } else {
3045 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
3046 }
3047 }
3048
3049 for( i=0; i<vecLen; ++i )
3050 {
3051 if (vec[i]->GetDefinition()->GetParticleSubType() == "pi")
3052 {
3053 vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
3054 pp = vec[i]->GetTotalMomentum()/MeV;
3055 pp1 = vec[i]->GetMomentum().mag()/MeV;
3056 if( pp1 < 0.001 )
3057 {
3058 G4double costheta = 2.*G4UniformRand() - 1.;
3059 G4double sintheta = std::sqrt(1. - costheta*costheta);
3060 G4double phi = twopi*G4UniformRand();
3061 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
3062 pp*sintheta*std::sin(phi)*MeV,
3063 pp*costheta*MeV ) ;
3064 } else {
3065 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
3066 }
3067 }
3068 } // for i
3069 } // if (ek1 != 0)
3070 }
3071
3072 void G4ReactionDynamics::AddBlackTrackParticles(
3073 const G4double epnb, // GeV
3074 const G4int npnb,
3075 const G4double edta, // GeV
3076 const G4int ndta,
3077 const G4double sprob,
3078 const G4double kineticMinimum, // GeV
3079 const G4double kineticFactor, // GeV
3080 const G4ReactionProduct &modifiedOriginal,
3081 G4int PinNucleus,
3082 G4int NinNucleus,
3083 const G4Nucleus &targetNucleus,
3084 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3085 G4int &vecLen )
3086 {
3087 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
3088 //
3089 // npnb is number of proton/neutron black track particles
3090 // ndta is the number of deuterons, tritons, and alphas produced
3091 // epnb is the kinetic energy available for proton/neutron black track particles
3092 // edta is the kinetic energy available for deuteron/triton/alpha particles
3093 //
3094
3095 G4ParticleDefinition *aProton = G4Proton::Proton();
3096 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3097 G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3098 G4ParticleDefinition *aTriton = G4Triton::Triton();
3099 G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3100
3101 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
3102 const G4double atomicWeight = targetNucleus.GetN();
3103 const G4double atomicNumber = targetNucleus.GetZ();
3104
3105 const G4double ika1 = 3.6;
3106 const G4double ika2 = 35.56;
3107 const G4double ika3 = 6.45;
3108
3109 G4int i;
3110 G4double pp;
3111 G4double kinCreated = 0;
3112 G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
3113
3114 // First add protons and neutrons to final state
3115
3116 if (npnb > 0)
3117 {
3118 G4double backwardKinetic = 0.0;
3119 G4int local_npnb = npnb;
3120 for( i=0; i<npnb; ++i ) if( G4UniformRand() < sprob ) local_npnb--;
3121 G4double local_epnb = epnb;
3122 if (ndta == 0) local_epnb += edta; // Retrieve unused kinetic energy
3123 G4double ekin = local_epnb/std::max(1,local_npnb);
3124
3125 for( i=0; i<local_npnb; ++i )
3126 {
3127 G4ReactionProduct * p1 = new G4ReactionProduct();
3128 if( backwardKinetic > local_epnb )
3129 {
3130 delete p1;
3131 break;
3132 }
3133 G4double ran = G4UniformRand();
3134 G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
3135 if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
3136 backwardKinetic += kinetic;
3137 if( backwardKinetic > local_epnb )
3138 kinetic = std::max( kineticMinimum, local_epnb-(backwardKinetic-kinetic) );
3139
3140 if (G4UniformRand() > (1.0-atomicNumber/atomicWeight)) {
3141
3142 // Boil off a proton if there are any left, otherwise a neutron
3143
3144 if (PinNucleus > 0) {
3145 p1->SetDefinition( aProton );
3146 PinNucleus--;
3147 } else if (NinNucleus > 0) {
3148 p1->SetDefinition( aNeutron );
3149 NinNucleus--;
3150 } else {
3151 delete p1;
3152 break; // no nucleons left in nucleus
3153 }
3154 } else {
3155
3156 // Boil off a neutron if there are any left, otherwise a proton
3157
3158 if (NinNucleus > 0) {
3159 p1->SetDefinition( aNeutron );
3160 NinNucleus--;
3161 } else if (PinNucleus > 0) {
3162 p1->SetDefinition( aProton );
3163 PinNucleus--;
3164 } else {
3165 delete p1;
3166 break; // no nucleons left in nucleus
3167 }
3168 }
3169
3170 vec.SetElement( vecLen, p1 );
3171 G4double cost = G4UniformRand() * 2.0 - 1.0;
3172 G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
3173 G4double phi = twopi * G4UniformRand();
3174 vec[vecLen]->SetNewlyAdded( true );
3175 vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3176 kinCreated+=kinetic;
3177 pp = vec[vecLen]->GetTotalMomentum()/MeV;
3178 vec[vecLen]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3179 pp*sint*std::cos(phi)*MeV,
3180 pp*cost*MeV );
3181 vecLen++;
3182 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3183 }
3184
3185 if (NinNucleus > 0) {
3186 if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
3187 {
3188 G4double ekw = ekOriginal/GeV;
3189 G4int ika, kk = 0;
3190 if( ekw > 1.0 )ekw *= ekw;
3191 ekw = std::max( 0.1, ekw );
3192 ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/
3193 atomicWeight-ika2)/ika3)/ekw);
3194 if( ika > 0 )
3195 {
3196 for( i=(vecLen-1); i>=0; --i )
3197 {
3198 if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
3199 {
3200 vec[i]->SetDefinitionAndUpdateE( aNeutron ); // modified 22-Oct-97
3201 PinNucleus++;
3202 NinNucleus--;
3203 if( ++kk > ika )break;
3204 }
3205 }
3206 }
3207 }
3208 } // if (NinNucleus >0)
3209 } // if (npnb > 0)
3210
3211 // Next try to add deuterons, tritons and alphas to final state
3212
3213 if (ndta > 0)
3214 {
3215 G4double backwardKinetic = 0.0;
3216 G4int local_ndta=ndta;
3217 for( i=0; i<ndta; ++i )if( G4UniformRand() < sprob )local_ndta--;
3218 G4double local_edta = edta;
3219 if (npnb == 0) local_edta += epnb; // Retrieve unused kinetic energy
3220 G4double ekin = local_edta/std::max(1,local_ndta);
3221
3222 for( i=0; i<local_ndta; ++i )
3223 {
3224 G4ReactionProduct *p2 = new G4ReactionProduct();
3225 if( backwardKinetic > local_edta )
3226 {
3227 delete p2;
3228 break;
3229 }
3230 G4double ran = G4UniformRand();
3231 G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
3232 if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
3233 backwardKinetic += kinetic;
3234 if( backwardKinetic > local_edta )kinetic = local_edta-(backwardKinetic-kinetic);
3235 if( kinetic < 0.0 )kinetic = kineticMinimum;
3236 G4double cost = 2.0*G4UniformRand() - 1.0;
3237 G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
3238 G4double phi = twopi*G4UniformRand();
3239 ran = G4UniformRand();
3240 if (ran < 0.60) {
3241 if (PinNucleus > 0 && NinNucleus > 0) {
3242 p2->SetDefinition( aDeuteron );
3243 PinNucleus--;
3244 NinNucleus--;
3245 } else if (NinNucleus > 0) {
3246 p2->SetDefinition( aNeutron );
3247 NinNucleus--;
3248 } else if (PinNucleus > 0) {
3249 p2->SetDefinition( aProton );
3250 PinNucleus--;
3251 } else {
3252 delete p2;
3253 break;
3254 }
3255 } else if (ran < 0.90) {
3256 if (PinNucleus > 0 && NinNucleus > 1) {
3257 p2->SetDefinition( aTriton );
3258 PinNucleus--;
3259 NinNucleus -= 2;
3260 } else if (PinNucleus > 0 && NinNucleus > 0) {
3261 p2->SetDefinition( aDeuteron );
3262 PinNucleus--;
3263 NinNucleus--;
3264 } else if (NinNucleus > 0) {
3265 p2->SetDefinition( aNeutron );
3266 NinNucleus--;
3267 } else if (PinNucleus > 0) {
3268 p2->SetDefinition( aProton );
3269 PinNucleus--;
3270 } else {
3271 delete p2;
3272 break;
3273 }
3274 } else {
3275 if (PinNucleus > 1 && NinNucleus > 1) {
3276 p2->SetDefinition( anAlpha );
3277 PinNucleus -= 2;
3278 NinNucleus -= 2;
3279 } else if (PinNucleus > 0 && NinNucleus > 1) {
3280 p2->SetDefinition( aTriton );
3281 PinNucleus--;
3282 NinNucleus -= 2;
3283 } else if (PinNucleus > 0 && NinNucleus > 0) {
3284 p2->SetDefinition( aDeuteron );
3285 PinNucleus--;
3286 NinNucleus--;
3287 } else if (NinNucleus > 0) {
3288 p2->SetDefinition( aNeutron );
3289 NinNucleus--;
3290 } else if (PinNucleus > 0) {
3291 p2->SetDefinition( aProton );
3292 PinNucleus--;
3293 } else {
3294 delete p2;
3295 break;
3296 }
3297 }
3298
3299 vec.SetElement( vecLen, p2 );
3300 vec[vecLen]->SetNewlyAdded( true );
3301 vec[vecLen]->SetKineticEnergy( kinetic*GeV );
3302 kinCreated+=kinetic;
3303 pp = vec[vecLen]->GetTotalMomentum()/MeV;
3304 vec[vecLen++]->SetMomentum( pp*sint*std::sin(phi)*MeV,
3305 pp*sint*std::cos(phi)*MeV,
3306 pp*cost*MeV );
3307 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3308 }
3309 } // if (ndta > 0)
3310
3311 // G4double delta = epnb+edta - kinCreated;
3312 }
3313
3314
3315 std::pair<G4int, G4int> G4ReactionDynamics::GetFinalStateNucleons(
3316 const G4DynamicParticle* originalTarget,
3317 const G4FastVector<G4ReactionProduct,GHADLISTSIZE>& vec,
3318 const G4int& vecLen)
3319 {
3320 // Get number of protons and neutrons removed from the target nucleus
3321
3322 G4int protonsRemoved = 0;
3323 G4int neutronsRemoved = 0;
3324 if (originalTarget->GetDefinition()->GetParticleName() == "proton")
3325 protonsRemoved++;
3326 else
3327 neutronsRemoved++;
3328
3329 G4String secName;
3330 for (G4int i = 0; i < vecLen; i++) {
3331 secName = vec[i]->GetDefinition()->GetParticleName();
3332 if (secName == "proton") {
3333 protonsRemoved++;
3334 } else if (secName == "neutron") {
3335 neutronsRemoved++;
3336 } else if (secName == "anti_proton") {
3337 protonsRemoved--;
3338 } else if (secName == "anti_neutron") {
3339 neutronsRemoved--;
3340 }
3341 }
3342
3343 return std::pair<G4int, G4int>(protonsRemoved, neutronsRemoved);
3344 }
3345
3346
3347 void G4ReactionDynamics::MomentumCheck(
3348 const G4ReactionProduct &modifiedOriginal,
3349 G4ReactionProduct &currentParticle,
3350 G4ReactionProduct &targetParticle,
3351 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3352 G4int &vecLen )
3353 {
3354 const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
3355 G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
3356 G4double pMass;
3357 if( testMomentum >= pOriginal )
3358 {
3359 pMass = currentParticle.GetMass()/MeV;
3360 currentParticle.SetTotalEnergy(
3361 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3362 currentParticle.SetMomentum(
3363 currentParticle.GetMomentum() * (pOriginal/testMomentum) );
3364 }
3365 testMomentum = targetParticle.GetMomentum().mag()/MeV;
3366 if( testMomentum >= pOriginal )
3367 {
3368 pMass = targetParticle.GetMass()/MeV;
3369 targetParticle.SetTotalEnergy(
3370 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3371 targetParticle.SetMomentum(
3372 targetParticle.GetMomentum() * (pOriginal/testMomentum) );
3373 }
3374 for( G4int i=0; i<vecLen; ++i )
3375 {
3376 testMomentum = vec[i]->GetMomentum().mag()/MeV;
3377 if( testMomentum >= pOriginal )
3378 {
3379 pMass = vec[i]->GetMass()/MeV;
3380 vec[i]->SetTotalEnergy(
3381 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
3382 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
3383 }
3384 }
3385 }
3386
3387 void G4ReactionDynamics::ProduceStrangeParticlePairs(
3388 G4FastVector<G4ReactionProduct,GHADLISTSIZE> &vec,
3389 G4int &vecLen,
3390 const G4ReactionProduct &modifiedOriginal,
3391 const G4DynamicParticle *originalTarget,
3392 G4ReactionProduct &currentParticle,
3393 G4ReactionProduct &targetParticle,
3394 G4bool &incidentHasChanged,
3395 G4bool &targetHasChanged )
3396 {
3397 // derived from original FORTRAN code STPAIR by H. Fesefeldt (16-Dec-1987)
3398 //
3399 // Choose charge combinations K+ K-, K+ K0B, K0 K0B, K0 K-,
3400 // K+ Y0, K0 Y+, K0 Y-
3401 // For antibaryon induced reactions half of the cross sections KB YB
3402 // pairs are produced. Charge is not conserved, no experimental data available
3403 // for exclusive reactions, therefore some average behaviour assumed.
3404 // The ratio L/SIGMA is taken as 3:1 (from experimental low energy)
3405 //
3406 if( vecLen == 0 )return;
3407 //
3408 // the following protects against annihilation processes
3409 //
3410 if( currentParticle.GetMass() == 0.0 || targetParticle.GetMass() == 0.0 )return;
3411
3412 const G4double etOriginal = modifiedOriginal.GetTotalEnergy()/GeV;
3413 const G4double mOriginal = modifiedOriginal.GetDefinition()->GetPDGMass()/GeV;
3414 G4double targetMass = originalTarget->GetDefinition()->GetPDGMass()/GeV;
3415 G4double centerofmassEnergy = std::sqrt( mOriginal*mOriginal +
3416 targetMass*targetMass +
3417 2.0*targetMass*etOriginal ); // GeV
3418 G4double currentMass = currentParticle.GetMass()/GeV;
3419 G4double availableEnergy = centerofmassEnergy-(targetMass+currentMass);
3420 if( availableEnergy <= 1.0 )return;
3421
3422 G4ParticleDefinition *aProton = G4Proton::Proton();
3423 G4ParticleDefinition *anAntiProton = G4AntiProton::AntiProton();
3424 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3425 G4ParticleDefinition *anAntiNeutron = G4AntiNeutron::AntiNeutron();
3426 G4ParticleDefinition *aSigmaMinus = G4SigmaMinus::SigmaMinus();
3427 G4ParticleDefinition *aSigmaPlus = G4SigmaPlus::SigmaPlus();
3428 G4ParticleDefinition *aSigmaZero = G4SigmaZero::SigmaZero();
3429 G4ParticleDefinition *anAntiSigmaMinus = G4AntiSigmaMinus::AntiSigmaMinus();
3430 G4ParticleDefinition *anAntiSigmaPlus = G4AntiSigmaPlus::AntiSigmaPlus();
3431 G4ParticleDefinition *anAntiSigmaZero = G4AntiSigmaZero::AntiSigmaZero();
3432 G4ParticleDefinition *aKaonMinus = G4KaonMinus::KaonMinus();
3433 G4ParticleDefinition *aKaonPlus = G4KaonPlus::KaonPlus();
3434 G4ParticleDefinition *aKaonZL = G4KaonZeroLong::KaonZeroLong();
3435 G4ParticleDefinition *aKaonZS = G4KaonZeroShort::KaonZeroShort();
3436 G4ParticleDefinition *aLambda = G4Lambda::Lambda();
3437 G4ParticleDefinition *anAntiLambda = G4AntiLambda::AntiLambda();
3438
3439 const G4double protonMass = aProton->GetPDGMass()/GeV;
3440 const G4double sigmaMinusMass = aSigmaMinus->GetPDGMass()/GeV;
3441 //
3442 // determine the center of mass energy bin
3443 //
3444 const G4double avrs[] = {3.,4.,5.,6.,7.,8.,9.,10.,20.,30.,40.,50.};
3445
3446 G4int ibin, i3, i4;
3447 G4double avk, avy, avn, ran;
3448 G4int i = 1;
3449 while( (i<12) && (centerofmassEnergy>avrs[i]) )++i;
3450 if( i == 12 )
3451 ibin = 11;
3452 else
3453 ibin = i;
3454 //
3455 // the fortran code chooses a random replacement of produced kaons
3456 // but does not take into account charge conservation
3457 //
3458 if( vecLen == 1 ) // we know that vecLen > 0
3459 {
3460 i3 = 0;
3461 i4 = 1; // note that we will be adding a new secondary particle in this case only
3462 }
3463 else // otherwise 0 <= i3,i4 < vecLen
3464 {
3465 G4double ran = G4UniformRand();
3466 while( ran == 1.0 )ran = G4UniformRand();
3467 i4 = i3 = G4int( vecLen*ran );
3468 while( i3 == i4 )
3469 {
3470 ran = G4UniformRand();
3471 while( ran == 1.0 )ran = G4UniformRand();
3472 i4 = G4int( vecLen*ran );
3473 }
3474 }
3475 //
3476 // use linear interpolation or extrapolation by y=centerofmassEnergy*x+b
3477 //
3478 const G4double avkkb[] = { 0.0015, 0.005, 0.012, 0.0285, 0.0525, 0.075,
3479 0.0975, 0.123, 0.28, 0.398, 0.495, 0.573 };
3480 const G4double avky[] = { 0.005, 0.03, 0.064, 0.095, 0.115, 0.13,
3481 0.145, 0.155, 0.20, 0.205, 0.210, 0.212 };
3482 const G4double avnnb[] = { 0.00001, 0.0001, 0.0006, 0.0025, 0.01, 0.02,
3483 0.04, 0.05, 0.12, 0.15, 0.18, 0.20 };
3484
3485 avk = (std::log(avkkb[ibin])-std::log(avkkb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3486 /(avrs[ibin]-avrs[ibin-1]) + std::log(avkkb[ibin-1]);
3487 avk = std::exp(avk);
3488
3489 avy = (std::log(avky[ibin])-std::log(avky[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3490 /(avrs[ibin]-avrs[ibin-1]) + std::log(avky[ibin-1]);
3491 avy = std::exp(avy);
3492
3493 avn = (std::log(avnnb[ibin])-std::log(avnnb[ibin-1]))*(centerofmassEnergy-avrs[ibin-1])
3494 /(avrs[ibin]-avrs[ibin-1]) + std::log(avnnb[ibin-1]);
3495 avn = std::exp(avn);
3496
3497 if( avk+avy+avn <= 0.0 )return;
3498
3499 if( currentMass < protonMass )avy /= 2.0;
3500 if( targetMass < protonMass )avy = 0.0;
3501 avy += avk+avn;
3502 avk += avn;
3503 ran = G4UniformRand();
3504 if( ran < avn )
3505 {
3506 if( availableEnergy < 2.0 )return;
3507 if( vecLen == 1 ) // add a new secondary
3508 {
3509 G4ReactionProduct *p1 = new G4ReactionProduct;
3510 if( G4UniformRand() < 0.5 )
3511 {
3512 vec[0]->SetDefinition( aNeutron );
3513 p1->SetDefinition( anAntiNeutron );
3514 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3515 vec[0]->SetMayBeKilled(false);
3516 p1->SetMayBeKilled(false);
3517 }
3518 else
3519 {
3520 vec[0]->SetDefinition( aProton );
3521 p1->SetDefinition( anAntiProton );
3522 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3523 vec[0]->SetMayBeKilled(false);
3524 p1->SetMayBeKilled(false);
3525 }
3526 vec.SetElement( vecLen++, p1 );
3527 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3528 }
3529 else
3530 { // replace two secondaries
3531 if( G4UniformRand() < 0.5 )
3532 {
3533 vec[i3]->SetDefinition( aNeutron );
3534 vec[i4]->SetDefinition( anAntiNeutron );
3535 vec[i3]->SetMayBeKilled(false);
3536 vec[i4]->SetMayBeKilled(false);
3537 }
3538 else
3539 {
3540 vec[i3]->SetDefinition( aProton );
3541 vec[i4]->SetDefinition( anAntiProton );
3542 vec[i3]->SetMayBeKilled(false);
3543 vec[i4]->SetMayBeKilled(false);
3544 }
3545 }
3546 }
3547 else if( ran < avk )
3548 {
3549 if( availableEnergy < 1.0 )return;
3550
3551 const G4double kkb[] = { 0.2500, 0.3750, 0.5000, 0.5625, 0.6250,
3552 0.6875, 0.7500, 0.8750, 1.000 };
3553 const G4int ipakkb1[] = { 10, 10, 10, 11, 11, 12, 12, 11, 12 };
3554 const G4int ipakkb2[] = { 13, 11, 12, 11, 12, 11, 12, 13, 13 };
3555 ran = G4UniformRand();
3556 i = 0;
3557 while( (i<9) && (ran>=kkb[i]) )++i;
3558 if( i == 9 )return;
3559 //
3560 // ipakkb[] = { 10,13, 10,11, 10,12, 11,11, 11,12, 12,11, 12,12, 11,13, 12,13 };
3561 // charge + - + 0 + 0 0 0 0 0 0 0 0 0 0 - 0 -
3562 //
3563 switch( ipakkb1[i] )
3564 {
3565 case 10:
3566 vec[i3]->SetDefinition( aKaonPlus );
3567 vec[i3]->SetMayBeKilled(false);
3568 break;
3569 case 11:
3570 vec[i3]->SetDefinition( aKaonZS );
3571 vec[i3]->SetMayBeKilled(false);
3572 break;
3573 case 12:
3574 vec[i3]->SetDefinition( aKaonZL );
3575 vec[i3]->SetMayBeKilled(false);
3576 break;
3577 }
3578 if( vecLen == 1 ) // add a secondary
3579 {
3580 G4ReactionProduct *p1 = new G4ReactionProduct;
3581 switch( ipakkb2[i] )
3582 {
3583 case 11:
3584 p1->SetDefinition( aKaonZS );
3585 p1->SetMayBeKilled(false);
3586 break;
3587 case 12:
3588 p1->SetDefinition( aKaonZL );
3589 p1->SetMayBeKilled(false);
3590 break;
3591 case 13:
3592 p1->SetDefinition( aKaonMinus );
3593 p1->SetMayBeKilled(false);
3594 break;
3595 }
3596 (G4UniformRand() < 0.5) ? p1->SetSide( -1 ) : p1->SetSide( 1 );
3597 vec.SetElement( vecLen++, p1 );
3598 // DEBUGGING --> DumpFrames::DumpFrame(vec, vecLen);
3599 }
3600 else // replace
3601 {
3602 switch( ipakkb2[i] )
3603 {
3604 case 11:
3605 vec[i4]->SetDefinition( aKaonZS );
3606 vec[i4]->SetMayBeKilled(false);
3607 break;
3608 case 12:
3609 vec[i4]->SetDefinition( aKaonZL );
3610 vec[i4]->SetMayBeKilled(false);
3611 break;
3612 case 13:
3613 vec[i4]->SetDefinition( aKaonMinus );
3614 vec[i4]->SetMayBeKilled(false);
3615 break;
3616 }
3617 }
3618 }
3619 else if( ran < avy )
3620 {
3621 if( availableEnergy < 1.6 )return;
3622
3623 const G4double ky[] = { 0.200, 0.300, 0.400, 0.550, 0.625, 0.700,
3624 0.800, 0.850, 0.900, 0.950, 0.975, 1.000 };
3625 const G4int ipaky1[] = { 18, 18, 18, 20, 20, 20, 21, 21, 21, 22, 22, 22 };
3626 const G4int ipaky2[] = { 10, 11, 12, 10, 11, 12, 10, 11, 12, 10, 11, 12 };
3627 const G4int ipakyb1[] = { 19, 19, 19, 23, 23, 23, 24, 24, 24, 25, 25, 25 };
3628 const G4int ipakyb2[] = { 13, 12, 11, 13, 12, 11, 13, 12, 11, 13, 12, 11 };
3629 ran = G4UniformRand();
3630 i = 0;
3631 while( (i<12) && (ran>ky[i]) )++i;
3632 if( i == 12 )return;
3633 if( (currentMass<protonMass) || (G4UniformRand()<0.5) )
3634 {
3635 // ipaky[] = { 18,10, 18,11, 18,12, 20,10, 20,11, 20,12,
3636 // 0 + 0 0 0 0 + + + 0 + 0
3637 //
3638 // 21,10, 21,11, 21,12, 22,10, 22,11, 22,12 }
3639 // 0 + 0 0 0 0 - + - 0 - 0
3640 switch( ipaky1[i] )
3641 {
3642 case 18:
3643 targetParticle.SetDefinition( aLambda );
3644 break;
3645 case 20:
3646 targetParticle.SetDefinition( aSigmaPlus );
3647 break;
3648 case 21:
3649 targetParticle.SetDefinition( aSigmaZero );
3650 break;
3651 case 22:
3652 targetParticle.SetDefinition( aSigmaMinus );
3653 break;
3654 }
3655 targetHasChanged = true;
3656 switch( ipaky2[i] )
3657 {
3658 case 10:
3659 vec[i3]->SetDefinition( aKaonPlus );
3660 vec[i3]->SetMayBeKilled(false);
3661 break;
3662 case 11:
3663 vec[i3]->SetDefinition( aKaonZS );
3664 vec[i3]->SetMayBeKilled(false);
3665 break;
3666 case 12:
3667 vec[i3]->SetDefinition( aKaonZL );
3668 vec[i3]->SetMayBeKilled(false);
3669 break;
3670 }
3671 }
3672 else // (currentMass >= protonMass) && (G4UniformRand() >= 0.5)
3673 {
3674 // ipakyb[] = { 19,13, 19,12, 19,11, 23,13, 23,12, 23,11,
3675 // 24,13, 24,12, 24,11, 25,13, 25,12, 25,11 };
3676 if( (currentParticle.GetDefinition() == anAntiProton) ||
3677 (currentParticle.GetDefinition() == anAntiNeutron) ||
3678 (currentParticle.GetDefinition() == anAntiLambda) ||
3679 (currentMass > sigmaMinusMass) )
3680 {
3681 switch( ipakyb1[i] )
3682 {
3683 case 19:
3684 currentParticle.SetDefinitionAndUpdateE( anAntiLambda );
3685 break;
3686 case 23:
3687 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaPlus );
3688 break;
3689 case 24:
3690 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaZero );
3691 break;
3692 case 25:
3693 currentParticle.SetDefinitionAndUpdateE( anAntiSigmaMinus );
3694 break;
3695 }
3696 incidentHasChanged = true;
3697 switch( ipakyb2[i] )
3698 {
3699 case 11:
3700 vec[i3]->SetDefinition( aKaonZS );
3701 vec[i3]->SetMayBeKilled(false);
3702 break;
3703 case 12:
3704 vec[i3]->SetDefinition( aKaonZL );
3705 vec[i3]->SetMayBeKilled(false);
3706 break;
3707 case 13:
3708 vec[i3]->SetDefinition( aKaonMinus );
3709 vec[i3]->SetMayBeKilled(false);
3710 break;
3711 }
3712 }
3713 else
3714 {
3715 switch( ipaky1[i] )
3716 {
3717 case 18:
3718 currentParticle.SetDefinitionAndUpdateE( aLambda );
3719 break;
3720 case 20:
3721 currentParticle.SetDefinitionAndUpdateE( aSigmaPlus );
3722 break;
3723 case 21:
3724 currentParticle.SetDefinitionAndUpdateE( aSigmaZero );
3725 break;
3726 case 22:
3727 currentParticle.SetDefinitionAndUpdateE( aSigmaMinus );
3728 break;
3729 }
3730 incidentHasChanged = true;
3731 switch( ipaky2[i] )
3732 {
3733 case 10:
3734 vec[i3]->SetDefinition( aKaonPlus );
3735 vec[i3]->SetMayBeKilled(false);
3736 break;
3737 case 11:
3738 vec[i3]->SetDefinition( aKaonZS );
3739 vec[i3]->SetMayBeKilled(false);
3740 break;
3741 case 12:
3742 vec[i3]->SetDefinition( aKaonZL );
3743 vec[i3]->SetMayBeKilled(false);
3744 break;
3745 }
3746 }
3747 }
3748 }
3749 else return;
3750 //
3751 // check the available energy
3752 // if there is not enough energy for kkb/ky pair production
3753 // then reduce the number of secondary particles
3754 // NOTE:
3755 // the number of secondaries may have been changed
3756 // the incident and/or target particles may have changed
3757 // charge conservation is ignored (as well as strangness conservation)
3758 //
3759 currentMass = currentParticle.GetMass()/GeV;
3760 targetMass = targetParticle.GetMass()/GeV;
3761
3762 G4double energyCheck = centerofmassEnergy-(currentMass+targetMass);
3763 for( i=0; i<vecLen; ++i )
3764 {
3765 energyCheck -= vec[i]->GetMass()/GeV;
3766 if( energyCheck < 0.0 ) // chop off the secondary List
3767 {
3768 vecLen = std::max( 0, --i ); // looks like a memory leak @@@@@@@@@@@@
3769 G4int j;
3770 for(j=i; j<vecLen; j++) delete vec[j];
3771 break;
3772 }
3773 }
3774 return;
3775 }
3776
3777 void
3778 G4ReactionDynamics::NuclearReaction(
3779 G4FastVector<G4ReactionProduct,4> &vec,
3780 G4int &vecLen,
3781 const G4HadProjectile *originalIncident,
3782 const G4Nucleus &targetNucleus,
3783 const G4double theAtomicMass,
3784 const G4double *mass )
3785 {
3786 // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
3787 //
3788 // Nuclear reaction kinematics at low energies
3789 //
3790 G4ParticleDefinition *aGamma = G4Gamma::Gamma();
3791 G4ParticleDefinition *aProton = G4Proton::Proton();
3792 G4ParticleDefinition *aNeutron = G4Neutron::Neutron();
3793 G4ParticleDefinition *aDeuteron = G4Deuteron::Deuteron();
3794 G4ParticleDefinition *aTriton = G4Triton::Triton();
3795 G4ParticleDefinition *anAlpha = G4Alpha::Alpha();
3796
3797 const G4double aProtonMass = aProton->GetPDGMass()/MeV;
3798 const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
3799 const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
3800 const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
3801 const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
3802
3803 G4ReactionProduct currentParticle;
3804 currentParticle = *originalIncident;
3805 //
3806 // Set beam particle, take kinetic energy of current particle as the
3807 // fundamental quantity. Due to the difficult kinematic, all masses have to
3808 // be assigned the best measured values
3809 //
3810 G4double p = currentParticle.GetTotalMomentum();
3811 G4double pp = currentParticle.GetMomentum().mag();
3812 if( pp <= 0.001*MeV )
3813 {
3814 G4double phinve = twopi*G4UniformRand();
3815 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3816 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3817 p*std::sin(rthnve)*std::sin(phinve),
3818 p*std::cos(rthnve) );
3819 }
3820 else
3821 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3822 //
3823 // calculate Q-value of reactions
3824 //
3825 G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
3826 G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
3827 G4double qv = currentKinetic + theAtomicMass + currentMass;
3828
3829 G4double qval[9];
3830 qval[0] = qv - mass[0];
3831 qval[1] = qv - mass[1] - aNeutronMass;
3832 qval[2] = qv - mass[2] - aProtonMass;
3833 qval[3] = qv - mass[3] - aDeuteronMass;
3834 qval[4] = qv - mass[4] - aTritonMass;
3835 qval[5] = qv - mass[5] - anAlphaMass;
3836 qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
3837 qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
3838 qval[8] = qv - mass[8] - aProtonMass - aProtonMass;
3839
3840 if( currentParticle.GetDefinition() == aNeutron )
3841 {
3842 const G4double A = targetNucleus.GetN(); // atomic weight
3843 if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
3844 qval[0] = 0.0;
3845 if( G4UniformRand() >= currentKinetic/7.9254*A )
3846 qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
3847 }
3848 else
3849 qval[0] = 0.0;
3850
3851 G4int i;
3852 qv = 0.0;
3853 for( i=0; i<9; ++i )
3854 {
3855 if( mass[i] < 500.0*MeV )qval[i] = 0.0;
3856 if( qval[i] < 0.0 )qval[i] = 0.0;
3857 qv += qval[i];
3858 }
3859 G4double qv1 = 0.0;
3860 G4double ran = G4UniformRand();
3861 G4int index;
3862 for( index=0; index<9; ++index )
3863 {
3864 if( qval[index] > 0.0 )
3865 {
3866 qv1 += qval[index]/qv;
3867 if( ran <= qv1 )break;
3868 }
3869 }
3870 if( index == 9 ) // loop continued to the end
3871 {
3872 throw G4HadronicException(__FILE__, __LINE__,
3873 "G4ReactionDynamics::NuclearReaction: inelastic reaction kinematically not possible");
3874 }
3875 G4double ke = currentParticle.GetKineticEnergy()/GeV;
3876 G4int nt = 2;
3877 if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
3878
3879 G4ReactionProduct **v = new G4ReactionProduct * [3];
3880 v[0] = new G4ReactionProduct;
3881 v[1] = new G4ReactionProduct;
3882 v[2] = new G4ReactionProduct;
3883
3884 v[0]->SetMass( mass[index]*MeV );
3885 switch( index )
3886 {
3887 case 0:
3888 v[1]->SetDefinition( aGamma );
3889 v[2]->SetDefinition( aGamma );
3890 break;
3891 case 1:
3892 v[1]->SetDefinition( aNeutron );
3893 v[2]->SetDefinition( aGamma );
3894 break;
3895 case 2:
3896 v[1]->SetDefinition( aProton );
3897 v[2]->SetDefinition( aGamma );
3898 break;
3899 case 3:
3900 v[1]->SetDefinition( aDeuteron );
3901 v[2]->SetDefinition( aGamma );
3902 break;
3903 case 4:
3904 v[1]->SetDefinition( aTriton );
3905 v[2]->SetDefinition( aGamma );
3906 break;
3907 case 5:
3908 v[1]->SetDefinition( anAlpha );
3909 v[2]->SetDefinition( aGamma );
3910 break;
3911 case 6:
3912 v[1]->SetDefinition( aNeutron );
3913 v[2]->SetDefinition( aNeutron );
3914 break;
3915 case 7:
3916 v[1]->SetDefinition( aNeutron );
3917 v[2]->SetDefinition( aProton );
3918 break;
3919 case 8:
3920 v[1]->SetDefinition( aProton );
3921 v[2]->SetDefinition( aProton );
3922 break;
3923 }
3924 //
3925 // calculate centre of mass energy
3926 //
3927 G4ReactionProduct pseudo1;
3928 pseudo1.SetMass( theAtomicMass*MeV );
3929 pseudo1.SetTotalEnergy( theAtomicMass*MeV );
3930 G4ReactionProduct pseudo2 = currentParticle + pseudo1;
3931 pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
3932 //
3933 // use phase space routine in centre of mass system
3934 //
3935 G4FastVector<G4ReactionProduct,GHADLISTSIZE> tempV;
3936 tempV.Initialize( nt );
3937 G4int tempLen = 0;
3938 tempV.SetElement( tempLen++, v[0] );
3939 tempV.SetElement( tempLen++, v[1] );
3940 if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
3941 G4bool constantCrossSection = true;
3942 GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
3943 v[0]->Lorentz( *v[0], pseudo2 );
3944 v[1]->Lorentz( *v[1], pseudo2 );
3945 if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
3946
3947 G4bool particleIsDefined = false;
3948 if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
3949 {
3950 v[0]->SetDefinition( aProton );
3951 particleIsDefined = true;
3952 }
3953 else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
3954 {
3955 v[0]->SetDefinition( aNeutron );
3956 particleIsDefined = true;
3957 }
3958 else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
3959 {
3960 v[0]->SetDefinition( aDeuteron );
3961 particleIsDefined = true;
3962 }
3963 else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
3964 {
3965 v[0]->SetDefinition( aTriton );
3966 particleIsDefined = true;
3967 }
3968 else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
3969 {
3970 v[0]->SetDefinition( anAlpha );
3971 particleIsDefined = true;
3972 }
3973 currentParticle.SetKineticEnergy(
3974 std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
3975 p = currentParticle.GetTotalMomentum();
3976 pp = currentParticle.GetMomentum().mag();
3977 if( pp <= 0.001*MeV )
3978 {
3979 G4double phinve = twopi*G4UniformRand();
3980 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
3981 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3982 p*std::sin(rthnve)*std::sin(phinve),
3983 p*std::cos(rthnve) );
3984 }
3985 else
3986 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
3987
3988 if( particleIsDefined )
3989 {
3990 v[0]->SetKineticEnergy(
3991 std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
3992 p = v[0]->GetTotalMomentum();
3993 pp = v[0]->GetMomentum().mag();
3994 if( pp <= 0.001*MeV )
3995 {
3996 G4double phinve = twopi*G4UniformRand();
3997 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
3998 v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
3999 p*std::sin(rthnve)*std::sin(phinve),
4000 p*std::cos(rthnve) );
4001 }
4002 else
4003 v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
4004 }
4005 if( (v[1]->GetDefinition() == aDeuteron) ||
4006 (v[1]->GetDefinition() == aTriton) ||
4007 (v[1]->GetDefinition() == anAlpha) )
4008 v[1]->SetKineticEnergy(
4009 std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
4010 else
4011 v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
4012
4013 p = v[1]->GetTotalMomentum();
4014 pp = v[1]->GetMomentum().mag();
4015 if( pp <= 0.001*MeV )
4016 {
4017 G4double phinve = twopi*G4UniformRand();
4018 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4019 v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4020 p*std::sin(rthnve)*std::sin(phinve),
4021 p*std::cos(rthnve) );
4022 }
4023 else
4024 v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
4025
4026 if( nt == 3 )
4027 {
4028 if( (v[2]->GetDefinition() == aDeuteron) ||
4029 (v[2]->GetDefinition() == aTriton) ||
4030 (v[2]->GetDefinition() == anAlpha) )
4031 v[2]->SetKineticEnergy(
4032 std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
4033 else
4034 v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
4035
4036 p = v[2]->GetTotalMomentum();
4037 pp = v[2]->GetMomentum().mag();
4038 if( pp <= 0.001*MeV )
4039 {
4040 G4double phinve = twopi*G4UniformRand();
4041 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
4042 v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
4043 p*std::sin(rthnve)*std::sin(phinve),
4044 p*std::cos(rthnve) );
4045 }
4046 else
4047 v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
4048 }
4049 G4int del;
4050 for(del=0; del<vecLen; del++) delete vec[del];
4051 vecLen = 0;
4052 if( particleIsDefined )
4053 {
4054 vec.SetElement( vecLen++, v[0] );
4055 }
4056 else
4057 {
4058 delete v[0];
4059 }
4060 vec.SetElement( vecLen++, v[1] );
4061 if( nt == 3 )
4062 {
4063 vec.SetElement( vecLen++, v[2] );
4064 }
4065 else
4066 {
4067 delete v[2];
4068 }
4069 delete [] v;
4070 return;
4071 }
4072
4073 /* end of file */
4074
Note: See TracBrowser for help on using the repository browser.