Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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