OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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"
28 #include "Algorithms/PartData.h"
29 #include "Physics/Physics.h"
30 #include "Structure/LossDataSink.h"
32 #include "Utilities/Options.h"
33 #include "Utility/Inform.h"
34 
35 #include <iostream>
36 #include <fstream>
37 #include <algorithm>
38 #include <cmath>
39 #include <sys/time.h>
40 #include <boost/math/special_functions/chebyshev.hpp>
41 
42 namespace {
43  struct InsideTester {
44  virtual ~InsideTester() {}
45  virtual bool checkHit(const Vector_t& R) = 0;
46  virtual double getPressure(const Vector_t& R) = 0;
47  };
48 
49  struct BeamStrippingInsideTester: public InsideTester {
50  explicit BeamStrippingInsideTester(ElementBase* el) {
51  vac_m = static_cast<Vacuum*>(el);
52  }
53  virtual bool checkHit(const Vector_t& R) {
54  return vac_m->checkPoint(R(0), R(1), R(2));
55  }
56  double getPressure(const Vector_t& R) {
57  return vac_m->checkPressure(R(0), R(1));
58  }
59  private:
60  Vacuum* vac_m;
61  };
62 }
63 
64 
67  T_m(0.0),
68  dT_m(0.0),
69  mass_m(0.0),
70  charge_m(0.0),
71  pressure_m(0.0),
72  nCSA(0.0),
73  nCSB(0.0),
74  nCSC(0.0),
75  nCSTotal(0.0),
76  bunchToMatStat_m(0),
77  stoppedPartStat_m(0),
78  rediffusedStat_m(0),
79  totalPartsInMat_m(0)
80 {
81  vac_m = dynamic_cast<Vacuum*>(getElement());
82 
83  lossDs_m = std::unique_ptr<LossDataSink>(new LossDataSink(getName(), !Options::asciidump));
84 
85  const gsl_rng_type* T;
86  gsl_rng_env_setup();
87  struct timeval tv; // Seed generation based on time
88  gettimeofday(&tv,0);
89  unsigned long mySeed = tv.tv_sec + tv.tv_usec;
90  T = gsl_rng_default; // Generator setup
91  r_m = gsl_rng_alloc (T);
92  gsl_rng_set(r_m, mySeed);
93 }
94 
95 
97  lossDs_m->save();
98  gsl_rng_free(r_m);
99 }
100 
101 
103  const std::pair<Vector_t,
104  double>& /*boundingSphere*/) {
105 
106  ParticleType pType = bunch->getPType();
107  if (pType != ParticleType::PROTON &&
108  pType != ParticleType::DEUTERON &&
109  pType != ParticleType::HMINUS &&
110  pType != ParticleType::H2P &&
111  pType != ParticleType::HYDROGEN) {
112 
114  "BeamStrippingPhysics::apply",
115  "Particle " + bunch->getPTypeString() +
116  " is not supported for residual stripping interactions!");
117  }
118 
119  dT_m = bunch->getdT();
120 
121  if (bunch->get_sPos() != 0) {
122  doPhysics(bunch);
123  }
124 }
125 
126 
128  /*
129  Do physics if
130  -- particle in material
131  -- particle not dead (bunch->Bin[i] != -1)
132  Delete particle i: bunch->Bin[i] != -1;
133  */
134  bool stop = vac_m->getStop();
135  Vector_t extE = Vector_t(0.0, 0.0, 0.0);
136  Vector_t extB = Vector_t(0.0, 0.0, 0.0); //kGauss
137 
138  InsideTester* tester;
139  tester = new BeamStrippingInsideTester(element_ref_m);
140 
141  Inform gmsgALL("OPAL", INFORM_ALL_NODES);
142  for (size_t i = 0; i < bunch->getLocalNum(); ++i) {
143  if ( (bunch->Bin[i] != -1) && (tester->checkHit(bunch->R[i]))) {
144 
145  bool pdead_GS = false;
146  bool pdead_LS = false;
147  pressure_m = tester->getPressure(bunch->R[i]);
148  mass_m = bunch->M[i];
149  charge_m = bunch->Q[i];
150 
151  double energy = (std::sqrt(1.0 + dot(bunch->P[i], bunch->P[i])) - 1) * mass_m; //GeV
152  double gamma = (energy + mass_m) / mass_m;
153  double beta = std::sqrt(1.0 - 1.0 / (gamma * gamma));
154  double deltas = dT_m * beta * Physics::c;
155 
156  computeCrossSection(bunch, i, energy);
157  pdead_GS = evalGasStripping(deltas);
158 
159  if (bunch->PType[i] == ParticleType::HMINUS) {
160  cycl_m->apply(bunch->R[i], bunch->P[i], T_m, extE, extB);
161  double bField = 0.1 * std::sqrt(extB[0]*extB[0] + extB[1]*extB[1] + extB[2]*extB[2]); //T
162  double eField = gamma * beta * Physics::c * bField;
163  pdead_LS = evalLorentzStripping(gamma, eField);
164  }
165 
166  if (pdead_GS == true || pdead_LS == true) {
167  lossDs_m->addParticle(OpalParticle(bunch->ID[i],
168  bunch->R[i], bunch->P[i],
169  bunch->getT(),
170  bunch->Q[i], bunch->M[i]));
171  if (stop) {
172  bunch->Bin[i] = -1;
174  gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
175  << " is deleted by beam stripping" << endl;
176  } else {
177  getSecondaryParticles(bunch, i, pdead_LS);
178  //bunch->updateNumTotal();
179  gmsgALL << level4 << getName()
180  << ": Total number of particles after beam stripping = "
181  << bunch->getTotalNum() << endl;
182  }
183  }
184  }
185  }
186  delete tester;
187 }
188 
189 
191  size_t& i, double energy) {
192 
193  const double temperature = vac_m->getTemperature(); // K
194  const ParticleType& pType = bunch->PType[i];
195  const ResidualGas& gas = vac_m->getResidualGas();
196 
197  energy *=1E6; //keV
198  double energyThreshold = 0.0;
199  double a1 = 0.0;
200  double a2 = 0.0;
201  double a3 = 0.0;
202  double a4 = 0.0;
203  double a5 = 0.0;
204  double a6 = 0.0;
205  double a7 = 0.0;
206  double a8 = 0.0;
207  double a9 = 0.0;
208  double a10 = 0.0;
209  double a11 = 0.0;
210  double a12 = 0.0;
211  double molecularDensity[3] = {};
212 
213  switch (gas) {
214  case ResidualGas::H2: {
215 
216  molecularDensity[0] = 100 * pressure_m / (Physics::kB * Physics::q_e * temperature);
217  double energyMin = 0.0, energyMax = 0.0;
218  double csA = 0.0, csB = 0.0, csC = 0.0, csTotal = 0.0;
219 
220  if (pType == ParticleType::HMINUS) {
221  double energyChebyshevFit = energy * 1E3 / (Physics::m_hm / Physics::amu);
222 
223  // Single-electron detachment - Hydrogen Production
224  energyMin = csCoefSingle_Hminus_Chebyshev[0];
225  energyMax = csCoefSingle_Hminus_Chebyshev[1];
226  for (int i = 0; i < 9; ++i)
228  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
229 
230  // Double-electron detachment - Proton Production
231  energyMin = csCoefDouble_Hminus_Chebyshev[0];
232  energyMax = csCoefDouble_Hminus_Chebyshev[1];
233  for (int i = 0; i < 9; ++i)
235  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
236 
237  } else if (pType == ParticleType::PROTON) {
238  double energyChebyshevFit = energy * 1E3 / (Physics::m_p / Physics::amu);
239 
240  // Single-electron capture - Hydrogen Production
241  energyMin = csCoefSingle_Hplus_Chebyshev[0];
242  energyMax = csCoefSingle_Hplus_Chebyshev[1];
243  for (int i = 0; i < 9; ++i)
244  a_m[i] = {csCoefSingle_Hplus_Chebyshev[i+2]};
245  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
246 
247  // Double-electron capture - Hminus Production
248  energyMin = csCoefDouble_Hplus_Chebyshev[0];
249  energyMax = csCoefDouble_Hplus_Chebyshev[1];
250  for (int i = 0; i < 9; ++i)
251  a_m[i] = {csCoefDouble_Hplus_Chebyshev[i+2]};
252  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
253 
254  } else if (pType == ParticleType::DEUTERON) {
255  // Single-electron capture
256  energyThreshold = csCoefSingle_Hplus_Tabata[0];
266  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
267  computeCrossSectionTabata(energy, energyThreshold, a5, a2, a6, a7, a8, a9);
268 
269  } else if (pType == ParticleType::HYDROGEN) {
270  // Single-electron detachment - Proton Production
271  energyThreshold = csCoefProtonProduction_H_Tabata[0];
278  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
279  a5 * computeCrossSectionTabata(energy/a6, energyThreshold/a6, a1, a2, 0.0, 0.0, a3, a4);
280 
281  // Single-electron capture - Hminus Production
282  energyThreshold = csCoefHminusProduction_H_Tabata[0];
295  csB = computeCrossSectionTabata(energy, energyThreshold, a1, a2, a3, a4, a5, a6) +
296  computeCrossSectionTabata(energy, energyThreshold, a7, a8, a9, a10, a11, a12);
297 
298  } else if (pType == ParticleType::H2P) {
299  double energyChebyshevFit = energy * 1E3 / (Physics::m_h2p / Physics::amu);
300  // Proton production
301  if (energy <= energyRangeH2plusinH2[0]) {
302  energyThreshold = csCoefProtonProduction_H2plus_Tabata[0];
313  csA = computeCrossSectionTabata(energy, energyThreshold, a1, a2, 0.0, 0.0, a3, a4) +
314  computeCrossSectionTabata(energy, energyThreshold, a5, a6, 0.0, 0.0, a7, a8) +
315  a9 * computeCrossSectionTabata(energy/a10, energyThreshold/a10, a5, a6, 0.0, 0.0, a7, a8);
316 
317  } else if (energy > energyRangeH2plusinH2[0] &&
318  energy < energyRangeH2plusinH2[1]) {
321  for (int i = 0; i < 9; ++i)
323  csA = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
324 
325  } else if (energy >= energyRangeH2plusinH2[1]) {
326  int zTarget = 1;
327  double massInAmu = Physics::m_h2p / Physics::amu;
328  csA = computeCrossSectionBohr(energy, zTarget, massInAmu);
329  }
330 
331  // Hydrogen production
334  for (int i = 0; i < 9; ++i)
336  csB = computeCrossSectionChebyshev(energyChebyshevFit, energyMin, energyMax);
337 
338  // H3+, H
339  energyThreshold = csCoefH3plusProduction_H2plus_Tabata[0];
346  csC = computeCrossSectionTabata(energy, energyThreshold, a1, a2, a3, a4, a5, a6);
347  }
348  csTotal = csA + csB + csC;
349 
350  nCSA = csA * 1E-4 * molecularDensity[0];
351  nCSB = csB * 1E-4 * molecularDensity[0];
352  nCSC = csC * 1E-4 * molecularDensity[0];
353  nCSTotal = csTotal * 1E-4 * molecularDensity[0];
354  break;
355  }
356 
357  case ResidualGas::AIR: {
358 
359  int zTarget[3] = {7, 8, 18};
360  static const double fMolarFraction[3] = {0.78084, 0.20947, 0.00934}; // N2, O2, Ar
361  double csSingle[3], csDouble[3], csTotal[3];
362  double nCSSingle[3], nCSDouble[3], nCS[3];
363  double nCSSingleSum = 0.0;
364  double nCSDoubleSum = 0.0;
365  double nCSTotalSum = 0.0;
366 
367  for (int i = 0; i < 3; ++i) {
368  molecularDensity[i] = 100 * pressure_m * fMolarFraction[i] / (Physics::kB * Physics::q_e * temperature);
369 
370  if (pType == ParticleType::HMINUS) {
371  // Single-electron detachment - Hydrogen Production
372  energyThreshold = csCoefSingle_Hminus[i][0];
373  for (int j = 0; j < 8; ++j)
374  b_m[i][j] = csCoefSingle_Hminus[i][j+1];
375  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i);
376 
377  // Double-electron detachment - Proton Production
378  energyThreshold = csCoefDouble_Hminus[i][0];
379  for (int j = 0; j < 8; ++j)
380  b_m[i][j] = csCoefDouble_Hminus[i][j+1];
381  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
382 
383  } else if (pType == ParticleType::PROTON || pType == ParticleType::DEUTERON) {
384  // Single-electron capture
385  energyThreshold = csCoefSingle_Hplus[i][0];
386  for (int j = 0; j < 8; ++j)
387  b_m[i][j] = csCoefSingle_Hplus[i][j+1];
388  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
389  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
390 
391  // Double-electron capture
392  energyThreshold = csCoefDouble_Hplus[i][0];
393  for (int j = 0; j < 8; ++j)
394  b_m[i][j] = csCoefDouble_Hplus[i][j+1];
395  if (b_m[i][7] != 0) {
396  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
397  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
398  } else {
399  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
400  }
401 
402  } else if (pType == ParticleType::HYDROGEN) {
403  // Single-electron detachment - Proton Production
404  energyThreshold = csCoefSingleLoss_H[i][0];
405  for (int j = 0; j < 8; ++j)
406  b_m[i][j] = csCoefSingleLoss_H[i][j+1];
407  csSingle[i] = computeCrossSectionNakai(energy, energyThreshold, i);
408 
409  // Single-electron capture - Hminus Production
410  energyThreshold = csCoefSingleCapt_H[i][0];
411  for (int j = 0; j < 8; ++j)
412  b_m[i][j] = csCoefSingleCapt_H[i][j+1];
413  if (b_m[i][7] != 0) {
414  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i) +
415  b_m[i][6] * computeCrossSectionNakai(energy/b_m[i][7], energyThreshold/b_m[i][7], i);
416  } else {
417  csDouble[i] = computeCrossSectionNakai(energy, energyThreshold, i);
418  }
419 
420  } else if (pType == ParticleType::H2P) {
421  double massInAmu = Physics::m_h2p / Physics::amu;
422  csSingle[i] = {0.0};
423  csDouble[i] = computeCrossSectionBohr(energy, zTarget[i], massInAmu);
424 
425  } else {
426  csSingle[i] = {0.0};
427  csDouble[i] = {0.0};
428  }
429  csTotal[i] = csSingle[i] + csDouble[i];
430  nCSSingle[i] = csSingle[i] * 1E-4 * molecularDensity[i];
431  nCSDouble[i] = csDouble[i] * 1E-4 * molecularDensity[i];
432  nCS[i] = csTotal[i] * 1E-4 * molecularDensity[i];
433 
434  nCSSingleSum += nCSSingle[i];
435  nCSDoubleSum += nCSDouble[i];
436  nCSTotalSum += nCS[i];
437  }
438  nCSA = nCSSingleSum;
439  nCSB = nCSDoubleSum;
440  nCSTotal = nCSTotalSum;
441  break;
442  }
443  default: {
444  break;
445  }
446  }
447 }
448 
455 // -------------------------------------------------------------------------
456 double BeamStrippingPhysics::computeCrossSectionNakai(double energy, double energyThreshold, int &i) {
457 
458  if (energy <= energyThreshold) {
459  return 0.0;
460  }
461  const double E_R = Physics::E_ryd * 1e6 * Physics::m_h / Physics::m_e; //keV
462  const double sigma_0 = 1E-16;
463  double sigma = 0.0; //cm2
464  double effectiveEnergy = energy - energyThreshold; //keV
465  double f1 = sigma_0 * b_m[i][0] * std::pow((effectiveEnergy/E_R),b_m[i][1]);
466  if (b_m[i][2] != 0.0 && b_m[i][3] != 0.0) {
467  sigma = f1 / (1 + std::pow((effectiveEnergy/b_m[i][2]),(b_m[i][1]+b_m[i][3]))
468  + std::pow((effectiveEnergy/b_m[i][4]),(b_m[i][1]+b_m[i][5])));
469  } else {
470  sigma = f1 / (1 + std::pow((effectiveEnergy/b_m[i][4]),(b_m[i][1]+b_m[i][5])));
471  }
472 
473  return sigma;
474 }
475 
482 // -------------------------------------------------------------------------
483 double BeamStrippingPhysics::computeCrossSectionTabata(double energy, double energyThreshold,
484  double a1, double a2, double a3,
485  double a4, double a5, double a6) {
486  if (energy <= energyThreshold) {
487  return 0.0;
488  }
489  const double sigma_0 = 1E-16;
490  double sigma = 0.0; //cm2
491  double effectiveEnergy = energy - energyThreshold; //keV
492  double f1 = sigma_0 * a1 * std::pow((effectiveEnergy/(Physics::E_ryd*1e6)),a2);
493  if (a3 != 0.0 && a4 != 0.0) {
494  sigma = f1 / (1 + std::pow((effectiveEnergy/a3),(a2+a4)) + std::pow((effectiveEnergy/a5),(a2+a6)));
495  } else {
496  sigma = f1 / (1 + std::pow((effectiveEnergy/a5),(a2+a6)));
497  }
498 
499  return sigma;
500 }
501 
506 // -------------------------------------------------------------------------
508  double energyMin,
509  double energyMax) {
510  // energy -> eV/amu
511  if (energy <= energyMin || energy >= energyMax) {
512  return 0.0;
513  }
514  double sum_aT = 0.0;
515  double aT[8] = {0.0};
516  double x = ((std::log(energy)-std::log(energyMin)) - (std::log(energyMax)-std::log(energy))) / (std::log(energyMax)-std::log(energyMin));
517  for (int i = 0; i < 8; ++i) {
518  aT[i] = (a_m[i+1] * boost::math::chebyshev_t(i+1, x));
519  sum_aT += aT[i];
520  }
521  double sigma = std::exp(0.5*a_m[0] + sum_aT); //cm2
522 
523  return sigma;
524 }
525 
531 // -------------------------------------------------------------------------
532 double BeamStrippingPhysics::computeCrossSectionBohr(double energy, int zTarget, double massInAmu) {
533 
534  double energyAmu = energy / massInAmu;
535  if (energyAmu <= 1E3 || energyAmu >= 1E5) {
536  return 0.0;
537  }
538  double sigma = 0.0; //cm2
539  double mass = mass_m * 1e6;
540  const double a0v0 = Physics::h_bar * Physics::c * Physics::c / Physics::m_e;
541  double v = Physics::c * std::sqrt(1 - std::pow(mass/(energy+mass), 2.0));
542  if (zTarget < 15) {
543  double z = (zTarget + zTarget*zTarget);
544  sigma = 1E4 * 4 * Physics::pi * std::pow(a0v0, 2.0) * z / std::pow(v, 2.0);
545  } else {
546  sigma = 1E4 * 4 * Physics::pi * Physics::a0 * a0v0 * std::pow(zTarget, 2.0/3.0) / v;
547  }
548  return sigma;
549 }
550 
551 
553 
554  double xi = gsl_rng_uniform(r_m);
555  double fg = 1-std::exp(-nCSTotal*deltas);
556 
557  return (fg >= xi);
558 }
559 
564 // -------------------------------------------------------------------------
565 bool BeamStrippingPhysics::evalLorentzStripping(double& gamma, double& eField) {
566 
567  double xi = gsl_rng_uniform(r_m);
568 
569  const double eps0 = 0.75419 * Physics::q_e; // electron binding energy,
570  const double hbar = Physics::h_bar * 1E9 * Physics::q_e; // Js
571  const double me = Physics::m_e * 1E9 * Physics::q_e / (Physics::c*Physics::c);
572  const double p = 0.0126; // polarization factor
573  const double s0 = 0.783; // spectroscopic coefficient
574  const double a = 2.01407/Physics::a0;
575  const double k0 = std::sqrt(2 * me * eps0)/hbar;
576  const double n = (std::sqrt(2 * k0 * (k0+a) * (2*k0+a)))/a; // normalization factor
577  double zT = eps0 / (Physics::q_e * eField);
578  double tau = (4 * me * zT)/(s0 * n * n * hbar * (1+p)*(1+p) * (1-1/(2*k0*zT))) * std::exp(4*k0*zT/3);
579  double fL = 1 - std::exp( -dT_m / (gamma * tau));
580 
581  return (fL >= xi);
582 }
583 
585  size_t& i, bool pdead_LS) {
586  double r = gsl_rng_uniform(r_m);
587 
588  const ParticleType& pType = bunch->PType[i];
589  const ResidualGas& gas = vac_m->getResidualGas();
590 
591  // change mass_m and charge_m
592  if (pType == ParticleType::HMINUS) {
593  if (pdead_LS == true) {
594  transformToHydrogen(bunch, i);
595  } else {
596  if (r > nCSB/nCSTotal)
597  transformToHydrogen(bunch, i);
598  else
599  transformToProton(bunch, i);
600  }
601 
602  } else if (pType == ParticleType::PROTON) {
603  if (r > nCSB/nCSTotal)
604  transformToHydrogen(bunch, i);
605  else
606  transformToHminus(bunch, i);
607 
608  } else if (pType == ParticleType::HYDROGEN) {
609  if (r > nCSB/nCSTotal)
610  transformToProton(bunch, i);
611  else
612  transformToHminus(bunch, i);
613 
614  } else if (pType == ParticleType::H2P) {
615  if (gas == ResidualGas::H2) {
616  if (nCSC>nCSB && nCSB>nCSA) {
617  if (r > (nCSA+nCSB)/nCSTotal)
618  transformToH3plus(bunch, i);
619  else if (r > nCSA/nCSTotal)
620  transformToHydrogen(bunch, i);
621  else
622  transformToProton(bunch, i);
623 
624  } else if (nCSA>nCSB && nCSB>nCSC) {
625  if (r > (nCSC+nCSB)/nCSTotal)
626  transformToProton(bunch, i);
627  else if (r > nCSC/nCSTotal)
628  transformToHydrogen(bunch, i);
629  else
630  transformToH3plus(bunch, i);
631 
632  } else if (nCSA>nCSB && nCSC>nCSA) {
633  if (r > (nCSA+nCSB)/nCSTotal)
634  transformToH3plus(bunch, i);
635  else if (r > nCSB/nCSTotal)
636  transformToProton(bunch, i);
637  else
638  transformToHydrogen(bunch, i);
639 
640  } else if (nCSA>nCSC && nCSC>nCSB) {
641  if (r > (nCSC+nCSB)/nCSTotal)
642  transformToProton(bunch, i);
643  else if (r > nCSB/nCSTotal)
644  transformToH3plus(bunch, i);
645  else
646  transformToHydrogen(bunch, i);
647 
648  } else if (nCSB>nCSC && nCSB>nCSA && nCSA>nCSC) {
649  if (r > (nCSC+nCSA)/nCSTotal)
650  transformToHydrogen(bunch, i);
651  else if (r > nCSC/nCSTotal)
652  transformToProton(bunch, i);
653  else
654  transformToH3plus(bunch, i);
655 
656  } else {
657  if (r > (nCSC+nCSA)/nCSTotal)
658  transformToHydrogen(bunch, i);
659  else if (r > nCSA/nCSTotal)
660  transformToH3plus(bunch, i);
661  else
662  transformToProton(bunch, i);
663  }
664  } else if (gas == ResidualGas::AIR) {
665  if (r > nCSTotal)
666  transformToProton(bunch, i);
667  }
668  } else if (pType == ParticleType::DEUTERON) {
669  GeneralClassicException("BeamStrippingPhysics::getSecondaryParticles",
670  "Tracking secondary particles from incident "
671  "ParticleType::DEUTERON is not implemented");
672  }
673 
675 
676  if (bunch->weHaveBins())
677  bunch->Bin[bunch->getLocalNum()-1] = bunch->Bin[i];
678 }
679 
681  Inform gmsgALL("OPAL", INFORM_ALL_NODES);
682  gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
683  << " is transformed to proton" << endl;
684  bunch->M[i] = Physics::m_p;
685  bunch->Q[i] = Physics::q_e;
686  bunch->PType[i] = ParticleType::PROTON;
687 }
688 
690  Inform gmsgALL("OPAL", INFORM_ALL_NODES);
691  gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
692  << " is transformed to neutral hydrogen" << endl;
693  bunch->M[i] = Physics::m_h;
694  bunch->Q[i] = 0.0;
695  bunch->PType[i] = ParticleType::HYDROGEN;
696 }
697 
699  Inform gmsgALL("OPAL", INFORM_ALL_NODES);
700  gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
701  << " is transformed to negative hydrogen ion" << endl;
702  bunch->M[i] = Physics::m_hm;
703  bunch->Q[i] = -Physics::q_e;
704  bunch->PType[i] = ParticleType::HMINUS;
705 }
706 
708  Inform gmsgALL("OPAL", INFORM_ALL_NODES);
709  gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
710  << " is transformed to H3+" << endl;
711  bunch->M[i] = Physics::m_h3p;
712  bunch->Q[i] = Physics::q_e;
713  bunch->PType[i] = ParticleType::H3P;
714 }
715 
717 }
718 
720  return totalPartsInMat_m != 0;
721 }
722 
723 /*
724  Cross sections parameters for interaction with air
725  -- [1] -> Nitrogen
726  -- [2] -> Oxygen
727  -- [3] -> Argon
728 */
729 const double BeamStrippingPhysics::csCoefSingle_Hminus[3][9] = {
730  {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},
731  {-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},
732  {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}
733 };
734 const double BeamStrippingPhysics::csCoefDouble_Hminus[3][9] = {
735  {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},
736  {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},
737  {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}
738 };
739 const double BeamStrippingPhysics::csCoefSingle_Hplus[3][9] = {
740  {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},
741  {-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},
742  {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}
743 };
744 const double BeamStrippingPhysics::csCoefDouble_Hplus[3][9] = {
745  {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},
746  {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},
747  {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}
748 };
749 const double BeamStrippingPhysics::csCoefSingleLoss_H[3][9] = {
750  {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},
751  {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},
752  {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}
753 };
754 const double BeamStrippingPhysics::csCoefSingleCapt_H[3][9] = {
755  {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},
756  {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},
757  {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}
758 };
759 
760 // Cross sections parameters for interaction with hydrogen gas (H2)
762  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
763 };
765  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
766 };
768  2.0E-02, 2.53E-04, 1.728E+00, 2.164E+00, 7.74E-01, 1.639E+00, 1.43E+01, 0, 0
769 };
771  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
772 };
774  0.00E+00, 6.05E+00, -5.247E-01, 4.088E-03, 2.872E+00, 7.3E-03, 6.99E+00
775 };
777  2.3, 1.7E+07, -73.1505813599, -1.7569509745, -2.0016760826, -0.1902804971, 0.0171353221, 0.1270833164, -0.1523126215, 0, 0
778 };
780  1.00E+03, 1.00E+07, -79.0158996582, -2.1025185585, -1.2407282591, 0.174798578, 0.1062489152, -0.0004342734, -0.0465673618, 0, 0
781 };
783  2.6E+00, 4.00E+06, -82.5164, -6.70755, -6.10977, -2.6281, 0.709759, 0.639033, 0.10298, 0.26124, -0.263817
784 };
786  200, 1.00E+06, -95.8165, -7.17049, -7.48288, -1.93034, 0.761153, 0.556689, -0.0542859, -0.270184, -0.0147
787 };
789  2.00E+03, 1.00E+05, -70.670173645, -0.632612288, -0.6065212488, -0.0915143117, -0.0121710282, 0.0168179292, 0.0104796877, 0, 0
790 };
792  1.50E+03, 1.00E+07, -74.9261474609, -2.1944284439, -0.8558337688, 0.0421306863, 0.2162267119, 0.0921146944, -0.0893079266, 0, 0
793 };
794 const double BeamStrippingPhysics::energyRangeH2plusinH2[2] = {111.4, 7.8462E+04};
795 double BeamStrippingPhysics::a_m[9] = {};
796 double BeamStrippingPhysics::b_m[3][9] = {};
ResidualGas
Definition: Vacuum.h:61
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Tps< T > exp(const Tps< T > &x)
Exponential.
Definition: TpsMath.h:165
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
ParticleType
Definition: PartBunchBase.h:50
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Inform & level4(Inform &inf)
Definition: Inform.cpp:48
#define INFORM_ALL_NODES
Definition: Inform.h:39
const std::string name
constexpr double kB
Boltzman's constant in eV/K.
Definition: Physics.h:66
constexpr double amu
The atomic mass unit energy equivalent in GeV.
Definition: Physics.h:81
constexpr double a0
Bohr radius in m.
Definition: Physics.h:72
constexpr double h_bar
The reduced Planck constant in GeVs.
Definition: Physics.h:60
constexpr double m_p
The proton rest mass in GeV.
Definition: Physics.h:96
constexpr double m_h3p
The H3+ rest mass in GeV.
Definition: Physics.h:138
constexpr double m_h2p
The H2+ rest mass in GeV.
Definition: Physics.h:135
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:75
constexpr double m_e
The electron rest mass in GeV.
Definition: Physics.h:84
constexpr double m_hm
The H- rest mass in GeV.
Definition: Physics.h:114
constexpr double E_ryd
Rydberg's energy (Rydberg's constant times hc) in GeV.
Definition: Physics.h:69
constexpr double m_h
The hydrogen atom rest mass in GeV.
Definition: Physics.h:132
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:51
constexpr double pi
The value of.
Definition: Physics.h:30
bool asciidump
Definition: Options.cpp:85
ParticlePos_t & R
ParticleAttrib< int > Bin
std::string getPTypeString()
size_t getLocalNum() const
ParticleAttrib< double > M
size_t getTotalNum() const
ParticleAttrib< Vector_t > P
ParticleAttrib< ParticleType > PType
double getdT() const
ParticleAttrib< ParticleOrigin > POrigin
bool weHaveBins() const
ParticleAttrib< double > Q
ParticleType getPType() const
ParticleIndex_t & ID
double get_sPos() const
double getT() const
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B)
Definition: Cyclotron.cpp:385
Definition: Vacuum.h:67
ResidualGas getResidualGas() const
Definition: Vacuum.cpp:148
double getTemperature() const
Definition: Vacuum.cpp:110
int checkPoint(const double &x, const double &y, const double &z)
Definition: Vacuum.cpp:261
virtual bool getStop() const
Definition: Vacuum.cpp:171
static const double csCoefProtonProduction_H_Tabata[9]
double computeCrossSectionNakai(double energy, double energyThreshold, int &i)
static const double csCoefProtonProduction_H2plus_Tabata[11]
double nCSA
macroscopic cross sections
static const double csCoefProtonProduction_H2plus_Chebyshev[11]
static const double csCoefDouble_Hminus[3][9]
virtual std::string getName()
static const double csCoefSingle_Hminus[3][9]
void getSecondaryParticles(PartBunchBase< double, 3 > *bunch, size_t &i, bool pdead_LS)
double computeCrossSectionChebyshev(double energy, double energyMin, double energyMax)
static const double csCoefSingle_Hminus_Chebyshev[11]
static const double energyRangeH2plusinH2[2]
static const double csCoefSingle_Hplus_Tabata[10]
void transformToHydrogen(PartBunchBase< double, 3 > *bunch, size_t &i)
void doPhysics(PartBunchBase< double, 3 > *bunch)
static const double csCoefHminusProduction_H_Tabata[13]
double computeCrossSectionBohr(double energy, int zTarget, double massInAmu)
static const double csCoefSingleCapt_H[3][9]
static const double csCoefDouble_Hplus_Chebyshev[11]
virtual void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere)
static const double csCoefSingle_Hplus[3][9]
void transformToH3plus(PartBunchBase< double, 3 > *bunch, size_t &i)
void transformToHminus(PartBunchBase< double, 3 > *bunch, size_t &i)
static const double csCoefSingleLoss_H[3][9]
static const double csCoefSingle_Hplus_Chebyshev[11]
virtual void print(Inform &msg)
void computeCrossSection(PartBunchBase< double, 3 > *bunch, size_t &i, double energy)
BeamStrippingPhysics(const std::string &name, ElementBase *element)
double computeCrossSectionTabata(double energy, double energyThreshold, double a1, double a2, double a3, double a4, double a5, double a6)
void transformToProton(PartBunchBase< double, 3 > *bunch, size_t &i)
bool evalLorentzStripping(double &gamma, double &eField)
std::unique_ptr< LossDataSink > lossDs_m
bool evalGasStripping(double &deltas)
static const double csCoefHydrogenProduction_H2plus_Chebyshev[11]
static const double csCoefH3plusProduction_H2plus_Tabata[7]
static double b_m[3][9]
static const double csCoefDouble_Hminus_Chebyshev[11]
static const double csCoefDouble_Hplus[3][9]
virtual bool checkHit(const Vector_t &R)=0
Definition: Inform.h:42
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6