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
G4INCLCrossSections.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// INCL++ intra-nuclear cascade model
27// Pekka Kaitaniemi, CEA and Helsinki Institute of Physics
28// Davide Mancusi, CEA
29// Alain Boudard, CEA
30// Sylvie Leray, CEA
31// Joseph Cugnon, University of Liege
32//
33// INCL++ revision: v5.1.8
34//
35#define INCLXX_IN_GEANT4_MODE 1
36
37#include "globals.hh"
38
42#include "G4INCLLogger.hh"
43// #include <cassert>
44
45namespace G4INCL {
46
47 G4double CrossSections::total(Particle const * const p1, Particle const * const p2) {
48 G4double inelastic = 0.0;
49 if(p1->isNucleon() && p2->isNucleon()) {
50 inelastic = CrossSections::deltaProduction(p1, p2);
51 } else if((p1->isNucleon() && p2->isDelta()) ||
52 (p1->isDelta() && p2->isNucleon())) {
53 inelastic = CrossSections::recombination(p1, p2);
54 } else if((p1->isNucleon() && p2->isPion()) ||
55 (p1->isPion() && p2->isNucleon())) {
56 inelastic = CrossSections::pionNucleon(p1, p2);
57 } else {
58 inelastic = 0.0;
59 }
60
61 return inelastic + CrossSections::elastic(p1, p2);
62 }
63
64 G4double CrossSections::pionNucleon(Particle const * const particle1, Particle const * const particle2) {
65 // FUNCTION SPN(X,IND2T3,IPIT3,f17)
66 // SIGMA(PI+ + P) IN THE (3,3) REGION
67 // NEW FIT BY J.VANDERMEULEN + FIT BY Th AOUST ABOVE (3,3) RES
68 // CONST AT LOW AND VERY HIGH ENERGY
69 // COMMON/BL8/RATHR,RAMASS REL21800
70 // integer f17
71 // RATHR and RAMASS are always 0.0!!!
72
73 G4double x = KinematicsUtils::totalEnergyInCM(particle1, particle2);
74 if(x>10000.) return 0.0; // no cross section above this value
75
76 G4int ipit3 = 0;
77 G4int ind2t3 = 0;
78 G4double ramass = 0.0;
79
80 if(particle1->isPion()) {
81 ipit3 = ParticleTable::getIsospin(particle1->getType());
82 } else if(particle2->isPion()) {
83 ipit3 = ParticleTable::getIsospin(particle2->getType());
84 }
85
86 if(particle1->isNucleon()) {
87 ind2t3 = ParticleTable::getIsospin(particle1->getType());
88 } else if(particle2->isNucleon()) {
89 ind2t3 = ParticleTable::getIsospin(particle2->getType());
90 }
91
92 G4double y=x*x;
93 G4double q2=(y-1076.0*1076.0)*(y-800.0*800.0)/y/4.0;
94 if (q2 <= 0.) {
95 return 0.0;
96 }
97 G4double q3 = std::pow(std::sqrt(q2),3);
98 G4double f3 = q3/(q3 + 5832000.); // 5832000 = 180^3
99 G4double spnResult = 326.5/(std::pow((x-1215.0-ramass)*2.0/(110.0-ramass), 2)+1.0);
100 spnResult = spnResult*(1.0-5.0*ramass/1215.0);
101 G4double cg = 4.0 + G4double(ind2t3)*G4double(ipit3);
102 spnResult = spnResult*f3*cg/6.0;
103
104 if(x < 1200.0 && spnResult < 5.0) {
105 spnResult = 5.0;
106 }
107
108 // HE pi+ p and pi- n
109 if(x > 1290.0) {
110 if((ind2t3 == 1 && ipit3 == 2) || (ind2t3 == -1 && ipit3 == -2))
111 spnResult=CrossSections::spnPiPlusPHE(x);
112 else if((ind2t3 == 1 && ipit3 == -2) || (ind2t3 == -1 && ipit3 == 2))
113 spnResult=CrossSections::spnPiMinusPHE(x);
114 else if(ipit3 == 0) spnResult = (CrossSections::spnPiPlusPHE(x) + CrossSections::spnPiMinusPHE(x))/2.0; // (spnpipphe(x)+spnpimphe(x))/2.0
115 else {
116 ERROR("Unknown configuration!" << std::endl);
117 }
118 }
119
120 return spnResult;
121 }
122
123 G4double CrossSections::spnPiPlusPHE(const G4double x) {
124 // HE and LE pi- p and pi+ n
125 if(x <= 1750.0) {
126 return -2.33730e-06*std::pow(x, 3)+1.13819e-02*std::pow(x,2)
127 -1.83993e+01*x+9893.4;
128 } else if(x > 1750.0 && x <= 2175.0) {
129 return 1.13531e-06*std::pow(x, 3)-6.91694e-03*std::pow(x, 2)
130 +1.39907e+01*x-9360.76;
131 } else {
132 return -3.18087*std::log(x)+52.9784;
133 }
134 }
135
136 G4double CrossSections::spnPiMinusPHE(const G4double x) {
137 // HE pi- p and pi+ n
138 if(x <= 1475.0) {
139 return 0.00120683*(x-1372.52)*(x-1372.52)+26.2058;
140 } else if(x > 1475.0 && x <= 1565.0) {
141 return 1.15873e-05*x*x+49965.6/((x-1519.59)*(x-1519.59)+2372.55);
142 } else if(x > 1565.0 && x <= 2400.0) {
143 return 34.0248+43262.2/((x-1681.65)*(x-1681.65)+1689.35);
144 } else if(x > 2400.0 && x <= 7500.0) {
145 return 3.3e-7*(x-7500.0)*(x-7500.0)+24.5;
146 } else {
147 return 24.5;
148 }
149 }
150
151 G4double CrossSections::recombination(Particle const * const p1, Particle const * const p2) {
153 if(isospin==4 || isospin==-4) return 0.0;
154
156 G4double Ecm = std::sqrt(s);
157 G4int deltaIsospin;
158 G4double deltaMass;
159 if(p1->isDelta()) {
160 deltaIsospin = ParticleTable::getIsospin(p1->getType());
161 deltaMass = p1->getMass();
162 } else {
163 deltaIsospin = ParticleTable::getIsospin(p2->getType());
164 deltaMass = p2->getMass();
165 }
166
167 if(Ecm <= 938.3 + deltaMass) {
168 return 0.0;
169 }
170
171 if(Ecm < 938.3 + deltaMass + 2.0) {
172 Ecm = 938.3 + deltaMass + 2.0;
173 s = Ecm*Ecm;
174 }
175
177 (s - std::pow(ParticleTable::effectiveNucleonMass + deltaMass, 2));
178 const G4double y = s/(s - std::pow(deltaMass - ParticleTable::effectiveNucleonMass, 2));
179 /* Concerning the way we calculate the lab momentum, see the considerations
180 * in CrossSections::elasticNNLegacy().
181 */
183 G4double result = 0.5 * x * y * deltaProduction(isospin, pLab);
184 result *= 3.*(32.0 + isospin * isospin * (deltaIsospin * deltaIsospin - 5))/64.0;
185 result /= 1.0 + 0.25 * isospin * isospin;
186 return result;
187 }
188
189 G4double CrossSections::deltaProduction(Particle const * const p1, Particle const * const p2) {
190// assert(p1->isNucleon() && p2->isNucleon());
191 const G4double sqrts = KinematicsUtils::totalEnergyInCM(p1,p2);
192 if(sqrts < ParticleTable::effectivePionMass + 2*ParticleTable::effectiveNucleonMass + 50.) { // approximately yields INCL4.6's hard-coded threshold in collis, 2065 MeV
193 return 0.0;
194 } else {
195 const G4double pLab = KinematicsUtils::momentumInLab(p1,p2);
197 return deltaProduction(isospin, pLab);
198 }
199 }
200
201 G4double CrossSections::deltaProduction(const G4int isospin, const G4double pLab) {
202 G4double xs = 0.0;
203// assert(isospin==-2 || isospin==0 || isospin==2);
204
205 const G4double momentumGeV = 0.001 * pLab;
206 if(pLab < 800.0) {
207 return 0.0;
208 }
209
210 if(isospin==2 || isospin==-2) { // pp, nn
211 if(pLab >= 2000.0) {
212 xs = (41.0 + (60.0*momentumGeV - 54.0)*std::exp(-1.2*momentumGeV) - 77.0/(momentumGeV + 1.5));
213 } else if(pLab >= 1500.0 && pLab < 2000.0) {
214 xs = (41.0 + 60.0*(momentumGeV - 0.9)*std::exp(-1.2*momentumGeV) - 1250.0/(momentumGeV+50.0)+ 4.0*std::pow(momentumGeV - 1.3, 2));
215 } else if(pLab < 1500.0) {
216 xs = (23.5 + 24.6/(1.0 + std::exp(-10.0*momentumGeV + 12.0))
217 -1250.0/(momentumGeV +50.0)+4.0*std::pow(momentumGeV - 1.3,2));
218 }
219 } else if(isospin==0) { // pn
220 if(pLab >= 2000.0) {
221 xs = (42.0 - 77.0/(momentumGeV + 1.5));
222 } else if(pLab >= 1000.0 && pLab < 2000.0) {
223 xs = (24.2 + 8.9*momentumGeV - 31.1/std::sqrt(momentumGeV));
224 } else if(pLab < 1000.0) {
225 xs = (33.0 + 196.0*std::sqrt(std::pow(std::abs(momentumGeV - 0.95),5))
226 -31.1/std::sqrt(momentumGeV));
227 }
228 }
229
230 if(xs < 0.0) return 0.0;
231 else return xs;
232 }
233
234 G4double CrossSections::elasticNNHighEnergy(const G4double momentum) {
235 return 77.0/(momentum + 1.5);
236 }
237
238 G4double CrossSections::elasticProtonNeutron(const G4double momentum) {
239 if(momentum < 0.450) {
240 const G4double alp = std::log(momentum);
241 return 6.3555*std::exp(-3.2481*alp-0.377*alp*alp);
242 } else if(momentum >= 0.450 && momentum < 0.8) {
243 return (33.0 + 196.0 * std::sqrt(std::pow(std::abs(momentum - 0.95), 5)));
244 } else if(momentum > 2.0) {
245 return CrossSections::elasticNNHighEnergy(momentum);
246 } else {
247 return 31.0/std::sqrt(momentum);
248 }
249 }
250
251 G4double CrossSections::elasticProtonProtonOrNeutronNeutron(const G4double momentum)
252 {
253 if(momentum < 0.440) {
254 return 34.0*std::pow(momentum/0.4, -2.104);
255 } else if(momentum < 0.8 && momentum >= 0.440) {
256 return (23.5 + 1000.0*std::pow(momentum-0.7, 4));
257 } else if(momentum < 2.0) {
258 return (1250.0/(50.0 + momentum) - 4.0*std::pow(momentum-1.3, 2));
259 } else {
260 return CrossSections::elasticNNHighEnergy(momentum);
261 }
262 }
263
264 G4double CrossSections::elasticNN(Particle const * const p1, Particle const * const p2) {
265 G4double momentum = 0.0;
266 momentum = 0.001 * KinematicsUtils::momentumInLab(p1, p2);
267 if((p1->getType() == Proton && p2->getType() == Proton) ||
268 (p1->getType() == Neutron && p2->getType() == Neutron)) {
269 return CrossSections::elasticProtonProtonOrNeutronNeutron(momentum);
270 } else if((p1->getType() == Proton && p2->getType() == Neutron) ||
271 (p1->getType() == Neutron && p2->getType() == Proton)) {
272 return CrossSections::elasticProtonNeutron(momentum);
273 } else {
274 ERROR("G4INCL::CrossSections::elasticNN: Bad input!" << std::endl
275 << p1->print() << p2->print() << std::endl);
276 }
277 return 0.0;
278 }
279
280 G4double CrossSections::elasticNNLegacy(Particle const * const part1, Particle const * const part2) {
281 G4double scale = 1.0;
282
283
284 G4int i = ParticleTable::getIsospin(part1->getType())
285 + ParticleTable::getIsospin(part2->getType());
286 G4double sel = 0.0;
287
288 /* The NN cross section is parametrised as a function of the lab momentum
289 * of one of the nucleons. For NDelta or DeltaDelta, the physical
290 * assumption is that the cross section is the same as NN *for the same
291 * total CM energy*. Thus, we calculate s from the particles involved, and
292 * we convert this value to the lab momentum of a nucleon *as if this were
293 * an NN collision*.
294 */
295 const G4double s = KinematicsUtils::squareTotalEnergyInCM(part1, part2);
297
298 G4double p1=0.001*plab;
299 if(plab > 2000.) goto sel13;
300 if(part1->isNucleon() && part2->isNucleon())
301 goto sel1;
302 else
303 goto sel3;
304 sel1: if (i == 0) goto sel2;
305 sel3: if (plab < 800.) goto sel4;
306 if (plab > 2000.) goto sel13;
307 sel=(1250./(50.+p1)-4.*std::pow(p1-1.3, 2))*scale;
308 goto sel100;
309 return sel;
310 sel4: if (plab < 440.) {
311 sel=34.*std::pow(p1/0.4, (-2.104))*scale;
312 } else {
313 sel=(23.5+1000.*std::pow(p1-0.7, 4))*scale;
314 }
315 goto sel100;
316 return sel;
317 sel13: sel=77./(p1+1.5)*scale;
318 goto sel100;
319 return sel;
320 sel2: if (plab < 800.) goto sel11;
321 if (plab > 2000.) goto sel13;
322 sel=31./std::sqrt(p1)*scale;
323 goto sel100;
324 return sel;
325 sel11: if (plab < 450.) {
326 G4double alp=std::log(p1);
327 sel=6.3555*std::exp(-3.2481*alp-0.377*alp*alp)*scale;
328 } else {
329 sel=(33.+196.*std::sqrt(std::pow(std::abs(p1-0.95),5)))*scale;
330 }
331
332 sel100: return sel;
333 }
334
335 G4double CrossSections::elastic(Particle const * const p1, Particle const * const p2) {
336 if(!p1->isPion() && !p2->isPion())
337 // return elasticNN(p1, p2); // New implementation
338 return elasticNNLegacy(p1, p2); // Translated from INCL4.6 FORTRAN
339 else
340 return 0.0; // No pion-nucleon elastic scattering
341 }
342
344 G4double x = 0.001 * pl; // Change to GeV
345 if(iso != 0) {
346 if(pl <= 2000.0) {
347 x = std::pow(x, 8);
348 return 5.5e-6 * x/(7.7 + x);
349 } else {
350 return (5.34 + 0.67*(x - 2.0)) * 1.0e-6;
351 }
352 } else {
353 if(pl < 800.0) {
354 G4double b = (7.16 - 1.63*x) * 1.0e-6;
355 return b/(1.0 + std::exp(-(x - 0.45)/0.05));
356 } else if(pl < 1100.0) {
357 return (9.87 - 4.88 * x) * 1.0e-6;
358 } else {
359 return (3.68 + 0.76*x) * 1.0e-6;
360 }
361 }
362 return 0.0; // Should never reach this point
363 }
364
366 ThreeVector nullVector;
367 ThreeVector unitVector(0., 0., 1.);
368
369 Particle protonProjectile(Proton, unitVector, nullVector);
370 protonProjectile.setEnergy(protonProjectile.getMass()+projectileKineticEnergy);
371 protonProjectile.adjustMomentumFromEnergy();
372 Particle neutronProjectile(Neutron, unitVector, nullVector);
373 neutronProjectile.setEnergy(neutronProjectile.getMass()+projectileKineticEnergy);
374 neutronProjectile.adjustMomentumFromEnergy();
375
376 Particle protonTarget(Proton, nullVector, nullVector);
377 Particle neutronTarget(Neutron, nullVector, nullVector);
378 const G4double sigmapp = total(&protonProjectile, &protonTarget);
379 const G4double sigmapn = total(&protonProjectile, &neutronTarget);
380 const G4double sigmanp = total(&neutronProjectile, &protonTarget);
381 const G4double sigmann = total(&neutronProjectile, &neutronTarget);
382 /* We compute the interaction distance from the largest of the NN cross
383 * sections. Note that this is different from INCL4.6, which just takes the
384 * average of the four, and will in general lead to a different geometrical
385 * cross section.
386 */
387 const G4double largestSigma = std::max(sigmapp, std::max(sigmapn, std::max(sigmanp,sigmann)));
388 const G4double interactionDistance = std::sqrt(largestSigma/Math::tenPi);
389
390 return interactionDistance;
391 }
392
394 ThreeVector nullVector;
395 ThreeVector unitVector(0., 0., 1.);
396
397 Particle piPlusProjectile(PiPlus, unitVector, nullVector);
398 piPlusProjectile.setEnergy(piPlusProjectile.getMass()+projectileKineticEnergy);
399 piPlusProjectile.adjustMomentumFromEnergy();
400 Particle piZeroProjectile(PiZero, unitVector, nullVector);
401 piZeroProjectile.setEnergy(piZeroProjectile.getMass()+projectileKineticEnergy);
402 piZeroProjectile.adjustMomentumFromEnergy();
403 Particle piMinusProjectile(PiMinus, unitVector, nullVector);
404 piMinusProjectile.setEnergy(piMinusProjectile.getMass()+projectileKineticEnergy);
405 piMinusProjectile.adjustMomentumFromEnergy();
406
407 Particle protonTarget(Proton, nullVector, nullVector);
408 Particle neutronTarget(Neutron, nullVector, nullVector);
409 const G4double sigmapipp = total(&piPlusProjectile, &protonTarget);
410 const G4double sigmapipn = total(&piPlusProjectile, &neutronTarget);
411 const G4double sigmapi0p = total(&piZeroProjectile, &protonTarget);
412 const G4double sigmapi0n = total(&piZeroProjectile, &neutronTarget);
413 const G4double sigmapimp = total(&piMinusProjectile, &protonTarget);
414 const G4double sigmapimn = total(&piMinusProjectile, &neutronTarget);
415 /* We compute the interaction distance from the largest of the pi-N cross
416 * sections. Note that this is different from INCL4.6, which just takes the
417 * average of the six, and will in general lead to a different geometrical
418 * cross section.
419 */
420 const G4double largestSigma = std::max(sigmapipp, std::max(sigmapipn, std::max(sigmapi0p, std::max(sigmapi0n, std::max(sigmapimp,sigmapimn)))));
421 const G4double interactionDistance = std::sqrt(largestSigma/Math::tenPi);
422
423 return interactionDistance;
424 }
425
426}
427
#define ERROR(x)
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
static G4double elastic(Particle const *const p1, Particle const *const p2)
static G4double interactionDistancePiN(const G4double projectileKineticEnergy)
Compute the "interaction distance".
static G4double deltaProduction(Particle const *const p1, Particle const *const p2)
static G4double calculateNNDiffCrossSection(G4double energyCM, G4int iso)
Calculate the slope of the NN DDXS.
static G4double recombination(Particle const *const p1, Particle const *const p2)
static G4double total(Particle const *const p1, Particle const *const p2)
static G4double pionNucleon(Particle const *const p1, Particle const *const p2)
static G4double interactionDistanceNN(const G4double projectileKineticEnergy)
Compute the "interaction distance".
static G4double squareTotalEnergyInCM(Particle const *const p1, Particle const *const p2)
static G4double totalEnergyInCM(Particle const *const p1, Particle const *const p2)
static G4double momentumInLab(Particle const *const p1, Particle const *const p2)
gives the momentum in the lab frame of two particles.
static const G4double effectiveNucleonMass2
static G4int getIsospin(const ParticleType t)
Get the isospin of a particle.
static const G4double effectiveNucleonMass
static const G4double effectivePionMass
const ThreeVector & adjustMomentumFromEnergy()
Rescale the momentum to match the total energy.
G4bool isPion() const
Is this a pion?
G4INCL::ParticleType getType() const
void setEnergy(G4double energy)
G4double getMass() const
Get the cached particle mass.
G4bool isDelta() const
Is it a Delta?
G4bool isNucleon() const
const G4double tenPi