OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
BeamStrippingPhysics.cpp
Go to the documentation of this file.
1 //
2 // Class BeamStrippingPhysics
3 // Defines the physical processes of residual gas
4 // interactions and Lorentz stripping
5 //
6 // Copyright (c) 2018 - 2021, Pedro Calvo, CIEMAT, Spain
7 // All rights reserved
8 //
9 // Implemented as part of the PhD thesis
10 // "Optimizing the radioisotope production of the novel AMIT
11 // superconducting weak focusing cyclotron"
12 //
13 // This file is part of OPAL.
14 //
15 // OPAL is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
22 //
24 
25 #include "AbsBeamline/Cyclotron.h"
26 #include "AbsBeamline/Vacuum.h"
30 #include "Physics/Physics.h"
31 #include "Physics/Units.h"
32 #include "Structure/LossDataSink.h"
33 #include "Utilities/Util.h"
35 #include "Utilities/Options.h"
36 #include "Utility/Inform.h"
37 
38 #include <boost/math/special_functions/chebyshev.hpp>
39 
40 #include <sys/time.h>
41 
42 #include <algorithm>
43 #include <cmath>
44 #include <fstream>
45 #include <iostream>
46 
47 extern Inform *gmsgALL;
48 
49 namespace {
50  struct VacuumInsideTester: public InsideTester {
51  explicit VacuumInsideTester(ElementBase* el) {
52  vac_m = static_cast<Vacuum*>(el);
53  }
54  bool checkHit(const Vector_t& R) override {
55  return vac_m->checkPoint(R);
56  }
57  private:
58  Vacuum* vac_m;
59  };
60 }
61 
62 
64  ElementBase* element):
65  ParticleMatterInteractionHandler(name, element),
66  pType_m(ParticleType::UNNAMED),
67  T_m(0.0),
68  dT_m(0.0),
69  mass_m(0.0),
70  pressure_m(0.0),
71  temperature_m(0.0),
72  nCSA_m(0.0),
73  nCSB_m(0.0),
74  nCSC_m(0.0),
75  nCSTotal_m(0.0),
76  bunchToMatStat_m(0),
77  stoppedPartStat_m(0),
78  rediffusedStat_m(0),
79  totalPartsInMat_m(0)
80 {
81  lossDs_m = std::unique_ptr<LossDataSink>(new LossDataSink(getName(), !Options::asciidump));
82 
83  const gsl_rng_type* T;
84  gsl_rng_env_setup();
85  struct timeval tv; // Seed generation based on time
86  gettimeofday(&tv,0);
87  unsigned long mySeed = tv.tv_sec + tv.tv_usec;
88  T = gsl_rng_default; // Generator setup
89  r_m = gsl_rng_alloc (T);
90  gsl_rng_set(r_m, mySeed);
91 }
92 
93 
95  lossDs_m->save();
96  gsl_rng_free(r_m);
97 }
98 
99 
101  const std::pair<Vector_t, double>& /*boundingSphere*/) {
102 
103  ParticleType particle = bunch->getPType();
104  if (particle != ParticleType::PROTON &&
105  particle != ParticleType::DEUTERON &&
106  particle != ParticleType::HMINUS &&
107  particle != ParticleType::H2P &&
108  particle != ParticleType::HYDROGEN) {
109 
111  "BeamStrippingPhysics::apply",
112  "Particle " + ParticleProperties::getParticleTypeString(particle) +
113  " is not supported for residual stripping interactions!");
114  }
115 
117  hitTester_m.reset(new VacuumInsideTester(element_ref_m));
118  vac_m = dynamic_cast<Vacuum*>(element_ref_m);
119  } else {
120  throw GeneralClassicException("BeamStrippingPhysics::apply",
121  "Unsupported element type");
122  }
123 
124  dT_m = bunch->getdT();
125 
126  rediffusedStat_m = 0;
127  stoppedPartStat_m = 0;
128  totalPartsInMat_m = 0;
129 
130  if (bunch->get_sPos() != 0) {
131  doPhysics(bunch);
132 
134 
135  if (OpalData::getInstance()->isInOPALTMode()) {
136  bunch->destroyT();
137  }
138  }
139 }
140 
141 
143  /*
144  Do physics if
145  -- particle in material
146  -- particle not dead (bunch->Bin[i] != -1)
147  Delete particle i: bunch->Bin[i] != -1;
148  */
150  bool stop = vac_m->getStop();
151  Vector_t extE = Vector_t(0.0, 0.0, 0.0);
152  Vector_t extB = Vector_t(0.0, 0.0, 0.0); //kGauss
153 
154  for (size_t i = 0; i < bunch->getLocalNum(); ++i) {
155  Vector_t& R = bunch->R[i];
156  Vector_t& P = bunch->P[i];
157  if ( bunch->Bin[i] != -1 && hitTester_m->checkHit(R) ) {
158 
160 
161  bool pdead_GS = false;
162  bool pdead_LS = false;
164  mass_m = bunch->M[i];
165  pType_m = bunch->PType[i];
166 
167  double energy = Util::getKineticEnergy(P, mass_m); //GeV
168  double gamma = Util::getGamma(P);
169  double beta = std::sqrt(1.0 - 1.0 / (gamma * gamma));
170  double deltas = dT_m * beta * Physics::c;
171 
172  computeCrossSection(energy);
173  pdead_GS = evalGasStripping(deltas);
174 
175  if (OpalData::getInstance()->isInOPALCyclMode() &&
176  bunch->PType[i] == ParticleType::HMINUS) {
177  cycl_m->apply(R, P, T_m, extE, extB);
178  double bField = Units::kG2T * std::sqrt(extB[0]*extB[0] + extB[1]*extB[1] + extB[2]*extB[2]); //T
179  double eField = gamma * beta * Physics::c * bField;
180  pdead_LS = evalLorentzStripping(gamma, eField);
181  }
182 
183  if (pdead_GS == true || pdead_LS == true) {
184  lossDs_m->addParticle(OpalParticle(bunch->ID[i],
185  R, P,
186  bunch->getT(),
187  bunch->Q[i], bunch->M[i]));
188  if (stop) {
189  bunch->Bin[i] = -1;
191  *gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
192  << " is deleted by beam stripping interactions" << endl;
193  } else {
195  getSecondaryParticles(bunch, i, pdead_LS);
196  }
197  }
198  }
199  }
200 }
201 
202 
204 
205  const ResidualGas& gas = vac_m->getResidualGas();
206 
207  energy *=Units::GeV2keV;
208  double energyThreshold = 0.0;
209  double a1 = 0.0;
210  double a2 = 0.0;
211  double a3 = 0.0;
212  double a4 = 0.0;
213  double a5 = 0.0;
214  double a6 = 0.0;
215  double a7 = 0.0;
216  double a8 = 0.0;
217  double a9 = 0.0;
218  double a10 = 0.0;
219  double a11 = 0.0;
220  double a12 = 0.0;
221  double molecularDensity[3] = {};
222 
223  switch (gas) {
224  case ResidualGas::H2: {
225 
226  molecularDensity[0] = 100 * pressure_m / (Physics::kB * Physics::q_e * temperature_m);
227  double energyMin = 0.0, energyMax = 0.0;
228  double csA = 0.0, csB = 0.0, csC = 0.0, csTotal = 0.0;
229 
230  if (pType_m == ParticleType::HMINUS) {
231  double energyChebyshevFit = energy * Units::keV2eV / (Physics::m_hm / Physics::amu);
232 
233  // Single-electron detachment - Hydrogen Production
234  energyMin = csCoefSingle_Hminus_Chebyshev[0];
235  energyMax = csCoefSingle_Hminus_Chebyshev[1];
236  for (int i = 0; i < 9; ++i)
238  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
239 
240  // Double-electron detachment - Proton Production
241  energyMin = csCoefDouble_Hminus_Chebyshev[0];
242  energyMax = csCoefDouble_Hminus_Chebyshev[1];
243  for (int i = 0; i < 9; ++i)
245  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
246 
247  } else if (pType_m == ParticleType::PROTON) {
248  double energyChebyshevFit = energy * Units::keV2eV / (Physics::m_p / Physics::amu);
249 
250  // Single-electron capture - Hydrogen Production
251  energyMin = csCoefSingle_Hplus_Chebyshev[0];
252  energyMax = csCoefSingle_Hplus_Chebyshev[1];
253  for (int i = 0; i < 9; ++i)
254  a_m[i] = {csCoefSingle_Hplus_Chebyshev[i+2]};
255  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
256 
257  // Double-electron capture - Hminus Production
258  energyMin = csCoefDouble_Hplus_Chebyshev[0];
259  energyMax = csCoefDouble_Hplus_Chebyshev[1];
260  for (int i = 0; i < 9; ++i)
261  a_m[i] = {csCoefDouble_Hplus_Chebyshev[i+2]};
262  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
263 
264  } else if (pType_m == ParticleType::DEUTERON) {
265  // Single-electron capture
266  energyThreshold = csCoefSingle_Hplus_Tabata[0];
276  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
277  computeCrossSectionTabata(energy, energyThreshold, a5, a2, a6, a7, a8, a9);
278 
279  } else if (pType_m == ParticleType::HYDROGEN) {
280  // Single-electron detachment - Proton Production
281  energyThreshold = csCoefProtonProduction_H_Tabata[0];
288  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
289  a5 * computeCrossSectionTabata(energy/a6, energyThreshold/a6, a1, a2, 0.0, 0.0, a3, a4);
290 
291  // Single-electron capture - Hminus Production
292  energyThreshold = csCoefHminusProduction_H_Tabata[0];
305  csB = computeCrossSectionTabata(energy, energyThreshold, a1, a2, a3, a4, a5, a6) +
306  computeCrossSectionTabata(energy, energyThreshold, a7, a8, a9, a10, a11, a12);
307 
308  } else if (pType_m == ParticleType::H2P) {
309  double energyChebyshevFit = energy * Units::keV2eV / (Physics::m_h2p / Physics::amu);
310  // Proton production
311  if (energy <= energyRangeH2plusinH2[0]) {
312  energyThreshold = csCoefProtonProduction_H2plus_Tabata[0];
323  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
324  computeCrossSectionTabata(energy, energyThreshold, a5, a6, 0.0, 0.0, a7, a8) +
325  a9 * computeCrossSectionTabata(energy/a10, energyThreshold/a10, a5, a6, 0.0, 0.0, a7, a8);
326 
327  } else if (energy > energyRangeH2plusinH2[0] &&
328  energy < energyRangeH2plusinH2[1]) {
331  for (int i = 0; i < 9; ++i)
333  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
334 
335  } else if (energy >= energyRangeH2plusinH2[1]) {
336  int zTarget = 1;
337  double massInAmu = Physics::m_h2p / Physics::amu;
338  csA = computeCrossSectionBohr(energy, zTarget, massInAmu);
339  }
340 
341  // Hydrogen production
344  for (int i = 0; i < 9; ++i)
346  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
347 
348  // H3+, H
349  energyThreshold = csCoefH3plusProduction_H2plus_Tabata[0];
356  csC = computeCrossSectionTabata(energy, energyThreshold, a1, a2, a3, a4, a5, a6);
357  }
358  csTotal = csA + csB + csC;
359 
360  nCSA_m = csA * Units::cm2m * Units::cm2m * molecularDensity[0];
361  nCSB_m = csB * Units::cm2m * Units::cm2m * molecularDensity[0];
362  nCSC_m = csC * Units::cm2m * Units::cm2m * molecularDensity[0];
363  nCSTotal_m = csTotal * Units::cm2m * Units::cm2m * molecularDensity[0];
364  break;
365  }
366 
367  case ResidualGas::AIR: {
368 
369  int zTarget[3] = {7, 8, 18};
370  static const double fMolarFraction[3] = {0.78084, 0.20947, 0.00934}; // N2, O2, Ar
371  double csSingle[3], csDouble[3], csTotal[3];
372  double nCSSingle[3], nCSDouble[3], nCS[3];
373  double nCSSingleSum = 0.0;
374  double nCSDoubleSum = 0.0;
375  double nCSTotalSum = 0.0;
376 
377  for (int i = 0; i < 3; ++i) {
378  molecularDensity[i] = 100 * pressure_m * fMolarFraction[i] / (Physics::kB * Physics::q_e * temperature_m);
379 
380  if (pType_m == ParticleType::HMINUS) {
381  // Single-electron detachment - Hydrogen Production
382  energyThreshold = csCoefSingle_Hminus[i][0];
383  for (int j = 0; j < 8; ++j)
384  b_m[i][j] = csCoefSingle_Hminus[i][j+1];
385  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i);
386 
387  // Double-electron detachment - Proton Production
388  energyThreshold = csCoefDouble_Hminus[i][0];
389  for (int j = 0; j < 8; ++j)
390  b_m[i][j] = csCoefDouble_Hminus[i][j+1];
391  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
392 
394  // Single-electron capture
395  energyThreshold = csCoefSingle_Hplus[i][0];
396  for (int j = 0; j < 8; ++j)
397  b_m[i][j] = csCoefSingle_Hplus[i][j+1];
398  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
399  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
400 
401  // Double-electron capture
402  energyThreshold = csCoefDouble_Hplus[i][0];
403  for (int j = 0; j < 8; ++j)
404  b_m[i][j] = csCoefDouble_Hplus[i][j+1];
405  if (b_m[i][7] != 0) {
406  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
407  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
408  } else {
409  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
410  }
411 
412  } else if (pType_m == ParticleType::HYDROGEN) {
413  // Single-electron detachment - Proton Production
414  energyThreshold = csCoefSingleLoss_H[i][0];
415  for (int j = 0; j < 8; ++j)
416  b_m[i][j] = csCoefSingleLoss_H[i][j+1];
417  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i);
418 
419  // Single-electron capture - Hminus Production
420  energyThreshold = csCoefSingleCapt_H[i][0];
421  for (int j = 0; j < 8; ++j)
422  b_m[i][j] = csCoefSingleCapt_H[i][j+1];
423  if (b_m[i][7] != 0) {
424  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
425  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
426  } else {
427  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
428  }
429 
430  } else if (pType_m == ParticleType::H2P) {
431  double massInAmu = Physics::m_h2p / Physics::amu;
432  csSingle[i] = {0.0};
433  csDouble[i] = computeCrossSectionBohr(energy, zTarget[i], massInAmu);
434 
435  } else {
436  csSingle[i] = {0.0};
437  csDouble[i] = {0.0};
438  }
439  csTotal[i] = csSingle[i] + csDouble[i];
440  nCSSingle[i] = csSingle[i] * Units::cm2m * Units::cm2m * molecularDensity[i];
441  nCSDouble[i] = csDouble[i] * Units::cm2m * Units::cm2m * molecularDensity[i];
442  nCS[i] = csTotal[i] * Units::cm2m * Units::cm2m * molecularDensity[i];
443 
444  nCSSingleSum += nCSSingle[i];
445  nCSDoubleSum += nCSDouble[i];
446  nCSTotalSum += nCS[i];
447  }
448  nCSA_m = nCSSingleSum;
449  nCSB_m = nCSDoubleSum;
450  nCSTotal_m = nCSTotalSum;
451  break;
452  }
453  default: {
454  break;
455  }
456  }
457 }
458 
465 // -------------------------------------------------------------------------
466 double BeamStrippingPhysics::computeCrossSectionNakai(double energy, double energyThreshold, int &i) {
467 
468  if (energy <= energyThreshold) {
469  return 0.0;
470  }
471  const double E_R = Physics::E_ryd * Units::GeV2keV * Physics::m_h / Physics::m_e;
472  const double sigma_0 = 1E-16;
473  double sigma = 0.0; //cm2
474  double effectiveEnergy = energy - energyThreshold; //keV
475  double f1 = sigma_0 * b_m[i][0] * std::pow((effectiveEnergy / E_R), b_m[i][1]);
476  if (b_m[i][2] != 0.0 && b_m[i][3] != 0.0) {
477  sigma = f1 / (1 + std::pow((effectiveEnergy / b_m[i][2]), (b_m[i][1] + b_m[i][3]))
478  + std::pow((effectiveEnergy / b_m[i][4]), (b_m[i][1] + b_m[i][5])));
479  } else {
480  sigma = f1 / (1 + std::pow((effectiveEnergy / b_m[i][4]), (b_m[i][1] + b_m[i][5])));
481  }
482 
483  return sigma;
484 }
485 
492 // -------------------------------------------------------------------------
493 double BeamStrippingPhysics::computeCrossSectionTabata(double energy, double energyThreshold,
494  double a1, double a2, double a3,
495  double a4, double a5, double a6) {
496  if (energy <= energyThreshold) {
497  return 0.0;
498  }
499  const double sigma_0 = 1E-16;
500  double sigma = 0.0; //cm2
501  double effectiveEnergy = energy - energyThreshold; //keV
502  double f1 = sigma_0 * a1 * std::pow((effectiveEnergy / (Physics::E_ryd * Units::GeV2keV)),a2);
503  if (a3 != 0.0 && a4 != 0.0) {
504  sigma = f1 / (1 + std::pow((effectiveEnergy / a3), (a2 + a4)) + std::pow((effectiveEnergy / a5), (a2 + a6)));
505  } else {
506  sigma = f1 / (1 + std::pow((effectiveEnergy / a5), (a2 + a6)));
507  }
508 
509  return sigma;
510 }
511 
516 // -------------------------------------------------------------------------
518  double energyMin,
519  double energyMax) {
520  // energy -> eV/amu
521  if (energy <= energyMin || energy >= energyMax) {
522  return 0.0;
523  }
524  double sum_aT = 0.0;
525  double aT[8] = {0.0};
526  double x = ((std::log(energy)-std::log(energyMin)) - (std::log(energyMax)-std::log(energy))) / (std::log(energyMax)-std::log(energyMin));
527  for (int i = 0; i < 8; ++i) {
528  aT[i] = (a_m[i+1] * boost::math::chebyshev_t(i+1, x));
529  sum_aT += aT[i];
530  }
531  double sigma = std::exp(0.5*a_m[0] + sum_aT); //cm2
532 
533  return sigma;
534 }
535 
541 // -------------------------------------------------------------------------
542 double BeamStrippingPhysics::computeCrossSectionBohr(double energy, int zTarget, double massInAmu) {
543 
544  double energyAmu = energy / massInAmu;
545  if (energyAmu <= 1E3 || energyAmu >= 1E5) {
546  return 0.0;
547  }
548  double sigma = 0.0; //cm2
549  constexpr double GeV2keV = Units::GeV2eV * Units::eV2keV;
550  double mass = mass_m * GeV2keV;
551  const double a0v0 = Physics::h_bar * Physics::c * Physics::c / Physics::m_e;
552  double v = Physics::c * std::sqrt(1 - std::pow(mass/(energy+mass), 2));
553  if (zTarget < 15) {
554  double z = (zTarget + zTarget*zTarget);
555  sigma = Units::m2cm * Units::m2cm * 4 * Physics::pi * std::pow(a0v0, 2) * z / std::pow(v, 2);
556  } else {
557  sigma = Units::m2cm * Units::m2cm * 4 * Physics::pi * Physics::a0 * a0v0 * std::pow(zTarget, 2.0/3.0) / v;
558  }
559  return sigma;
560 }
561 
562 
564 
565  double xi = gsl_rng_uniform(r_m);
566  double fg = 1-std::exp(-nCSTotal_m*deltas);
567 
568  return (fg >= xi);
569 }
570 
575 // -------------------------------------------------------------------------
576 bool BeamStrippingPhysics::evalLorentzStripping(double& gamma, double& eField) {
577 
578  double xi = gsl_rng_uniform(r_m);
579 
580  const double eps0 = 0.75419 * Physics::q_e; // electron binding energy,
581  const double hbar = Physics::h_bar * Units::GeV2eV * Physics::q_e; // Js
582  const double me = Physics::m_e * Units::GeV2kg;
583  const double p = 0.0126; // polarization factor
584  const double s0 = 0.783; // spectroscopic coefficient
585  const double a = 2.01407/Physics::a0;
586  const double k0 = std::sqrt(2 * me * eps0)/hbar;
587  const double n = (std::sqrt(2 * k0 * (k0+a) * (2*k0+a)))/a; // normalization factor
588  double zT = eps0 / (Physics::q_e * eField);
589  double tau = (4 * me * zT)/(s0 * n * n * hbar * (1+p)*(1+p) * (1-1/(2*k0*zT))) * std::exp(4*k0*zT/3);
590  double fL = 1 - std::exp( -dT_m / (gamma * tau));
591 
592  return (fL >= xi);
593 }
594 
596  size_t& i, bool pdead_LS) {
597  double r = gsl_rng_uniform(r_m);
598 
599  const ResidualGas& gas = vac_m->getResidualGas();
600 
601  if (pType_m == ParticleType::HMINUS) {
602  if (pdead_LS == true) {
604  } else {
605  if (r > nCSB_m/nCSTotal_m)
607  else
609  }
610 
611  } else if (pType_m == ParticleType::PROTON) {
612  if (r > nCSB_m/nCSTotal_m)
614  else
616 
617  } else if (pType_m == ParticleType::HYDROGEN) {
618  if (r > nCSB_m/nCSTotal_m)
620  else
622 
623  } else if (pType_m == ParticleType::H2P) {
624  if (gas == ResidualGas::H2) {
625  if (nCSC_m>nCSB_m && nCSB_m>nCSA_m) {
626  if (r > (nCSA_m+nCSB_m)/nCSTotal_m)
628  else if (r > nCSA_m/nCSTotal_m)
630  else
632 
633  } else if (nCSA_m>nCSB_m && nCSB_m>nCSC_m) {
634  if (r > (nCSC_m+nCSB_m)/nCSTotal_m)
636  else if (r > nCSC_m/nCSTotal_m)
638  else
640 
641  } else if (nCSA_m>nCSB_m && nCSC_m>nCSA_m) {
642  if (r > (nCSA_m+nCSB_m)/nCSTotal_m)
644  else if (r > nCSB_m/nCSTotal_m)
646  else
648 
649  } else if (nCSA_m>nCSC_m && nCSC_m>nCSB_m) {
650  if (r > (nCSC_m+nCSB_m)/nCSTotal_m)
652  else if (r > nCSB_m/nCSTotal_m)
654  else
656 
657  } else if (nCSB_m>nCSC_m && nCSB_m>nCSA_m && nCSA_m>nCSC_m) {
658  if (r > (nCSC_m+nCSA_m)/nCSTotal_m)
660  else if (r > nCSC_m/nCSTotal_m)
662  else
664 
665  } else {
666  if (r > (nCSC_m+nCSA_m)/nCSTotal_m)
668  else if (r > nCSA_m/nCSTotal_m)
670  else
672  }
673  } else if (gas == ResidualGas::AIR) {
674  if (r > nCSTotal_m)
676  }
677  } else if (pType_m == ParticleType::DEUTERON) {
678  GeneralClassicException("BeamStrippingPhysics::getSecondaryParticles",
679  "Tracking secondary particles from incident "
680  "ParticleType::DEUTERON is not implemented");
681  }
682 }
683 
685  size_t& i,
686  ParticleType type) {
688  bunch->PType[i] = type;
689  bunch->M[i] = ParticleProperties::getParticleMass(type);
691 
692  *gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
693  << " is transformed to " << ParticleProperties::getParticleTypeString(type) << endl;
694 }
695 
696 
698  Inform::FmtFlags_t ff = msg.flags();
699  if (totalPartsInMat_m > 0) {
700  msg << level2
701  << "\n"<< "--- BeamStrippingPhysics ---\n"
702  << "Name: " << name_m << " - "
703  << "Element: " << element_ref_m->getName() << " - "
704  << "Residual gas: " << vac_m->getResidualGasName() << "\n"
705  << std::setw(31) << "Particles in the material: " << Util::toStringWithThousandSep(totalPartsInMat_m) << "\n"
706  << std::setw(31) << "Rediffused as secondary: " << Util::toStringWithThousandSep(rediffusedStat_m) << "\n"
707  << std::setw(31) << "Stripped by the gas: " << Util::toStringWithThousandSep(stoppedPartStat_m)
708  << endl;
709  }
710  msg.flags(ff);
711 }
712 
714 
715  constexpr unsigned short numItems = 3;
716  unsigned int partStatistics[numItems] = {totalPartsInMat_m,
719 
720  allreduce(&(partStatistics[0]), numItems, std::plus<unsigned int>());
721 
722  totalPartsInMat_m = partStatistics[0];
723  rediffusedStat_m = partStatistics[1];
724  stoppedPartStat_m = partStatistics[2];
725 }
726 
727 
728 /*
729  Cross sections parameters for interaction with air
730  -- [1] -> Nitrogen
731  -- [2] -> Oxygen
732  -- [3] -> Argon
733 */
734 const double BeamStrippingPhysics::csCoefSingle_Hminus[3][9] = {
735  {7.50E-04, 4.38E+02, 7.28E-01, 8.40E-01, 2.82E-01, 4.10E+01, 1.37E+00, 0.00E+00, 0.00E+00},
736  {-2.00E-04, 3.45E+02, 4.80E-01, 5.30E-02, 8.40E-02, 1.00E+01, 9.67E-01, 0.00E+00, 0.00E+00},
737  {1.70E-3, 2.47E+01, 3.36E-01, 7.00E+01, 5.00E-01, 9.90E+01, 7.80E-01, 0.00E+00, 0.00E+00}
738 };
739 const double BeamStrippingPhysics::csCoefDouble_Hminus[3][9] = {
740  {1.40E-02, 1.77E+00, 4.80E-01, 0.00E+00, 0.00E+00, 1.52E+02, 1.52E+00, 0.00E+00, 0.00E+00},
741  {1.30E-02, 1.90E+00, 6.20E-01, 0.00E+00, 0.00E+00, 5.20E+01, 9.93E-01, 0.00E+00, 0.00E+00},
742  {1.50E-02, 1.97E+00, 8.90E-01, 0.00E+00, 0.00E+00, 5.10E+01, 9.37E-01, 0.00E+00, 0.00E+00}
743 };
744 const double BeamStrippingPhysics::csCoefSingle_Hplus[3][9] = {
745  {2.00E-03, 1.93E+03, 1.64E+00, 1.98E+00, 6.69E-01, 2.19E+01, 4.15E+00, 3.23E-04, 1.00E+01},
746  {-1.50E-03, 3.86E+05, 1.60E+00, 6.93E-02, 3.28E-01, 7.86E+00, 3.92E+00, 3.20E-04, 1.00E+01},
747  {2.18E-03, 1.61E+04, 2.12E+00, 1.16E+00, 4.44E-01, 1.39E+01, 4.07E+00, 2.99E-04, 1.45E+01}
748 };
749 const double BeamStrippingPhysics::csCoefDouble_Hplus[3][9] = {
750  {2.90E-02, 2.90E-01, 1.50E+00, 1.39E+01, 1.65E+00, 3.94E+01, 5.79E+00, 0.00E+00, 0.00E+00},
751  {2.20E-02, 2.64E-01, 1.50E+00, 1.40E+01, 1.70E+00, 4.00E+01, 5.80E+00, 0.00E+00, 0.00E+00},
752  {2.90E-02, 1.40E-01, 1.87E+00, 2.40E+01, 1.60E+00, 3.37E+01, 4.93E+00, 4.50E-01, 2.00E-01}
753 };
754 const double BeamStrippingPhysics::csCoefSingleLoss_H[3][9] = {
755  {1.36E-02, 2.59E+03, 1.78E+00, 2.69E-01, -3.52E-01, 5.60E+00, 8.99E-01, 0.00E+00, 0.00E+00},
756  {1.36E-02, 3.29E+03, 1.85E+00, 2.89E-01, -2.72E-01, 8.20E+00, 1.09E+00, 0.00E+00, 0.00E+00},
757  {1.36E-02, 1.16E+12, 7.40E+00, 5.36E-01, -5.42E-01, 1.23E+00, 7.26E-01, 0.00E+00, 0.00E+00}
758 };
759 const double BeamStrippingPhysics::csCoefSingleCapt_H[3][9] = {
760  {1.48E-02, 1.15E+00, 1.18E+00, 1.15E+01, 1.19E+00, 3.88E+01, 3.38E+00, 1.00E-01, 2.82E-02},
761  {1.13E-02, 3.26E+00, 1.02E+00, 2.99E+00, 4.50E-01, 1.90E+01, 3.42E+00, 0.00E+00, 0.00E+00},
762  {1.50E-02, 1.24E+03, 3.38E+00, 2.46E+00, 5.20E-01, 7.00E+00, 2.56E+00, 9.10E-02, 1.95E-02}
763 };
764 
765 // Cross sections parameters for interaction with hydrogen gas (H2)
767  2.50E-03, 2.12E+02, 1.721E+00, 6.70E-04, 3.239E-01, 4.34E-03, 1.296E+00, 1.42E-01, 9.34E+00, 2.997E+00
768 };
770  2.1E-02, 9.73E-03, 2.38E+00, 1.39E-02, -5.51E-01, 7.7E-02, 2.12E+00, 1.97E-06, 2.051E+00, 5.5E+00, 6.62E-01, 2.02E+01, 3.62E+00
771 };
773  2.0E-02, 2.53E-04, 1.728E+00, 2.164E+00, 7.74E-01, 1.639E+00, 1.43E+01, 0, 0
774 };
776  5.0E-03, 6.34E+01, 1.78E+00, 1.38E-03, 4.06E-01, 1.63E-01, 3.27E-01, 1.554E+01, 3.903E+00, 1.735, 1.02E+01
777 };
779  0.00E+00, 6.05E+00, -5.247E-01, 4.088E-03, 2.872E+00, 7.3E-03, 6.99E+00
780 };
782  2.3, 1.7E+07, -73.1505813599, -1.7569509745, -2.0016760826, -0.1902804971, 0.0171353221, 0.1270833164, -0.1523126215, 0, 0
783 };
785  1.00E+03, 1.00E+07, -79.0158996582, -2.1025185585, -1.2407282591, 0.174798578, 0.1062489152, -0.0004342734, -0.0465673618, 0, 0
786 };
788  2.6E+00, 4.00E+06, -82.5164, -6.70755, -6.10977, -2.6281, 0.709759, 0.639033, 0.10298, 0.26124, -0.263817
789 };
791  200, 1.00E+06, -95.8165, -7.17049, -7.48288, -1.93034, 0.761153, 0.556689, -0.0542859, -0.270184, -0.0147
792 };
794  2.00E+03, 1.00E+05, -70.670173645, -0.632612288, -0.6065212488, -0.0915143117, -0.0121710282, 0.0168179292, 0.0104796877, 0, 0
795 };
797  1.50E+03, 1.00E+07, -74.9261474609, -2.1944284439, -0.8558337688, 0.0421306863, 0.2162267119, 0.0921146944, -0.0893079266, 0, 0
798 };
799 const double BeamStrippingPhysics::energyRangeH2plusinH2[2] = {111.4, 7.8462E+04};
800 double BeamStrippingPhysics::a_m[9] = {};
801 double BeamStrippingPhysics::b_m[3][9] = {};
double computeCrossSectionTabata(double energy, double energyThreshold, double a1, double a2, double a3, double a4, double a5, double a6)
static OpalData * getInstance()
Definition: OpalData.cpp:196
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
virtual void print(Inform &msg) override
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
virtual void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere) override
ParticleAttrib< ParticleOrigin > POrigin
bool evalLorentzStripping(double &gamma, double &eField)
double computeCrossSectionBohr(double energy, int zTarget, double massInAmu)
static const double csCoefProtonProduction_H_Tabata[9]
ResidualGas
Definition: Vacuum.h:55
void doPhysics(PartBunchBase< double, 3 > *bunch)
static const double csCoefSingleLoss_H[3][9]
constexpr double h_bar
The reduced Planck constant in GeVs.
Definition: Physics.h:54
constexpr double m_h2p
The H2+ rest mass in GeV.
Definition: Physics.h:129
ParticleAttrib< Vector_t > P
virtual std::string getName() override
ParticleAttrib< ParticleType > PType
void computeCrossSection(double energy)
static const double energyRangeH2plusinH2[2]
double nCSA_m
macroscopic cross sections
constexpr double eV2keV
Definition: Units.h:89
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
constexpr double cm2m
Definition: Units.h:35
Definition: TSVMeta.h:24
bool asciidump
Definition: Options.cpp:85
virtual bool checkHit(const Vector_t &R)=0
ParticleAttrib< double > M
constexpr double GeV2keV
Definition: Units.h:92
static const double csCoefSingle_Hminus_Chebyshev[11]
double getTemperature() const
Definition: Vacuum.cpp:162
FmtFlags_t flags() const
Definition: Inform.h:106
Tps< T > exp(const Tps< T > &x)
Exponential.
Definition: TpsMath.h:165
double get_sPos() const
Definition: Vacuum.h:61
virtual const std::string & getName() const
Get element name.
static const double csCoefDouble_Hplus[3][9]
constexpr double pi
The value of .
Definition: Physics.h:30
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
double getdT() const
std::ios_base::fmtflags FmtFlags_t
Definition: Inform.h:99
static const double csCoefDouble_Hminus[3][9]
constexpr double m_h
The hydrogen atom rest mass in GeV.
Definition: Physics.h:126
static const double csCoefDouble_Hplus_Chebyshev[11]
void getSecondaryParticles(PartBunchBase< double, 3 > *bunch, size_t &i, bool pdead_LS)
double getT() const
constexpr double m2cm
Definition: Units.h:32
double checkPressure(const Vector_t &R)
Definition: Vacuum.cpp:298
ParticleType getPType() const
Inform & level4(Inform &inf)
Definition: Inform.cpp:48
size_t getLocalNum() const
void transformToSecondary(PartBunchBase< double, 3 > *bunch, size_t &i, ParticleType type)
Definition: Inform.h:42
std::string toStringWithThousandSep(T value, char sep= '\'')
Definition: Util.h:254
constexpr double amu
The atomic mass unit energy equivalent in GeV.
Definition: Physics.h:75
constexpr double keV2eV
Definition: Units.h:86
Inform * gmsgALL
Definition: Main.cpp:71
virtual ElementType getType() const =0
Get element type std::string.
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:56
ParticleAttrib< double > Q
std::unique_ptr< InsideTester > hitTester_m
constexpr double kB
Boltzman&#39;s constant in eV/K.
Definition: Physics.h:60
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:69
static const double csCoefProtonProduction_H2plus_Tabata[11]
static const double csCoefH3plusProduction_H2plus_Tabata[7]
static double b_m[3][9]
static const double csCoefHydrogenProduction_H2plus_Chebyshev[11]
double getGamma(Vector_t p)
Definition: Util.h:46
static const double csCoefSingleCapt_H[3][9]
constexpr double m_e
The electron rest mass in GeV.
Definition: Physics.h:78
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
const std::string name
ParticlePos_t & R
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B)
Definition: Cyclotron.cpp:417
ParticleType
ParticleIndex_t & ID
constexpr double m_p
The proton rest mass in GeV.
Definition: Physics.h:90
std::unique_ptr< LossDataSink > lossDs_m
static const double csCoefHminusProduction_H_Tabata[13]
bool evalGasStripping(double &deltas)
constexpr double GeV2eV
Definition: Units.h:68
static const double csCoefSingle_Hplus_Chebyshev[11]
constexpr double GeV2kg
Definition: Units.h:104
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
static double getParticleChargeInCoulomb(const ParticleType &type)
static const double csCoefSingle_Hplus_Tabata[10]
static const double csCoefDouble_Hminus_Chebyshev[11]
static double getParticleMass(const ParticleType &type)
ParticleAttrib< int > Bin
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
ResidualGas getResidualGas() const
Definition: Vacuum.cpp:111
std::string getResidualGasName()
Definition: Vacuum.cpp:115
BeamStrippingPhysics(const std::string &name, ElementBase *element)
static const double csCoefSingle_Hplus[3][9]
constexpr double m_hm
The H- rest mass in GeV.
Definition: Physics.h:108
constexpr double E_ryd
Rydberg&#39;s energy (Rydberg&#39;s constant times hc) in GeV.
Definition: Physics.h:63
constexpr double kG2T
Definition: Units.h:59
SDDS1 &description type
Definition: test.stat:4
constexpr double a0
Bohr radius in m.
Definition: Physics.h:66
double computeCrossSectionChebyshev(double energy, double energyMin, double energyMax)
bool getStop() const
Definition: Vacuum.cpp:175
static const double csCoefProtonProduction_H2plus_Chebyshev[11]
static std::string getParticleTypeString(const ParticleType &type)
static const double csCoefSingle_Hminus[3][9]
double computeCrossSectionNakai(double energy, double energyThreshold, int &i)