OPAL (Object Oriented Parallel Accelerator Library) 2022.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
26#include "AbsBeamline/Vacuum.h"
30#include "Physics/Physics.h"
31#include "Physics/Units.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
47namespace {
48 struct VacuumInsideTester: public InsideTester {
49 explicit VacuumInsideTester(ElementBase* el) {
50 vac_m = static_cast<Vacuum*>(el);
51 }
52 bool checkHit(const Vector_t& R) override {
53 return vac_m->checkPoint(R);
54 }
55 private:
56 Vacuum* vac_m;
57 };
58}
59
60
62 ElementBase* element):
64 pType_m(ParticleType::UNNAMED),
65 T_m(0.0),
66 dT_m(0.0),
67 mass_m(0.0),
68 pressure_m(0.0),
69 temperature_m(0.0),
70 nCSA_m(0.0),
71 nCSB_m(0.0),
72 nCSC_m(0.0),
73 nCSTotal_m(0.0),
74 bunchToMatStat_m(0),
75 stoppedPartStat_m(0),
76 rediffusedStat_m(0),
77 totalPartsInMat_m(0)
78{
79 lossDs_m = std::unique_ptr<LossDataSink>(new LossDataSink(getName(), !Options::asciidump));
80
81 const gsl_rng_type* T;
82 gsl_rng_env_setup();
83 struct timeval tv; // Seed generation based on time
84 gettimeofday(&tv,0);
85 unsigned long mySeed = tv.tv_sec + tv.tv_usec;
86 T = gsl_rng_default; // Generator setup
87 r_m = gsl_rng_alloc (T);
88 gsl_rng_set(r_m, mySeed);
89}
90
91
93 lossDs_m->save();
94 gsl_rng_free(r_m);
95}
96
97
99 const std::pair<Vector_t, double>& /*boundingSphere*/) {
100
101 ParticleType particle = bunch->getPType();
102 if (particle != ParticleType::PROTON &&
103 particle != ParticleType::DEUTERON &&
104 particle != ParticleType::HMINUS &&
105 particle != ParticleType::H2P &&
106 particle != ParticleType::HYDROGEN) {
107
109 "BeamStrippingPhysics::apply",
110 "Particle " + ParticleProperties::getParticleTypeString(particle) +
111 " is not supported for residual stripping interactions!");
112 }
113
115 hitTester_m.reset(new VacuumInsideTester(element_ref_m));
116 vac_m = dynamic_cast<Vacuum*>(element_ref_m);
117 } else {
118 throw GeneralClassicException("BeamStrippingPhysics::apply",
119 "Unsupported element type");
120 }
121
122 dT_m = bunch->getdT();
123
127
128 if (bunch->get_sPos() != 0) {
129 doPhysics(bunch);
130
132
133 if (OpalData::getInstance()->isInOPALTMode()) {
134 bunch->destroyT();
135 }
136 }
137}
138
139
141 /*
142 Do physics if
143 -- particle in material
144 -- particle not dead (bunch->Bin[i] != -1)
145 Delete particle i: bunch->Bin[i] != -1;
146 */
147 Inform gmsgALL("OPAL", INFORM_ALL_NODES);
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
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)
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)
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
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// -------------------------------------------------------------------------
466double BeamStrippingPhysics::computeCrossSectionNakai(double energy, double energyThreshold, int &i) {
467
468 if (energy <= energyThreshold) {
469 return 0.0;
470 }
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// -------------------------------------------------------------------------
493double 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// -------------------------------------------------------------------------
542double 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// -------------------------------------------------------------------------
576bool 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
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,
688 bunch->PType[i] = type;
691
692 Inform gmsgALL("OPAL", INFORM_ALL_NODES);
693 gmsgALL << level4 << getName() << ": Particle " << bunch->ID[i]
694 << " is transformed to " << ParticleProperties::getParticleTypeString(type) << endl;
695}
696
697
699 Inform::FmtFlags_t ff = msg.flags();
700 if (totalPartsInMat_m > 0) {
701 msg << level2
702 << "\n"<< "--- BeamStrippingPhysics ---\n"
703 << "Name: " << name_m << " - "
704 << "Element: " << element_ref_m->getName() << " - "
705 << "Residual gas: " << vac_m->getResidualGasName() << "\n"
706 << std::setw(31) << "Particles in the material: " << Util::toStringWithThousandSep(totalPartsInMat_m) << "\n"
707 << std::setw(31) << "Rediffused as secondary: " << Util::toStringWithThousandSep(rediffusedStat_m) << "\n"
708 << std::setw(31) << "Stripped by the gas: " << Util::toStringWithThousandSep(stoppedPartStat_m)
709 << endl;
710 }
711 msg.flags(ff);
712}
713
715
716 constexpr unsigned short numItems = 3;
717 unsigned int partStatistics[numItems] = {totalPartsInMat_m,
720
721 allreduce(&(partStatistics[0]), numItems, std::plus<unsigned int>());
722
723 totalPartsInMat_m = partStatistics[0];
724 rediffusedStat_m = partStatistics[1];
725 stoppedPartStat_m = partStatistics[2];
726}
727
728
729/*
730 Cross sections parameters for interaction with air
731 -- [1] -> Nitrogen
732 -- [2] -> Oxygen
733 -- [3] -> Argon
734*/
736 {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},
737 {-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},
738 {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}
739};
741 {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},
742 {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},
743 {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}
744};
745const double BeamStrippingPhysics::csCoefSingle_Hplus[3][9] = {
746 {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},
747 {-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},
748 {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}
749};
750const double BeamStrippingPhysics::csCoefDouble_Hplus[3][9] = {
751 {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},
752 {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},
753 {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}
754};
755const double BeamStrippingPhysics::csCoefSingleLoss_H[3][9] = {
756 {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},
757 {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},
758 {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}
759};
760const double BeamStrippingPhysics::csCoefSingleCapt_H[3][9] = {
761 {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},
762 {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},
763 {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}
764};
765
766// Cross sections parameters for interaction with hydrogen gas (H2)
768 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
769};
771 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
772};
774 2.0E-02, 2.53E-04, 1.728E+00, 2.164E+00, 7.74E-01, 1.639E+00, 1.43E+01, 0, 0
775};
777 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
778};
780 0.00E+00, 6.05E+00, -5.247E-01, 4.088E-03, 2.872E+00, 7.3E-03, 6.99E+00
781};
783 2.3, 1.7E+07, -73.1505813599, -1.7569509745, -2.0016760826, -0.1902804971, 0.0171353221, 0.1270833164, -0.1523126215, 0, 0
784};
786 1.00E+03, 1.00E+07, -79.0158996582, -2.1025185585, -1.2407282591, 0.174798578, 0.1062489152, -0.0004342734, -0.0465673618, 0, 0
787};
789 2.6E+00, 4.00E+06, -82.5164, -6.70755, -6.10977, -2.6281, 0.709759, 0.639033, 0.10298, 0.26124, -0.263817
790};
792 200, 1.00E+06, -95.8165, -7.17049, -7.48288, -1.93034, 0.761153, 0.556689, -0.0542859, -0.270184, -0.0147
793};
795 2.00E+03, 1.00E+05, -70.670173645, -0.632612288, -0.6065212488, -0.0915143117, -0.0121710282, 0.0168179292, 0.0104796877, 0, 0
796};
798 1.50E+03, 1.00E+07, -74.9261474609, -2.1944284439, -0.8558337688, 0.0421306863, 0.2162267119, 0.0921146944, -0.0893079266, 0, 0
799};
800const double BeamStrippingPhysics::energyRangeH2plusinH2[2] = {111.4, 7.8462E+04};
801double BeamStrippingPhysics::a_m[9] = {};
802double BeamStrippingPhysics::b_m[3][9] = {};
ResidualGas
Definition: Vacuum.h:55
ParticleType
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
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
std::complex< double > a
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
Inform & level4(Inform &inf)
Definition: Inform.cpp:48
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFORM_ALL_NODES
Definition: Inform.h:39
const std::string name
constexpr double kB
Boltzman's constant in eV/K.
Definition: Physics.h:60
constexpr double amu
The atomic mass unit energy equivalent in GeV.
Definition: Physics.h:75
constexpr double a0
Bohr radius in m.
Definition: Physics.h:66
constexpr double h_bar
The reduced Planck constant in GeVs.
Definition: Physics.h:54
constexpr double m_p
The proton rest mass in GeV.
Definition: Physics.h:90
constexpr double m_h2p
The H2+ rest mass in GeV.
Definition: Physics.h:129
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:69
constexpr double m_e
The electron rest mass in GeV.
Definition: Physics.h:78
constexpr double m_hm
The H- rest mass in GeV.
Definition: Physics.h:108
constexpr double E_ryd
Rydberg's energy (Rydberg's constant times hc) in GeV.
Definition: Physics.h:63
constexpr double m_h
The hydrogen atom rest mass in GeV.
Definition: Physics.h:126
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
constexpr double pi
The value of.
Definition: Physics.h:30
constexpr double GeV2keV
Definition: Units.h:92
constexpr double eV2keV
Definition: Units.h:89
constexpr double m2cm
Definition: Units.h:32
constexpr double keV2eV
Definition: Units.h:86
constexpr double cm2m
Definition: Units.h:35
constexpr double GeV2kg
Definition: Units.h:104
constexpr double GeV2eV
Definition: Units.h:68
constexpr double kG2T
Definition: Units.h:59
bool asciidump
Definition: Options.cpp:85
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:55
double getGamma(Vector_t p)
Definition: Util.h:45
std::string toStringWithThousandSep(T value, char sep='\'')
Definition: Util.h:234
boost::function< boost::tuple< double, bool >(arguments_t)> type
Definition: function.hpp:21
ParticlePos_t & R
ParticleAttrib< int > Bin
size_t getLocalNum() const
ParticleAttrib< double > M
ParticleAttrib< Vector_t > P
ParticleAttrib< ParticleType > PType
double getdT() const
ParticleAttrib< ParticleOrigin > POrigin
ParticleAttrib< double > Q
ParticleType getPType() const
ParticleIndex_t & ID
double get_sPos() const
double getT() const
static OpalData * getInstance()
Definition: OpalData.cpp:196
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B)
Definition: Cyclotron.cpp:393
virtual const std::string & getName() const
Get element name.
virtual ElementType getType() const =0
Get element type std::string.
Definition: Vacuum.h:61
ResidualGas getResidualGas() const
Definition: Vacuum.cpp:111
double checkPressure(const Vector_t &R)
Definition: Vacuum.cpp:298
double getTemperature() const
Definition: Vacuum.cpp:162
std::string getResidualGasName()
Definition: Vacuum.cpp:115
bool getStop() const
Definition: Vacuum.cpp:175
static std::string getParticleTypeString(const ParticleType &type)
static double getParticleMass(const ParticleType &type)
static double getParticleChargeInCoulomb(const ParticleType &type)
static const double csCoefProtonProduction_H_Tabata[9]
double computeCrossSectionNakai(double energy, double energyThreshold, int &i)
static const double csCoefProtonProduction_H2plus_Tabata[11]
static const double csCoefProtonProduction_H2plus_Chebyshev[11]
static const double csCoefDouble_Hminus[3][9]
static const double csCoefSingle_Hminus[3][9]
virtual void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere) override
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 doPhysics(PartBunchBase< double, 3 > *bunch)
static const double csCoefHminusProduction_H_Tabata[13]
double computeCrossSectionBohr(double energy, int zTarget, double massInAmu)
virtual void print(Inform &msg) override
static const double csCoefSingleCapt_H[3][9]
double nCSA_m
macroscopic cross sections
static const double csCoefDouble_Hplus_Chebyshev[11]
void computeCrossSection(double energy)
virtual std::string getName() override
static const double csCoefSingle_Hplus[3][9]
void transformToSecondary(PartBunchBase< double, 3 > *bunch, size_t &i, ParticleType type)
static const double csCoefSingleLoss_H[3][9]
static const double csCoefSingle_Hplus_Chebyshev[11]
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)
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
std::unique_ptr< InsideTester > hitTester_m
Definition: Inform.h:42
std::ios_base::fmtflags FmtFlags_t
Definition: Inform.h:99
FmtFlags_t flags() const
Definition: Inform.h:106
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6