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