Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4RPGReaction.cc
Go to the documentation of this file.
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// $Id$
27//
28
29#include <iostream>
30
31#include "G4RPGReaction.hh"
33#include "G4SystemOfUnits.hh"
34#include "Randomize.hh"
35
37ReactionStage(const G4HadProjectile* /*originalIncident*/,
38 G4ReactionProduct& /*modifiedOriginal*/,
39 G4bool& /*incidentHasChanged*/,
40 const G4DynamicParticle* /*originalTarget*/,
41 G4ReactionProduct& /*targetParticle*/,
42 G4bool& /*targetHasChanged*/,
43 const G4Nucleus& /*targetNucleus*/,
44 G4ReactionProduct& /*currentParticle*/,
46 G4int& /*vecLen*/,
47 G4bool /*leadFlag*/,
48 G4ReactionProduct& /*leadingStrangeParticle*/)
49{
50 G4cout << " G4RPGReactionStage must be overridden in a derived class "
51 << G4endl;
52 return false;
53}
54
55
57AddBlackTrackParticles(const G4double epnb, // GeV
58 const G4int npnb,
59 const G4double edta, // GeV
60 const G4int ndta,
61 const G4ReactionProduct& modifiedOriginal,
62 G4int PinNucleus,
63 G4int NinNucleus,
64 const G4Nucleus& targetNucleus,
66 G4int& vecLen)
67{
68 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
69 //
70 // npnb is number of proton/neutron black track particles
71 // ndta is the number of deuterons, tritons, and alphas produced
72 // epnb is the kinetic energy available for proton/neutron black track particles
73 // edta is the kinetic energy available for deuteron/triton/alpha particles
74
80
81 const G4double ekOriginal = modifiedOriginal.GetKineticEnergy()/MeV;
82 const G4double atomicWeight = targetNucleus.GetA_asInt();
83 const G4double atomicNumber = targetNucleus.GetZ_asInt();
84
85 const G4double ika1 = 3.6;
86 const G4double ika2 = 35.56;
87 const G4double ika3 = 6.45;
88
89 G4int i;
90 G4double pp;
91 G4double kinetic = 0;
92 G4double kinCreated = 0;
93 // G4double cfa = 0.025*((atomicWeight-1.0)/120.0) * std::exp(-(atomicWeight-1.0)/120.0);
94 G4double remainingE = 0;
95
96 // First add protons and neutrons to final state
97 if (npnb > 0) {
98 // G4double backwardKinetic = 0.0;
99 G4int local_npnb = npnb;
100 // DHW: does not conserve energy for (i = 0; i < npnb; ++i) if (G4UniformRand() < sprob) local_npnb--;
101 local_npnb = std::min(PinNucleus + NinNucleus , local_npnb);
102 G4double local_epnb = epnb;
103 if (ndta == 0) local_epnb += edta; // Retrieve unused kinetic energy
104 // G4double ekin = local_epnb/std::max(1,local_npnb);
105
106 remainingE = local_epnb;
107 for (i = 0; i < local_npnb; ++i)
108 {
110 // if( backwardKinetic > local_epnb ) {
111 // delete p1;
112 // break;
113 // }
114
115 // G4double ran = G4UniformRand();
116 // G4double kinetic = -ekin*std::log(ran) - cfa*(1.0+0.5*normal());
117 // if( kinetic < 0.0 )kinetic = -0.010*std::log(ran);
118 // backwardKinetic += kinetic;
119 // if( backwardKinetic > local_epnb )
120 // kinetic = std::max( kineticMinimum, local_epnb-(backwardKinetic-kinetic) );
121
122 if (G4UniformRand() > (1.0-atomicNumber/atomicWeight)) {
123
124 // Boil off a proton if there are any left, otherwise a neutron
125
126 if (PinNucleus > 0) {
127 p1->SetDefinition( aProton );
128 PinNucleus--;
129 } else {
130 p1->SetDefinition( aNeutron );
131 NinNucleus--;
132 // } else {
133 // delete p1;
134 // break; // no nucleons left in nucleus
135 }
136 } else {
137
138 // Boil off a neutron if there are any left, otherwise a proton
139
140 if (NinNucleus > 0) {
141 p1->SetDefinition( aNeutron );
142 NinNucleus--;
143 } else {
144 p1->SetDefinition( aProton );
145 PinNucleus--;
146 // } else {
147 // delete p1;
148 // break; // no nucleons left in nucleus
149 }
150 }
151
152 if (i < local_npnb - 1) {
153 kinetic = remainingE*G4UniformRand();
154 remainingE -= kinetic;
155 } else {
156 kinetic = remainingE;
157 }
158
159 vec.SetElement( vecLen, p1 );
160 G4double cost = G4UniformRand() * 2.0 - 1.0;
161 G4double sint = std::sqrt(std::fabs(1.0-cost*cost));
162 G4double phi = twopi * G4UniformRand();
163 vec[vecLen]->SetNewlyAdded( true );
164 vec[vecLen]->SetKineticEnergy( kinetic*GeV );
165 kinCreated+=kinetic;
166 pp = vec[vecLen]->GetTotalMomentum();
167 vec[vecLen]->SetMomentum(pp*sint*std::sin(phi),
168 pp*sint*std::cos(phi),
169 pp*cost );
170 vecLen++;
171 }
172
173 if (NinNucleus > 0) {
174 if( (atomicWeight >= 10.0) && (ekOriginal <= 2.0*GeV) )
175 {
176 G4double ekw = ekOriginal/GeV;
177 G4int ika, kk = 0;
178 if( ekw > 1.0 )ekw *= ekw;
179 ekw = std::max( 0.1, ekw );
180 ika = G4int(ika1*std::exp((atomicNumber*atomicNumber/
181 atomicWeight-ika2)/ika3)/ekw);
182 if( ika > 0 )
183 {
184 for( i=(vecLen-1); i>=0; --i )
185 {
186 if( (vec[i]->GetDefinition() == aProton) && vec[i]->GetNewlyAdded() )
187 {
188 vec[i]->SetDefinitionAndUpdateE( aNeutron ); // modified 22-Oct-97
189 PinNucleus++;
190 NinNucleus--;
191 if( ++kk > ika )break;
192 }
193 }
194 }
195 }
196 } // if (NinNucleus >0)
197 } // if (npnb > 0)
198
199 // Next try to add deuterons, tritons and alphas to final state
200
201 G4double ran = 0;
202 if (ndta > 0) {
203 // G4double backwardKinetic = 0.0;
204 G4int local_ndta=ndta;
205 // DHW: does not conserve energy for (i = 0; i < ndta; ++i) if (G4UniformRand() < sprob) local_ndta--;
206 G4double local_edta = edta;
207 if (npnb == 0) local_edta += epnb; // Retrieve unused kinetic energy
208 // G4double ekin = local_edta/std::max(1,local_ndta);
209
210 remainingE = local_edta;
211 for (i = 0; i < local_ndta; ++i) {
213 // if( backwardKinetic > local_edta ) {
214 // delete p2;
215 // break;
216 // }
217
218 // G4double ran = G4UniformRand();
219 // G4double kinetic = -ekin*std::log(ran)-cfa*(1.+0.5*normal());
220 // if( kinetic < 0.0 )kinetic = kineticFactor*std::log(ran);
221 // backwardKinetic += kinetic;
222 // if( backwardKinetic > local_edta )kinetic = local_edta-(backwardKinetic-kinetic);
223 // if( kinetic < 0.0 )kinetic = kineticMinimum;
224
225 ran = G4UniformRand();
226 if (ran < 0.60) {
227 if (PinNucleus > 0 && NinNucleus > 0) {
228 p2->SetDefinition( aDeuteron );
229 PinNucleus--;
230 NinNucleus--;
231 } else if (NinNucleus > 0) {
232 p2->SetDefinition( aNeutron );
233 NinNucleus--;
234 } else if (PinNucleus > 0) {
235 p2->SetDefinition( aProton );
236 PinNucleus--;
237 } else {
238 delete p2;
239 break;
240 }
241 } else if (ran < 0.90) {
242 if (PinNucleus > 0 && NinNucleus > 1) {
243 p2->SetDefinition( aTriton );
244 PinNucleus--;
245 NinNucleus -= 2;
246 } else if (PinNucleus > 0 && NinNucleus > 0) {
247 p2->SetDefinition( aDeuteron );
248 PinNucleus--;
249 NinNucleus--;
250 } else if (NinNucleus > 0) {
251 p2->SetDefinition( aNeutron );
252 NinNucleus--;
253 } else if (PinNucleus > 0) {
254 p2->SetDefinition( aProton );
255 PinNucleus--;
256 } else {
257 delete p2;
258 break;
259 }
260 } else {
261 if (PinNucleus > 1 && NinNucleus > 1) {
262 p2->SetDefinition( anAlpha );
263 PinNucleus -= 2;
264 NinNucleus -= 2;
265 } else if (PinNucleus > 0 && NinNucleus > 1) {
266 p2->SetDefinition( aTriton );
267 PinNucleus--;
268 NinNucleus -= 2;
269 } else if (PinNucleus > 0 && NinNucleus > 0) {
270 p2->SetDefinition( aDeuteron );
271 PinNucleus--;
272 NinNucleus--;
273 } else if (NinNucleus > 0) {
274 p2->SetDefinition( aNeutron );
275 NinNucleus--;
276 } else if (PinNucleus > 0) {
277 p2->SetDefinition( aProton );
278 PinNucleus--;
279 } else {
280 delete p2;
281 break;
282 }
283 }
284
285 if (i < local_ndta - 1) {
286 kinetic = remainingE*G4UniformRand();
287 remainingE -= kinetic;
288 } else {
289 kinetic = remainingE;
290 }
291
292 vec.SetElement( vecLen, p2 );
293 G4double cost = 2.0*G4UniformRand() - 1.0;
294 G4double sint = std::sqrt(std::max(0.0,(1.0-cost*cost)));
295 G4double phi = twopi*G4UniformRand();
296 vec[vecLen]->SetNewlyAdded( true );
297 vec[vecLen]->SetKineticEnergy( kinetic*GeV );
298 kinCreated+=kinetic;
299
300 pp = vec[vecLen]->GetTotalMomentum();
301 vec[vecLen]->SetMomentum( pp*sint*std::sin(phi),
302 pp*sint*std::cos(phi),
303 pp*cost );
304 vecLen++;
305 }
306 } // if (ndta > 0)
307}
308
309
312 const G4bool constantCrossSection,
314 G4int &vecLen)
315{
316 G4int i;
317 const G4double expxu = 82.; // upper bound for arg. of exp
318 const G4double expxl = -expxu; // lower bound for arg. of exp
319
320 if (vecLen < 2) {
321 G4cerr << "*** Error in G4RPGReaction::GenerateNBodyEvent" << G4endl;
322 G4cerr << " number of particles < 2" << G4endl;
323 G4cerr << "totalEnergy = " << totalEnergy << "MeV, vecLen = " << vecLen << G4endl;
324 return -1.0;
325 }
326
327 G4double mass[18]; // mass of each particle
328 G4double energy[18]; // total energy of each particle
329 G4double pcm[3][18]; // pcm is an array with 3 rows and vecLen columns
330
331 G4double totalMass = 0.0;
332 G4double extraMass = 0;
333 G4double sm[18];
334
335 for (i=0; i<vecLen; ++i) {
336 mass[i] = vec[i]->GetMass()/GeV;
337 if(vec[i]->GetSide() == -2) extraMass+=vec[i]->GetMass()/GeV;
338 vec[i]->SetMomentum( 0.0, 0.0, 0.0 );
339 pcm[0][i] = 0.0; // x-momentum of i-th particle
340 pcm[1][i] = 0.0; // y-momentum of i-th particle
341 pcm[2][i] = 0.0; // z-momentum of i-th particle
342 energy[i] = mass[i]; // total energy of i-th particle
343 totalMass += mass[i];
344 sm[i] = totalMass;
345 }
346
347 G4double totalE = totalEnergy/GeV;
348 if (totalMass > totalE) {
349 //G4cerr << "*** Error in G4RPGReaction::GenerateNBodyEvent" << G4endl;
350 //G4cerr << " total mass (" << totalMass*GeV << "MeV) > total energy ("
351 // << totalEnergy << "MeV)" << G4endl;
352 totalE = totalMass;
353 return -1.0;
354 }
355
356 G4double kineticEnergy = totalE - totalMass;
357 G4double emm[18];
358 emm[0] = mass[0];
359 emm[vecLen-1] = totalE;
360
361 if (vecLen > 2) { // the random numbers are sorted
362 G4double ran[18];
363 for( i=0; i<vecLen; ++i )ran[i] = G4UniformRand();
364 for (i=0; i<vecLen-2; ++i) {
365 for (G4int j=vecLen-2; j>i; --j) {
366 if (ran[i] > ran[j]) {
367 G4double temp = ran[i];
368 ran[i] = ran[j];
369 ran[j] = temp;
370 }
371 }
372 }
373 for( i=1; i<vecLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
374 }
375
376 // Weight is the sum of logarithms of terms instead of the product of terms
377
378 G4bool lzero = true;
379 G4double wtmax = 0.0;
380 if (constantCrossSection) {
381 G4double emmax = kineticEnergy + mass[0];
382 G4double emmin = 0.0;
383 for( i=1; i<vecLen; ++i )
384 {
385 emmin += mass[i-1];
386 emmax += mass[i];
387 G4double wtfc = 0.0;
388 if( emmax*emmax > 0.0 )
389 {
390 G4double arg = emmax*emmax
391 + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
392 - 2.0*(emmin*emmin+mass[i]*mass[i]);
393 if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
394 }
395 if( wtfc == 0.0 )
396 {
397 lzero = false;
398 break;
399 }
400 wtmax += std::log( wtfc );
401 }
402 if( lzero )
403 wtmax = -wtmax;
404 else
405 wtmax = expxu;
406 } else {
407 // ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
408 const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
409 256.3704, 268.4705, 240.9780, 189.2637,
410 132.1308, 83.0202, 47.4210, 24.8295,
411 12.0006, 5.3858, 2.2560, 0.8859 };
412 wtmax = std::log( std::pow( kineticEnergy, vecLen-2 ) * ffq[vecLen-1] / totalE );
413 }
414
415 // Calculate momenta for secondaries
416
417 lzero = true;
418 G4double pd[50];
419
420 for( i=0; i<vecLen-1; ++i )
421 {
422 pd[i] = 0.0;
423 if( emm[i+1]*emm[i+1] > 0.0 )
424 {
425 G4double arg = emm[i+1]*emm[i+1]
426 + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
427 /(emm[i+1]*emm[i+1])
428 - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
429 if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
430 }
431 if( pd[i] <= 0.0 ) // changed from == on 02 April 98
432 lzero = false;
433 else
434 wtmax += std::log( pd[i] );
435 }
436 G4double weight = 0.0; // weight is returned by GenerateNBodyEvent
437 if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
438
439 G4double bang, cb, sb, s0, s1, s2, c, esys, a, b, gama, beta;
440 G4double ss;
441 pcm[0][0] = 0.0;
442 pcm[1][0] = pd[0];
443 pcm[2][0] = 0.0;
444 for( i=1; i<vecLen; ++i )
445 {
446 pcm[0][i] = 0.0;
447 pcm[1][i] = -pd[i-1];
448 pcm[2][i] = 0.0;
449 bang = twopi*G4UniformRand();
450 cb = std::cos(bang);
451 sb = std::sin(bang);
452 c = 2.0*G4UniformRand() - 1.0;
453 ss = std::sqrt( std::fabs( 1.0-c*c ) );
454 if( i < vecLen-1 )
455 {
456 esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
457 beta = pd[i]/esys;
458 gama = esys/emm[i];
459 for( G4int j=0; j<=i; ++j )
460 {
461 s0 = pcm[0][j];
462 s1 = pcm[1][j];
463 s2 = pcm[2][j];
464 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
465 a = s0*c - s1*ss; // rotation
466 pcm[1][j] = s0*ss + s1*c;
467 b = pcm[2][j];
468 pcm[0][j] = a*cb - b*sb;
469 pcm[2][j] = a*sb + b*cb;
470 pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
471 }
472 }
473 else
474 {
475 for( G4int j=0; j<=i; ++j )
476 {
477 s0 = pcm[0][j];
478 s1 = pcm[1][j];
479 s2 = pcm[2][j];
480 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
481 a = s0*c - s1*s; // rotation
482 pcm[1][j] = s0*ss + s1*c;
483 b = pcm[2][j];
484 pcm[0][j] = a*cb - b*sb;
485 pcm[2][j] = a*sb + b*cb;
486 }
487 }
488 }
489
490 for (i=0; i<vecLen; ++i) {
491 vec[i]->SetMomentum( pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV );
492 vec[i]->SetTotalEnergy( energy[i]*GeV );
493 }
494
495 return weight;
496}
497
498
501 const G4bool constantCrossSection,
502 std::vector<G4ReactionProduct*>& tempList)
503{
504 G4int i;
505 const G4double expxu = 82.; // upper bound for arg. of exp
506 const G4double expxl = -expxu; // lower bound for arg. of exp
507 G4int listLen = tempList.size();
508
509 if (listLen < 2) {
510 G4cerr << "*** Error in G4RPGReaction::GenerateNBodyEvent" << G4endl;
511 G4cerr << " number of particles < 2" << G4endl;
512 G4cerr << "totalEnergy = " << totalEnergy << "MeV, listLen = " << listLen << G4endl;
513 return -1.0;
514 }
515
516 G4double mass[18]; // mass of each particle
517 G4double energy[18]; // total energy of each particle
518 G4double pcm[3][18]; // pcm is an array with 3 rows and listLen columns
519
520 G4double totalMass = 0.0;
521 G4double extraMass = 0;
522 G4double sm[18];
523
524 for (i=0; i<listLen; ++i) {
525 mass[i] = tempList[i]->GetMass()/GeV;
526 if(tempList[i]->GetSide() == -2) extraMass+=tempList[i]->GetMass()/GeV;
527 tempList[i]->SetMomentum( 0.0, 0.0, 0.0 );
528 pcm[0][i] = 0.0; // x-momentum of i-th particle
529 pcm[1][i] = 0.0; // y-momentum of i-th particle
530 pcm[2][i] = 0.0; // z-momentum of i-th particle
531 energy[i] = mass[i]; // total energy of i-th particle
532 totalMass += mass[i];
533 sm[i] = totalMass;
534 }
535
536 G4double totalE = totalEnergy/GeV;
537 if (totalMass > totalE) {
538 totalE = totalMass;
539 return -1.0;
540 }
541
542 G4double kineticEnergy = totalE - totalMass;
543 G4double emm[18];
544 emm[0] = mass[0];
545 emm[listLen-1] = totalE;
546
547 if (listLen > 2) { // the random numbers are sorted
548 G4double ran[18];
549 for( i=0; i<listLen; ++i )ran[i] = G4UniformRand();
550 for (i=0; i<listLen-2; ++i) {
551 for (G4int j=listLen-2; j>i; --j) {
552 if (ran[i] > ran[j]) {
553 G4double temp = ran[i];
554 ran[i] = ran[j];
555 ran[j] = temp;
556 }
557 }
558 }
559 for( i=1; i<listLen-1; ++i )emm[i] = ran[i-1]*kineticEnergy + sm[i];
560 }
561
562 // Weight is the sum of logarithms of terms instead of the product of terms
563
564 G4bool lzero = true;
565 G4double wtmax = 0.0;
566 if (constantCrossSection) {
567 G4double emmax = kineticEnergy + mass[0];
568 G4double emmin = 0.0;
569 for( i=1; i<listLen; ++i )
570 {
571 emmin += mass[i-1];
572 emmax += mass[i];
573 G4double wtfc = 0.0;
574 if( emmax*emmax > 0.0 )
575 {
576 G4double arg = emmax*emmax
577 + (emmin*emmin-mass[i]*mass[i])*(emmin*emmin-mass[i]*mass[i])/(emmax*emmax)
578 - 2.0*(emmin*emmin+mass[i]*mass[i]);
579 if( arg > 0.0 )wtfc = 0.5*std::sqrt( arg );
580 }
581 if( wtfc == 0.0 )
582 {
583 lzero = false;
584 break;
585 }
586 wtmax += std::log( wtfc );
587 }
588 if( lzero )
589 wtmax = -wtmax;
590 else
591 wtmax = expxu;
592 } else {
593 // ffq(n) = pi*(2*pi)^(n-2)/(n-2)!
594 const G4double ffq[18] = { 0., 3.141592, 19.73921, 62.01255, 129.8788, 204.0131,
595 256.3704, 268.4705, 240.9780, 189.2637,
596 132.1308, 83.0202, 47.4210, 24.8295,
597 12.0006, 5.3858, 2.2560, 0.8859 };
598 wtmax = std::log( std::pow( kineticEnergy, listLen-2 ) * ffq[listLen-1] / totalE );
599 }
600
601 // Calculate momenta for secondaries
602
603 lzero = true;
604 G4double pd[50];
605
606 for( i=0; i<listLen-1; ++i )
607 {
608 pd[i] = 0.0;
609 if( emm[i+1]*emm[i+1] > 0.0 )
610 {
611 G4double arg = emm[i+1]*emm[i+1]
612 + (emm[i]*emm[i]-mass[i+1]*mass[i+1])*(emm[i]*emm[i]-mass[i+1]*mass[i+1])
613 /(emm[i+1]*emm[i+1])
614 - 2.0*(emm[i]*emm[i]+mass[i+1]*mass[i+1]);
615 if( arg > 0.0 )pd[i] = 0.5*std::sqrt( arg );
616 }
617 if( pd[i] <= 0.0 ) // changed from == on 02 April 98
618 lzero = false;
619 else
620 wtmax += std::log( pd[i] );
621 }
622 G4double weight = 0.0; // weight is returned by GenerateNBodyEvent
623 if( lzero )weight = std::exp( std::max(std::min(wtmax,expxu),expxl) );
624
625 G4double bang, cb, sb, s0, s1, s2, c, esys, a, b, gama, beta;
626 G4double ss;
627 pcm[0][0] = 0.0;
628 pcm[1][0] = pd[0];
629 pcm[2][0] = 0.0;
630 for( i=1; i<listLen; ++i )
631 {
632 pcm[0][i] = 0.0;
633 pcm[1][i] = -pd[i-1];
634 pcm[2][i] = 0.0;
635 bang = twopi*G4UniformRand();
636 cb = std::cos(bang);
637 sb = std::sin(bang);
638 c = 2.0*G4UniformRand() - 1.0;
639 ss = std::sqrt( std::fabs( 1.0-c*c ) );
640 if( i < listLen-1 )
641 {
642 esys = std::sqrt(pd[i]*pd[i] + emm[i]*emm[i]);
643 beta = pd[i]/esys;
644 gama = esys/emm[i];
645 for( G4int j=0; j<=i; ++j )
646 {
647 s0 = pcm[0][j];
648 s1 = pcm[1][j];
649 s2 = pcm[2][j];
650 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
651 a = s0*c - s1*ss; // rotation
652 pcm[1][j] = s0*ss + s1*c;
653 b = pcm[2][j];
654 pcm[0][j] = a*cb - b*sb;
655 pcm[2][j] = a*sb + b*cb;
656 pcm[1][j] = gama*(pcm[1][j] + beta*energy[j]);
657 }
658 }
659 else
660 {
661 for( G4int j=0; j<=i; ++j )
662 {
663 s0 = pcm[0][j];
664 s1 = pcm[1][j];
665 s2 = pcm[2][j];
666 energy[j] = std::sqrt( s0*s0 + s1*s1 + s2*s2 + mass[j]*mass[j] );
667 a = s0*c - s1*ss; // rotation
668 pcm[1][j] = s0*ss + s1*c;
669 b = pcm[2][j];
670 pcm[0][j] = a*cb - b*sb;
671 pcm[2][j] = a*sb + b*cb;
672 }
673 }
674 }
675
676 for (i=0; i<listLen; ++i) {
677 tempList[i]->SetMomentum(pcm[0][i]*GeV, pcm[1][i]*GeV, pcm[2][i]*GeV);
678 tempList[i]->SetTotalEnergy(energy[i]*GeV);
679 }
680
681 return weight;
682}
683
684
686{
687 G4double ran = -6.0;
688 for( G4int i=0; i<12; ++i )ran += G4UniformRand();
689 return ran;
690}
691
692
693void G4RPGReaction::Defs1(const G4ReactionProduct& modifiedOriginal,
694 G4ReactionProduct& currentParticle,
695 G4ReactionProduct& targetParticle,
697 G4int& vecLen)
698{
699 // Rotate final state particle momenta by initial particle direction
700
701 const G4double pjx = modifiedOriginal.GetMomentum().x()/MeV;
702 const G4double pjy = modifiedOriginal.GetMomentum().y()/MeV;
703 const G4double pjz = modifiedOriginal.GetMomentum().z()/MeV;
704 const G4double p = modifiedOriginal.GetMomentum().mag()/MeV;
705
706 if (pjx*pjx+pjy*pjy > 0.0) {
707 G4double cost, sint, ph, cosp, sinp, pix, piy, piz;
708 cost = pjz/p;
709 sint = std::sqrt(std::abs((1.0-cost)*(1.0+cost)));
710 if( pjy < 0.0 )
711 ph = 3*halfpi;
712 else
713 ph = halfpi;
714 if( std::abs( pjx ) > 0.001*MeV )ph = std::atan2(pjy,pjx);
715 cosp = std::cos(ph);
716 sinp = std::sin(ph);
717 pix = currentParticle.GetMomentum().x()/MeV;
718 piy = currentParticle.GetMomentum().y()/MeV;
719 piz = currentParticle.GetMomentum().z()/MeV;
720 currentParticle.SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
721 (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
722 (-sint*pix + cost*piz)*MeV);
723 pix = targetParticle.GetMomentum().x()/MeV;
724 piy = targetParticle.GetMomentum().y()/MeV;
725 piz = targetParticle.GetMomentum().z()/MeV;
726 targetParticle.SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
727 (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
728 (-sint*pix + cost*piz)*MeV);
729
730 for (G4int i=0; i<vecLen; ++i) {
731 pix = vec[i]->GetMomentum().x()/MeV;
732 piy = vec[i]->GetMomentum().y()/MeV;
733 piz = vec[i]->GetMomentum().z()/MeV;
734 vec[i]->SetMomentum((cost*cosp*pix - sinp*piy + sint*cosp*piz)*MeV,
735 (cost*sinp*pix + cosp*piy + sint*sinp*piz)*MeV,
736 (-sint*pix + cost*piz)*MeV);
737 }
738
739 } else {
740 if (pjz < 0.0) {
741 currentParticle.SetMomentum( -currentParticle.GetMomentum().z() );
742 targetParticle.SetMomentum( -targetParticle.GetMomentum().z() );
743 for (G4int i=0; i<vecLen; ++i) vec[i]->SetMomentum( -vec[i]->GetMomentum().z() );
744 }
745 }
746}
747
748
750 const G4double numberofFinalStateNucleons,
751 const G4ThreeVector &temp,
752 const G4ReactionProduct &modifiedOriginal, // Fermi motion & evap. effect included
753 const G4HadProjectile *originalIncident, // original incident particle
754 const G4Nucleus &targetNucleus,
755 G4ReactionProduct &currentParticle,
756 G4ReactionProduct &targetParticle,
758 G4int &vecLen )
759 {
760 // derived from original FORTRAN code in GENXPT and TWOCLU by H. Fesefeldt
761 //
762 // Rotate in direction of z-axis, this does disturb in some way our
763 // inclusive distributions, but it is necessary for momentum conservation
764 //
765 const G4double atomicWeight = targetNucleus.GetA_asInt();
766 const G4double logWeight = std::log(atomicWeight);
767
771
772 G4int i;
773 G4ThreeVector pseudoParticle[4];
774 for( i=0; i<4; ++i )pseudoParticle[i].set(0,0,0);
775 pseudoParticle[0] = currentParticle.GetMomentum()
776 + targetParticle.GetMomentum();
777 for( i=0; i<vecLen; ++i )
778 pseudoParticle[0] = pseudoParticle[0] + (vec[i]->GetMomentum());
779 //
780 // Some smearing in transverse direction from Fermi motion
781 //
782 G4float pp, pp1;
783 G4double alekw, p;
784 G4double r1, r2, a1, ran1, ran2, xxh, exh, pxTemp, pyTemp, pzTemp;
785
786 r1 = twopi*G4UniformRand();
787 r2 = G4UniformRand();
788 a1 = std::sqrt(-2.0*std::log(r2));
789 ran1 = a1*std::sin(r1)*0.020*numberofFinalStateNucleons*GeV;
790 ran2 = a1*std::cos(r1)*0.020*numberofFinalStateNucleons*GeV;
791 G4ThreeVector fermir(ran1, ran2, 0);
792
793 pseudoParticle[0] = pseudoParticle[0]+fermir; // all particles + fermir
794 pseudoParticle[2] = temp; // original in cms system
795 pseudoParticle[3] = pseudoParticle[0];
796
797 pseudoParticle[1] = pseudoParticle[2].cross(pseudoParticle[3]);
798 G4double rotation = 2.*pi*G4UniformRand();
799 pseudoParticle[1] = pseudoParticle[1].rotate(rotation, pseudoParticle[3]);
800 pseudoParticle[2] = pseudoParticle[3].cross(pseudoParticle[1]);
801 for(G4int ii=1; ii<=3; ii++)
802 {
803 p = pseudoParticle[ii].mag();
804 if( p == 0.0 )
805 pseudoParticle[ii]= G4ThreeVector( 0.0, 0.0, 0.0 );
806 else
807 pseudoParticle[ii]= pseudoParticle[ii] * (1./p);
808 }
809
810 pxTemp = pseudoParticle[1].dot(currentParticle.GetMomentum());
811 pyTemp = pseudoParticle[2].dot(currentParticle.GetMomentum());
812 pzTemp = pseudoParticle[3].dot(currentParticle.GetMomentum());
813 currentParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
814
815 pxTemp = pseudoParticle[1].dot(targetParticle.GetMomentum());
816 pyTemp = pseudoParticle[2].dot(targetParticle.GetMomentum());
817 pzTemp = pseudoParticle[3].dot(targetParticle.GetMomentum());
818 targetParticle.SetMomentum( pxTemp, pyTemp, pzTemp );
819
820 for( i=0; i<vecLen; ++i )
821 {
822 pxTemp = pseudoParticle[1].dot(vec[i]->GetMomentum());
823 pyTemp = pseudoParticle[2].dot(vec[i]->GetMomentum());
824 pzTemp = pseudoParticle[3].dot(vec[i]->GetMomentum());
825 vec[i]->SetMomentum( pxTemp, pyTemp, pzTemp );
826 }
827 //
828 // Rotate in direction of primary particle, subtract binding energies
829 // and make some further corrections if required
830 //
831 Defs1( modifiedOriginal, currentParticle, targetParticle, vec, vecLen );
832 G4double ekin;
833 G4double dekin = 0.0;
834 G4double ek1 = 0.0;
835 G4int npions = 0;
836 if( atomicWeight >= 1.5 ) // self-absorption in heavy molecules
837 {
838 // corrections for single particle spectra (shower particles)
839 //
840 const G4double alem[] = { 1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00 };
841 const G4double val0[] = { 0.00, 0.40, 0.48, 0.51, 0.54, 0.60, 0.65 };
842 alekw = std::log( originalIncident->GetKineticEnergy()/GeV );
843 exh = 1.0;
844 if( alekw > alem[0] ) // get energy bin
845 {
846 exh = val0[6];
847 for( G4int j=1; j<7; ++j )
848 {
849 if( alekw < alem[j] ) // use linear interpolation/extrapolation
850 {
851 G4double rcnve = (val0[j] - val0[j-1]) / (alem[j] - alem[j-1]);
852 exh = rcnve * alekw + val0[j-1] - rcnve * alem[j-1];
853 break;
854 }
855 }
856 exh = 1.0 - exh;
857 }
858 const G4double cfa = 0.025*((atomicWeight-1.)/120.)*std::exp(-(atomicWeight-1.)/120.);
859 ekin = currentParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
860 ekin = std::max( 1.0e-6, ekin );
861 xxh = 1.0;
862 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
863 modifiedOriginal.GetDefinition() == aPiMinus) &&
864 currentParticle.GetDefinition() == aPiZero &&
865 G4UniformRand() <= logWeight) xxh = exh;
866 dekin += ekin*(1.0-xxh);
867 ekin *= xxh;
868 if (currentParticle.GetDefinition()->GetParticleSubType() == "pi") {
869 ++npions;
870 ek1 += ekin;
871 }
872 currentParticle.SetKineticEnergy( ekin*GeV );
873 pp = currentParticle.GetTotalMomentum()/MeV;
874 pp1 = currentParticle.GetMomentum().mag()/MeV;
875 if( pp1 < 0.001*MeV )
876 {
877 G4double costheta = 2.*G4UniformRand() - 1.;
878 G4double sintheta = std::sqrt(1. - costheta*costheta);
879 G4double phi = twopi*G4UniformRand();
880 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
881 pp*sintheta*std::sin(phi)*MeV,
882 pp*costheta*MeV ) ;
883 }
884 else
885 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
886 ekin = targetParticle.GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
887 ekin = std::max( 1.0e-6, ekin );
888 xxh = 1.0;
889 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
890 modifiedOriginal.GetDefinition() == aPiMinus) &&
891 targetParticle.GetDefinition() == aPiZero &&
892 G4UniformRand() < logWeight) xxh = exh;
893 dekin += ekin*(1.0-xxh);
894 ekin *= xxh;
895 if (targetParticle.GetDefinition()->GetParticleSubType() == "pi") {
896 ++npions;
897 ek1 += ekin;
898 }
899 targetParticle.SetKineticEnergy( ekin*GeV );
900 pp = targetParticle.GetTotalMomentum()/MeV;
901 pp1 = targetParticle.GetMomentum().mag()/MeV;
902 if( pp1 < 0.001*MeV )
903 {
904 G4double costheta = 2.*G4UniformRand() - 1.;
905 G4double sintheta = std::sqrt(1. - costheta*costheta);
906 G4double phi = twopi*G4UniformRand();
907 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
908 pp*sintheta*std::sin(phi)*MeV,
909 pp*costheta*MeV ) ;
910 }
911 else
912 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
913 for( i=0; i<vecLen; ++i )
914 {
915 ekin = vec[i]->GetKineticEnergy()/GeV - cfa*(1+normal()/2.0);
916 ekin = std::max( 1.0e-6, ekin );
917 xxh = 1.0;
918 if( (modifiedOriginal.GetDefinition() == aPiPlus ||
919 modifiedOriginal.GetDefinition() == aPiMinus) &&
920 vec[i]->GetDefinition() == aPiZero &&
921 G4UniformRand() < logWeight) xxh = exh;
922 dekin += ekin*(1.0-xxh);
923 ekin *= xxh;
924 if (vec[i]->GetDefinition()->GetParticleSubType() == "pi") {
925 ++npions;
926 ek1 += ekin;
927 }
928 vec[i]->SetKineticEnergy( ekin*GeV );
929 pp = vec[i]->GetTotalMomentum()/MeV;
930 pp1 = vec[i]->GetMomentum().mag()/MeV;
931 if( pp1 < 0.001*MeV )
932 {
933 G4double costheta = 2.*G4UniformRand() - 1.;
934 G4double sintheta = std::sqrt(1. - costheta*costheta);
935 G4double phi = twopi*G4UniformRand();
936 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
937 pp*sintheta*std::sin(phi)*MeV,
938 pp*costheta*MeV ) ;
939 }
940 else
941 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
942 }
943 }
944 if( (ek1 != 0.0) && (npions > 0) )
945 {
946 dekin = 1.0 + dekin/ek1;
947 //
948 // first do the incident particle
949 //
950 if (currentParticle.GetDefinition()->GetParticleSubType() == "pi")
951 {
952 currentParticle.SetKineticEnergy(
953 std::max( 0.001*MeV, dekin*currentParticle.GetKineticEnergy() ) );
954 pp = currentParticle.GetTotalMomentum()/MeV;
955 pp1 = currentParticle.GetMomentum().mag()/MeV;
956 if( pp1 < 0.001 )
957 {
958 G4double costheta = 2.*G4UniformRand() - 1.;
959 G4double sintheta = std::sqrt(1. - costheta*costheta);
960 G4double phi = twopi*G4UniformRand();
961 currentParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
962 pp*sintheta*std::sin(phi)*MeV,
963 pp*costheta*MeV ) ;
964 } else {
965 currentParticle.SetMomentum( currentParticle.GetMomentum() * (pp/pp1) );
966 }
967 }
968
969 if (targetParticle.GetDefinition()->GetParticleSubType() == "pi")
970 {
971 targetParticle.SetKineticEnergy(
972 std::max( 0.001*MeV, dekin*targetParticle.GetKineticEnergy() ) );
973 pp = targetParticle.GetTotalMomentum()/MeV;
974 pp1 = targetParticle.GetMomentum().mag()/MeV;
975 if( pp1 < 0.001 )
976 {
977 G4double costheta = 2.*G4UniformRand() - 1.;
978 G4double sintheta = std::sqrt(1. - costheta*costheta);
979 G4double phi = twopi*G4UniformRand();
980 targetParticle.SetMomentum( pp*sintheta*std::cos(phi)*MeV,
981 pp*sintheta*std::sin(phi)*MeV,
982 pp*costheta*MeV ) ;
983 } else {
984 targetParticle.SetMomentum( targetParticle.GetMomentum() * (pp/pp1) );
985 }
986 }
987
988 for( i=0; i<vecLen; ++i )
989 {
990 if (vec[i]->GetDefinition()->GetParticleSubType() == "pi")
991 {
992 vec[i]->SetKineticEnergy( std::max( 0.001*MeV, dekin*vec[i]->GetKineticEnergy() ) );
993 pp = vec[i]->GetTotalMomentum()/MeV;
994 pp1 = vec[i]->GetMomentum().mag()/MeV;
995 if( pp1 < 0.001 )
996 {
997 G4double costheta = 2.*G4UniformRand() - 1.;
998 G4double sintheta = std::sqrt(1. - costheta*costheta);
999 G4double phi = twopi*G4UniformRand();
1000 vec[i]->SetMomentum( pp*sintheta*std::cos(phi)*MeV,
1001 pp*sintheta*std::sin(phi)*MeV,
1002 pp*costheta*MeV ) ;
1003 } else {
1004 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pp/pp1) );
1005 }
1006 }
1007 } // for i
1008 } // if (ek1 != 0)
1009 }
1010
1012 const G4DynamicParticle* originalTarget,
1014 const G4int& vecLen)
1015 {
1016 // Get number of protons and neutrons removed from the target nucleus
1017
1018 G4int protonsRemoved = 0;
1019 G4int neutronsRemoved = 0;
1020 if (originalTarget->GetDefinition()->GetParticleName() == "proton")
1021 protonsRemoved++;
1022 else
1023 neutronsRemoved++;
1024
1025 G4String secName;
1026 for (G4int i = 0; i < vecLen; i++) {
1027 secName = vec[i]->GetDefinition()->GetParticleName();
1028 if (secName == "proton") {
1029 protonsRemoved++;
1030 } else if (secName == "neutron") {
1031 neutronsRemoved++;
1032 } else if (secName == "anti_proton") {
1033 protonsRemoved--;
1034 } else if (secName == "anti_neutron") {
1035 neutronsRemoved--;
1036 }
1037 }
1038
1039 return std::pair<G4int, G4int>(protonsRemoved, neutronsRemoved);
1040 }
1041
1042
1044 {
1045 G4double costheta = 2.*G4UniformRand() - 1.;
1046 G4double sintheta = std::sqrt(1. - costheta*costheta);
1047 G4double phi = twopi*G4UniformRand();
1048 return G4ThreeVector(pp*sintheta*std::cos(phi),
1049 pp*sintheta*std::sin(phi),
1050 pp*costheta);
1051 }
1052
1053
1055 const G4ReactionProduct &modifiedOriginal,
1056 G4ReactionProduct &currentParticle,
1057 G4ReactionProduct &targetParticle,
1059 G4int &vecLen )
1060 {
1061 const G4double pOriginal = modifiedOriginal.GetTotalMomentum()/MeV;
1062 G4double testMomentum = currentParticle.GetMomentum().mag()/MeV;
1063 G4double pMass;
1064 if( testMomentum >= pOriginal )
1065 {
1066 pMass = currentParticle.GetMass()/MeV;
1067 currentParticle.SetTotalEnergy(
1068 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
1069 currentParticle.SetMomentum(
1070 currentParticle.GetMomentum() * (pOriginal/testMomentum) );
1071 }
1072 testMomentum = targetParticle.GetMomentum().mag()/MeV;
1073 if( testMomentum >= pOriginal )
1074 {
1075 pMass = targetParticle.GetMass()/MeV;
1076 targetParticle.SetTotalEnergy(
1077 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
1078 targetParticle.SetMomentum(
1079 targetParticle.GetMomentum() * (pOriginal/testMomentum) );
1080 }
1081 for( G4int i=0; i<vecLen; ++i )
1082 {
1083 testMomentum = vec[i]->GetMomentum().mag()/MeV;
1084 if( testMomentum >= pOriginal )
1085 {
1086 pMass = vec[i]->GetMass()/MeV;
1087 vec[i]->SetTotalEnergy(
1088 std::sqrt( pMass*pMass + pOriginal*pOriginal )*MeV );
1089 vec[i]->SetMomentum( vec[i]->GetMomentum() * (pOriginal/testMomentum) );
1090 }
1091 }
1092 }
1093
1096 G4int &vecLen,
1097 const G4HadProjectile *originalIncident,
1098 const G4Nucleus &targetNucleus,
1099 const G4double theAtomicMass,
1100 const G4double *mass )
1101 {
1102 // derived from original FORTRAN code NUCREC by H. Fesefeldt (12-Feb-1987)
1103 //
1104 // Nuclear reaction kinematics at low energies
1105 //
1112
1113 const G4double aProtonMass = aProton->GetPDGMass()/MeV;
1114 const G4double aNeutronMass = aNeutron->GetPDGMass()/MeV;
1115 const G4double aDeuteronMass = aDeuteron->GetPDGMass()/MeV;
1116 const G4double aTritonMass = aTriton->GetPDGMass()/MeV;
1117 const G4double anAlphaMass = anAlpha->GetPDGMass()/MeV;
1118
1119 G4ReactionProduct currentParticle;
1120 currentParticle = *originalIncident;
1121 //
1122 // Set beam particle, take kinetic energy of current particle as the
1123 // fundamental quantity. Due to the difficult kinematic, all masses have to
1124 // be assigned the best measured values
1125 //
1126 G4double p = currentParticle.GetTotalMomentum();
1127 G4double pp = currentParticle.GetMomentum().mag();
1128 if( pp <= 0.001*MeV )
1129 {
1130 G4double phinve = twopi*G4UniformRand();
1131 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
1132 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1133 p*std::sin(rthnve)*std::sin(phinve),
1134 p*std::cos(rthnve) );
1135 }
1136 else
1137 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
1138 //
1139 // calculate Q-value of reactions
1140 //
1141 G4double currentKinetic = currentParticle.GetKineticEnergy()/MeV;
1142 G4double currentMass = currentParticle.GetDefinition()->GetPDGMass()/MeV;
1143 G4double qv = currentKinetic + theAtomicMass + currentMass;
1144
1145 G4double qval[9];
1146 qval[0] = qv - mass[0];
1147 qval[1] = qv - mass[1] - aNeutronMass;
1148 qval[2] = qv - mass[2] - aProtonMass;
1149 qval[3] = qv - mass[3] - aDeuteronMass;
1150 qval[4] = qv - mass[4] - aTritonMass;
1151 qval[5] = qv - mass[5] - anAlphaMass;
1152 qval[6] = qv - mass[6] - aNeutronMass - aNeutronMass;
1153 qval[7] = qv - mass[7] - aNeutronMass - aProtonMass;
1154 qval[8] = qv - mass[8] - aProtonMass - aProtonMass;
1155
1156 if( currentParticle.GetDefinition() == aNeutron )
1157 {
1158 const G4double A = targetNucleus.GetA_asInt(); // atomic weight
1159 if( G4UniformRand() > ((A-1.0)/230.0)*((A-1.0)/230.0) )
1160 qval[0] = 0.0;
1161 if( G4UniformRand() >= currentKinetic/7.9254*A )
1162 qval[2] = qval[3] = qval[4] = qval[5] = qval[8] = 0.0;
1163 }
1164 else
1165 qval[0] = 0.0;
1166
1167 G4int i;
1168 qv = 0.0;
1169 for( i=0; i<9; ++i )
1170 {
1171 if( mass[i] < 500.0*MeV )qval[i] = 0.0;
1172 if( qval[i] < 0.0 )qval[i] = 0.0;
1173 qv += qval[i];
1174 }
1175 G4double qv1 = 0.0;
1176 G4double ran = G4UniformRand();
1177 G4int index;
1178 for( index=0; index<9; ++index )
1179 {
1180 if( qval[index] > 0.0 )
1181 {
1182 qv1 += qval[index]/qv;
1183 if( ran <= qv1 )break;
1184 }
1185 }
1186 if( index == 9 ) // loop continued to the end
1187 {
1188 throw G4HadronicException(__FILE__, __LINE__,
1189 "G4RPGReaction::NuclearReaction: inelastic reaction kinematically not possible");
1190 }
1191 G4double ke = currentParticle.GetKineticEnergy()/GeV;
1192 G4int nt = 2;
1193 if( (index>=6) || (G4UniformRand()<std::min(0.5,ke*10.0)) )nt = 3;
1194
1195 G4ReactionProduct **v = new G4ReactionProduct * [3];
1196 v[0] = new G4ReactionProduct;
1197 v[1] = new G4ReactionProduct;
1198 v[2] = new G4ReactionProduct;
1199
1200 v[0]->SetMass( mass[index]*MeV );
1201 switch( index )
1202 {
1203 case 0:
1204 v[1]->SetDefinition( aGamma );
1205 v[2]->SetDefinition( aGamma );
1206 break;
1207 case 1:
1208 v[1]->SetDefinition( aNeutron );
1209 v[2]->SetDefinition( aGamma );
1210 break;
1211 case 2:
1212 v[1]->SetDefinition( aProton );
1213 v[2]->SetDefinition( aGamma );
1214 break;
1215 case 3:
1216 v[1]->SetDefinition( aDeuteron );
1217 v[2]->SetDefinition( aGamma );
1218 break;
1219 case 4:
1220 v[1]->SetDefinition( aTriton );
1221 v[2]->SetDefinition( aGamma );
1222 break;
1223 case 5:
1224 v[1]->SetDefinition( anAlpha );
1225 v[2]->SetDefinition( aGamma );
1226 break;
1227 case 6:
1228 v[1]->SetDefinition( aNeutron );
1229 v[2]->SetDefinition( aNeutron );
1230 break;
1231 case 7:
1232 v[1]->SetDefinition( aNeutron );
1233 v[2]->SetDefinition( aProton );
1234 break;
1235 case 8:
1236 v[1]->SetDefinition( aProton );
1237 v[2]->SetDefinition( aProton );
1238 break;
1239 }
1240 //
1241 // calculate centre of mass energy
1242 //
1243 G4ReactionProduct pseudo1;
1244 pseudo1.SetMass( theAtomicMass*MeV );
1245 pseudo1.SetTotalEnergy( theAtomicMass*MeV );
1246 G4ReactionProduct pseudo2 = currentParticle + pseudo1;
1247 pseudo2.SetMomentum( pseudo2.GetMomentum() * (-1.0) );
1248 //
1249 // use phase space routine in centre of mass system
1250 //
1252 tempV.Initialize( nt );
1253 G4int tempLen = 0;
1254 tempV.SetElement( tempLen++, v[0] );
1255 tempV.SetElement( tempLen++, v[1] );
1256 if( nt == 3 )tempV.SetElement( tempLen++, v[2] );
1257 G4bool constantCrossSection = true;
1258 GenerateNBodyEvent( pseudo2.GetMass()/MeV, constantCrossSection, tempV, tempLen );
1259 v[0]->Lorentz( *v[0], pseudo2 );
1260 v[1]->Lorentz( *v[1], pseudo2 );
1261 if( nt == 3 )v[2]->Lorentz( *v[2], pseudo2 );
1262
1263 G4bool particleIsDefined = false;
1264 if( v[0]->GetMass()/MeV - aProtonMass < 0.1 )
1265 {
1266 v[0]->SetDefinition( aProton );
1267 particleIsDefined = true;
1268 }
1269 else if( v[0]->GetMass()/MeV - aNeutronMass < 0.1 )
1270 {
1271 v[0]->SetDefinition( aNeutron );
1272 particleIsDefined = true;
1273 }
1274 else if( v[0]->GetMass()/MeV - aDeuteronMass < 0.1 )
1275 {
1276 v[0]->SetDefinition( aDeuteron );
1277 particleIsDefined = true;
1278 }
1279 else if( v[0]->GetMass()/MeV - aTritonMass < 0.1 )
1280 {
1281 v[0]->SetDefinition( aTriton );
1282 particleIsDefined = true;
1283 }
1284 else if( v[0]->GetMass()/MeV - anAlphaMass < 0.1 )
1285 {
1286 v[0]->SetDefinition( anAlpha );
1287 particleIsDefined = true;
1288 }
1289 currentParticle.SetKineticEnergy(
1290 std::max( 0.001, currentParticle.GetKineticEnergy()/MeV ) );
1291 p = currentParticle.GetTotalMomentum();
1292 pp = currentParticle.GetMomentum().mag();
1293 if( pp <= 0.001*MeV )
1294 {
1295 G4double phinve = twopi*G4UniformRand();
1296 G4double rthnve = std::acos( std::max( -1.0, std::min( 1.0, -1.0 + 2.0*G4UniformRand() ) ) );
1297 currentParticle.SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1298 p*std::sin(rthnve)*std::sin(phinve),
1299 p*std::cos(rthnve) );
1300 }
1301 else
1302 currentParticle.SetMomentum( currentParticle.GetMomentum() * (p/pp) );
1303
1304 if( particleIsDefined )
1305 {
1306 v[0]->SetKineticEnergy(
1307 std::max( 0.001, 0.5*G4UniformRand()*v[0]->GetKineticEnergy()/MeV ) );
1308 p = v[0]->GetTotalMomentum();
1309 pp = v[0]->GetMomentum().mag();
1310 if( pp <= 0.001*MeV )
1311 {
1312 G4double phinve = twopi*G4UniformRand();
1313 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1314 v[0]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1315 p*std::sin(rthnve)*std::sin(phinve),
1316 p*std::cos(rthnve) );
1317 }
1318 else
1319 v[0]->SetMomentum( v[0]->GetMomentum() * (p/pp) );
1320 }
1321 if( (v[1]->GetDefinition() == aDeuteron) ||
1322 (v[1]->GetDefinition() == aTriton) ||
1323 (v[1]->GetDefinition() == anAlpha) )
1324 v[1]->SetKineticEnergy(
1325 std::max( 0.001, 0.5*G4UniformRand()*v[1]->GetKineticEnergy()/MeV ) );
1326 else
1327 v[1]->SetKineticEnergy( std::max( 0.001, v[1]->GetKineticEnergy()/MeV ) );
1328
1329 p = v[1]->GetTotalMomentum();
1330 pp = v[1]->GetMomentum().mag();
1331 if( pp <= 0.001*MeV )
1332 {
1333 G4double phinve = twopi*G4UniformRand();
1334 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1335 v[1]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1336 p*std::sin(rthnve)*std::sin(phinve),
1337 p*std::cos(rthnve) );
1338 }
1339 else
1340 v[1]->SetMomentum( v[1]->GetMomentum() * (p/pp) );
1341
1342 if( nt == 3 )
1343 {
1344 if( (v[2]->GetDefinition() == aDeuteron) ||
1345 (v[2]->GetDefinition() == aTriton) ||
1346 (v[2]->GetDefinition() == anAlpha) )
1347 v[2]->SetKineticEnergy(
1348 std::max( 0.001, 0.5*G4UniformRand()*v[2]->GetKineticEnergy()/MeV ) );
1349 else
1350 v[2]->SetKineticEnergy( std::max( 0.001, v[2]->GetKineticEnergy()/MeV ) );
1351
1352 p = v[2]->GetTotalMomentum();
1353 pp = v[2]->GetMomentum().mag();
1354 if( pp <= 0.001*MeV )
1355 {
1356 G4double phinve = twopi*G4UniformRand();
1357 G4double rthnve = std::acos( std::max(-1.0,std::min(1.0,-1.0+2.0*G4UniformRand())) );
1358 v[2]->SetMomentum( p*std::sin(rthnve)*std::cos(phinve),
1359 p*std::sin(rthnve)*std::sin(phinve),
1360 p*std::cos(rthnve) );
1361 }
1362 else
1363 v[2]->SetMomentum( v[2]->GetMomentum() * (p/pp) );
1364 }
1365 G4int del;
1366 for(del=0; del<vecLen; del++) delete vec[del];
1367 vecLen = 0;
1368 if( particleIsDefined )
1369 {
1370 vec.SetElement( vecLen++, v[0] );
1371 }
1372 else
1373 {
1374 delete v[0];
1375 }
1376 vec.SetElement( vecLen++, v[1] );
1377 if( nt == 3 )
1378 {
1379 vec.SetElement( vecLen++, v[2] );
1380 }
1381 else
1382 {
1383 delete v[2];
1384 }
1385 delete [] v;
1386 return;
1387 }
1388
1389 /* end of file */
1390
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:64
float G4float
Definition: G4Types.hh:65
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
#define G4endl
Definition: G4ios.hh:52
G4DLLIMPORT std::ostream G4cerr
G4DLLIMPORT std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:53
double z() const
double x() const
double y() const
Hep3Vector cross(const Hep3Vector &) const
double dot(const Hep3Vector &) const
double mag() const
Hep3Vector & rotate(double, const Hep3Vector &)
Definition: ThreeVectorR.cc:28
static G4Alpha * Alpha()
Definition: G4Alpha.cc:89
static G4Deuteron * Deuteron()
Definition: G4Deuteron.cc:94
G4ParticleDefinition * GetDefinition() const
void SetElement(G4int anIndex, Type *anElement)
Definition: G4FastVector.hh:76
void Initialize(G4int items)
Definition: G4FastVector.hh:63
static G4Gamma * Gamma()
Definition: G4Gamma.cc:86
G4double GetKineticEnergy() const
static G4Neutron * Neutron()
Definition: G4Neutron.cc:104
G4int GetA_asInt() const
Definition: G4Nucleus.hh:109
G4int GetZ_asInt() const
Definition: G4Nucleus.hh:115
const G4String & GetParticleName() const
const G4String & GetParticleSubType() const
static G4PionMinus * PionMinus()
Definition: G4PionMinus.cc:98
static G4PionPlus * PionPlus()
Definition: G4PionPlus.cc:98
static G4PionZero * PionZero()
Definition: G4PionZero.cc:104
static G4Proton * Proton()
Definition: G4Proton.cc:93
G4double GenerateNBodyEventT(const G4double totalEnergy, const G4bool constantCrossSection, std::vector< G4ReactionProduct * > &list)
void Rotate(const G4double numberofFinalStateNucleons, const G4ThreeVector &temp, const G4ReactionProduct &modifiedOriginal, const G4HadProjectile *originalIncident, const G4Nucleus &targetNucleus, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, G4FastVector< G4ReactionProduct, 256 > &vec, G4int &vecLen)
std::pair< G4int, G4int > GetFinalStateNucleons(const G4DynamicParticle *originalTarget, const G4FastVector< G4ReactionProduct, 256 > &vec, const G4int &vecLen)
G4bool ReactionStage(const G4HadProjectile *, G4ReactionProduct &, G4bool &, const G4DynamicParticle *, G4ReactionProduct &, G4bool &, const G4Nucleus &, G4ReactionProduct &, G4FastVector< G4ReactionProduct, 256 > &, G4int &, G4bool, G4ReactionProduct &)
void AddBlackTrackParticles(const G4double, const G4int, const G4double, const G4int, const G4ReactionProduct &, G4int, G4int, const G4Nucleus &, G4FastVector< G4ReactionProduct, 256 > &, G4int &)
G4double GenerateNBodyEvent(const G4double totalEnergy, const G4bool constantCrossSection, G4FastVector< G4ReactionProduct, 256 > &vec, G4int &vecLen)
void MomentumCheck(const G4ReactionProduct &modifiedOriginal, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, G4FastVector< G4ReactionProduct, 256 > &vec, G4int &vecLen)
void Defs1(const G4ReactionProduct &modifiedOriginal, G4ReactionProduct &currentParticle, G4ReactionProduct &targetParticle, G4FastVector< G4ReactionProduct, 256 > &vec, G4int &vecLen)
G4ThreeVector Isotropic(const G4double &)
void NuclearReaction(G4FastVector< G4ReactionProduct, 4 > &vec, G4int &vecLen, const G4HadProjectile *originalIncident, const G4Nucleus &aNucleus, const G4double theAtomicMass, const G4double *massVec)
G4double normal()
void SetMomentum(const G4double x, const G4double y, const G4double z)
void SetTotalEnergy(const G4double en)
G4double GetTotalMomentum() const
G4double GetKineticEnergy() const
G4ThreeVector GetMomentum() const
void Lorentz(const G4ReactionProduct &p1, const G4ReactionProduct &p2)
void SetKineticEnergy(const G4double en)
G4ParticleDefinition * GetDefinition() const
void SetDefinition(G4ParticleDefinition *aParticleDefinition)
G4double GetMass() const
void SetMass(const G4double mas)
static G4Triton * Triton()
Definition: G4Triton.cc:95