OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
ScatteringPhysics.cpp
Go to the documentation of this file.
1//
2// Class ScatteringPhysics
3// Defines the physical processes of beam scattering
4// and energy loss by heavy charged particles
5//
6// Copyright (c) 2009 - 2022, Bi, Yang, Stachel, Adelmann
7// Paul Scherrer Institut, Villigen PSI, Switzerland
8// All rights reserved.
9//
10// This file is part of OPAL.
11//
12// OPAL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation, either version 3 of the License, or
15// (at your option) any later version.
16//
17// You should have received a copy of the GNU General Public License
18// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
19//
21
26#include "AbsBeamline/Drift.h"
27#include "AbsBeamline/SBend.h"
28#include "AbsBeamline/RBend.h"
30#include "Physics/Material.h"
32#include "Physics/Physics.h"
33#include "Physics/Units.h"
35#include "Utilities/Options.h"
37#include "Utilities/Util.h"
38#include "Utilities/Timer.h"
39
40#include "Utility/Inform.h"
41
42#include <gsl/gsl_randist.h>
43
44#include <algorithm>
45#include <cmath>
46#include <fstream>
47#include <iostream>
48
49#include <sys/time.h>
50
51namespace {
52 struct DegraderInsideTester: public InsideTester {
53 explicit DegraderInsideTester(ElementBase* el) {
54 deg_m = static_cast<Degrader*>(el);
55 }
56 bool checkHit(const Vector_t& R) override {
57 return deg_m->isInMaterial(R(2));
58 }
59 private:
60 Degrader* deg_m;
61 };
62
63 struct CollimatorInsideTester: public InsideTester {
64 explicit CollimatorInsideTester(ElementBase* el) {
65 col_m = static_cast<CCollimator*>(el);
66 }
67 bool checkHit(const Vector_t& R) override {
68 return col_m->checkPoint(R(0), R(1));
69 }
70 private:
71 CCollimator* col_m;
72 };
73
74 struct FlexCollimatorInsideTester: public InsideTester {
75 explicit FlexCollimatorInsideTester(ElementBase* el) {
76 col_m = static_cast<FlexibleCollimator*>(el);
77 }
78 bool checkHit(const Vector_t& R) override {
79 return col_m->isStopped(R);
80 }
81 private:
82 FlexibleCollimator* col_m;
83 };
84
85 constexpr long double operator"" _keV(long double value) { return value; }
86 constexpr long double operator"" _MeV(long double value) { return value * 1e3; }
87 constexpr long double operator"" _GeV(long double value) { return value * 1e6; }
88}
89
91 ElementBase* element,
92 std::string& material,
93 bool enableRutherford,
94 double lowEnergyThr):
96 T_m(0.0),
97 dT_m(0.0),
98 mass_m(0.0),
99 charge_m(0.0),
100 material_m(material),
101 Z_m(0),
102 A_m(0.0),
103 rho_m(0.0),
104 X0_m(0.0),
105 I_m(0.0),
106 A1_c(0.0),
107 A2_c(0.0),
108 A3_c(0.0),
109 A4_c(0.0),
110 A5_c(0.0),
111 B1_c(0.0),
112 B2_c(0.0),
113 B3_c(0.0),
114 B4_c(0.0),
115 B5_c(0.0),
116 bunchToMatStat_m(0),
117 stoppedPartStat_m(0),
118 rediffusedStat_m(0),
119 totalPartsInMat_m(0),
120 Eavg_m(0.0),
121 Emax_m(0.0),
122 Emin_m(0.0),
123 enableRutherford_m(enableRutherford),
124 lowEnergyThr_m(lowEnergyThr)
125{
126
127 gsl_rng_env_setup();
128 rGen_m = gsl_rng_alloc(gsl_rng_default);
129
130 size_t mySeed = Options::seed;
131
132 if (Options::seed == -1) {
133 struct timeval tv;
134 gettimeofday(&tv,0);
135 mySeed = tv.tv_sec + tv.tv_usec;
136 }
137
138 gsl_rng_set(rGen_m, mySeed + Ippl::myNode());
139
141
142 ElementType collshape = element_ref_m->getType();
143 switch (collshape) {
145 hitTester_m.reset(new DegraderInsideTester(element_ref_m));
146 break;
148 hitTester_m.reset(new CollimatorInsideTester(element_ref_m));
149 break;
151 hitTester_m.reset(new FlexCollimatorInsideTester(element_ref_m));
152 break;
153 default:
154 throw GeneralClassicException("ScatteringPhysics::ScatteringPhysics",
155 "Unsupported element type");
156 }
157
158 lossDs_m = std::unique_ptr<LossDataSink>(new LossDataSink(getName(), !Options::asciidump));
159
163}
164
166 locParts_m.clear();
167 lossDs_m->save();
168 if (rGen_m)
169 gsl_rng_free(rGen_m);
170}
171
172
174// ------------------------------------------------------------------------
177 Z_m = material->getAtomicNumber();
178 A_m = material->getAtomicMass();
179 rho_m = material->getMassDensity();
180 X0_m = material->getRadiationLength();
181 I_m = material->getMeanExcitationEnergy();
182 A1_c = material->getStoppingPowerFitCoefficients(Physics::Material::A1);
183 A2_c = material->getStoppingPowerFitCoefficients(Physics::Material::A2);
184 A3_c = material->getStoppingPowerFitCoefficients(Physics::Material::A3);
185 A4_c = material->getStoppingPowerFitCoefficients(Physics::Material::A4);
186 A5_c = material->getStoppingPowerFitCoefficients(Physics::Material::A5);
187 B1_c = material->getStoppingPowerFitCoefficients(Physics::Material::B1);
188 B2_c = material->getStoppingPowerFitCoefficients(Physics::Material::B2);
189 B3_c = material->getStoppingPowerFitCoefficients(Physics::Material::B3);
190 B4_c = material->getStoppingPowerFitCoefficients(Physics::Material::B4);
191 B5_c = material->getStoppingPowerFitCoefficients(Physics::Material::B5);
192}
193
195 const std::pair<Vector_t, double>& boundingSphere) {
197
198 /*
199 Particles that have entered material are flagged as Bin[i] == -1.
200
201 Flagged particles are copied to a local structure within Scattering Physics locParts_m.
202
203 Particles in that structure will be pushed in the material and either come
204 back to the bunch or will be fully stopped in the material.
205 */
206
207 ParticleType pType = bunch->getPType();
208 if (pType != ParticleType::PROTON &&
209 pType != ParticleType::DEUTERON &&
210 pType != ParticleType::HMINUS &&
211 pType != ParticleType::MUON &&
212 pType != ParticleType::H2P &&
213 pType != ParticleType::ALPHA) {
214
216 "ScatteringPhysics::apply",
217 "Particle " + ParticleProperties::getParticleTypeString(pType) +
218 " is not supported for scattering interactions!");
219 }
220
221 Eavg_m = 0.0;
222 Emax_m = 0.0;
223 Emin_m = 0.0;
224
229
230 dT_m = bunch->getdT();
231 T_m = bunch->getT();
232 mass_m = bunch->getM();
233 charge_m = bunch->getQ();
234
235 bool onlyOneLoopOverParticles = !(allParticleInMat_m);
236
237 do {
239 push();
241
242 // if we are not looping copy newly arrived particles
243 if (onlyOneLoopOverParticles) {
244 copyFromBunch(bunch, boundingSphere);
245 }
246 addBackToBunch(bunch);
247
248 computeInteraction(bunch);
249
250 push();
252
254
255 T_m += dT_m; // update local time
256
258
259 if (allParticleInMat_m) {
260 onlyOneLoopOverParticles = (rediffusedStat_m > 0 || totalPartsInMat_m <= 0);
261 } else {
262 onlyOneLoopOverParticles = true;
263 }
264 } while (onlyOneLoopOverParticles == false);
265
267}
268
270 /*
271 Do physics if
272 -- correct type of particle
273 -- particle not stopped (locParts_m[i].label != -1.0)
274
275 Absorbed particle i: locParts_m[i].label = -1.0;
276 */
277 for (size_t i = 0; i < locParts_m.size(); ++i) {
278 if (locParts_m[i].label != -1) {
279 Vector_t& R = locParts_m[i].Rincol;
280 Vector_t& P = locParts_m[i].Pincol;
281 double& dt = locParts_m[i].DTincol;
282
283 if (hitTester_m->checkHit(R)) {
284 bool pdead = computeEnergyLoss(bunch, P, dt);
285 if (!pdead) {
286 /*
287 Now scatter and transport particle in material.
288 The checkHit call just above will detect if the
289 particle is rediffused from the material into vacuum.
290 */
291
293 } else {
294 // The particle is stopped in the material, set label to -1
295 locParts_m[i].label = -1.0;
297 lossDs_m->addParticle(OpalParticle(locParts_m[i].IDincol,
298 R, P, T_m,
299 locParts_m[i].Qincol, locParts_m[i].Mincol));
300
301 if (OpalData::getInstance()->isInOPALCyclMode()) {
302 // OpalCycl performs particle deletion in ParallelCyclotronTracker.
303 // Particles lost by scattering have to be returned to the bunch
304 // with a negative Bin attribute to avoid miscounting of particles.
305 // Only the minimal number of attributes are fixed because the
306 // particle is marked for deletion (Bin<0)
307
308 addParticleBackToBunch(bunch, locParts_m[i], pdead);
309 }
310 }
311 }
312 }
313 }
314
315 // delete absorbed particles
317}
318
325// -------------------------------------------------------------------------
327 Vector_t& P,
328 const double deltat,
329 bool includeFluctuations) const {
330
331 ParticleType pType = bunch->getPType();
332
333 const double mass_keV = mass_m * Units::eV2keV;
334 constexpr double massElectron_keV = Physics::m_e * Units::GeV2keV;
335
336 constexpr double K = (4.0 * Physics::pi * Physics::Avo * Physics::r_e
337 * Units::m2cm * Physics::r_e * Units::m2cm * massElectron_keV);
338
339 double gamma = Util::getGamma(P);
340 const double gammaSqr = std::pow(gamma, 2);
341 const double betaSqr = 1.0 - 1.0 / gammaSqr;
342 double beta = std::sqrt(betaSqr);
343 double Ekin_keV = (gamma - 1) * mass_keV;
344 double dEdx = 0.0;
345 double epsilon = 0.0;
346
347 const double deltas = deltat * beta * Physics::c;
348 const double deltasrho = deltas * Units::m2cm * rho_m;
349
350 const double massRatio = massElectron_keV / mass_keV;
351 double Tmax = (2.0 * massElectron_keV * betaSqr * gammaSqr /
352 (std::pow(gamma + massRatio, 2) - (gammaSqr - 1.0)));
353
354 if (pType != ParticleType::ALPHA) {
355
356 if (Ekin_keV >= 0.6_MeV && Ekin_keV < 10.0_GeV) {
357 dEdx = (-K * std::pow(charge_m, 2) * Z_m / (A_m * betaSqr) *
358 (0.5 * std::log(2 * massElectron_keV * betaSqr * gammaSqr * Tmax / std::pow(I_m * Units::eV2keV, 2)) - betaSqr));
359 } else if (pType == ParticleType::PROTON && Ekin_keV < 0.6_MeV) {
360 constexpr double massProton_amu = Physics::m_p / Physics::amu;
361 const double Ts = Ekin_keV / massProton_amu;
362 if (Ekin_keV > 10.0_keV) {
363 const double epsilon_low = A2_c * std::pow(Ts, 0.45);
364 const double epsilon_high = (A3_c / Ts) * std::log(1 + (A4_c / Ts) + (A5_c * Ts));
365 epsilon = (epsilon_low * epsilon_high) / (epsilon_low + epsilon_high);
366 } else if (Ekin_keV > 1.0_keV) {
367 epsilon = A1_c * std::pow(Ts, 0.5);
368 }
369 dEdx = -epsilon / (1e18 * (A_m / Physics::Avo));
370 } else {
371 INFOMSG(level4 << "Particle energy out of the valid range "
372 "for energy loss calculation." << endl);
373 }
374 } else {
375 if (Ekin_keV > 10.0_MeV && Ekin_keV < 1.0_GeV) {
376 dEdx = (-K * std::pow(charge_m, 2) * Z_m / (A_m * betaSqr) *
377 (0.5 * std::log(2 * massElectron_keV * betaSqr * gammaSqr * Tmax / std::pow(I_m * Units::eV2keV, 2)) - betaSqr));
378 } else if (Ekin_keV > 1.0_keV && Ekin_keV <= 10.0_MeV) {
379 const double T = Ekin_keV * Units::keV2MeV;
380 const double epsilon_low = B1_c * std::pow(T * Units::MeV2keV, B2_c);
381 const double epsilon_high = (B3_c / T) * std::log(1 + (B4_c / T) + (B5_c * T));
382 epsilon = (epsilon_low * epsilon_high) / (epsilon_low + epsilon_high);
383 dEdx = -epsilon / (1e18 * (A_m / Physics::Avo));
384 } else {
385 INFOMSG(level4 << "Particle energy out of the valid range "
386 "for energy loss calculation." << endl);
387 }
388 }
389
390 Ekin_keV += deltasrho * dEdx;
391
392 if (includeFluctuations) {
393 double sigma_E = std::sqrt(K * massElectron_keV * rho_m * (Z_m / A_m) * deltas * Units::m2cm);
394 Ekin_keV += gsl_ran_gaussian(rGen_m, sigma_E);
395 }
396
397 gamma = Ekin_keV / mass_keV + 1.0;
398 beta = std::sqrt(1.0 - 1.0 / std::pow(gamma, 2));
399 P = gamma * beta * P / euclidean_norm(P);
400
401 bool stopped = (Ekin_keV < lowEnergyThr_m * Units::MeV2keV || dEdx > 0);
402 return stopped;
403}
404
405
406// Implement the rotation in 2 dimensions here
407// For details see: J. Beringer et al. (Particle Data Group),
408// "Passage of particles through matter", Phys. Rev. D 86, 010001 (2012)
409// -------------------------------------------------------------------------
411 Vector_t& R,
412 double shift,
413 double thetacou) {
414 // Calculate the angle between the transverse and longitudinal component of the momentum
415 double Psixz = std::fmod(std::atan2(P(0), P(2)) + Physics::two_pi, Physics::two_pi);
416
417 R(0) = R(0) + shift * std::cos(Psixz);
418 R(2) = R(2) - shift * std::sin(Psixz);
419
420 // Apply the rotation about the random angle thetacou
421 double Px = P(0);
422 P(0) = Px * std::cos(thetacou) + P(2) * std::sin(thetacou);
423 P(2) = -Px * std::sin(thetacou) + P(2) * std::cos(thetacou);
424}
425
427
428 double thetaru = 2.5 / std::sqrt(gsl_rng_uniform(rGen_m)) * 2.0 * theta0;
429 double phiru = Physics::two_pi * gsl_rng_uniform(rGen_m);
430
431 double normPtrans = std::sqrt(P(0) * P(0) + P(1) * P(1));
432 double Theta = std::atan(normPtrans / std::abs(P(2)));
433 double CosT = std::cos(Theta);
434 double SinT = std::sin(Theta);
435
436 Vector_t X(std::cos(phiru)*std::sin(thetaru),
437 std::sin(phiru)*std::sin(thetaru),
438 std::cos(thetaru));
439 X *= euclidean_norm(P);
440
441 Vector_t W(-P(1), P(0), 0.0);
442 W = W / normPtrans;
443
444 // Rodrigues' formula for a rotation about W by angle Theta
445 P = X * CosT + cross(W, X) * SinT + W * dot(W, X) * (1.0 - CosT);
446}
447
450//--------------------------------------------------------------------------
452 Vector_t& P,
453 double dt) {
454
455 constexpr double sqrtThreeInv = 0.57735026918962576451; // sqrt(1.0 / 3.0)
456 const double normP = euclidean_norm(P);
457 const double beta = euclidean_norm(Util::getBeta(P));
458 const double deltas = dt * beta * Physics::c;
459 const double theta0 = (13.6e6 / (beta * normP * mass_m) *
460 charge_m * std::sqrt(deltas / X0_m) *
461 (1.0 + 0.038 * std::log(deltas / X0_m)));
462
463 double phi = Physics::two_pi * gsl_rng_uniform(rGen_m);
464 for (unsigned int i = 0; i < 2; ++ i) {
465 CoordinateSystemTrafo randomTrafo(R, Quaternion(cos(phi), 0, 0, sin(phi)));
466 P = randomTrafo.rotateTo(P);
467 R = Vector_t(0.0); // corresponds to randomTrafo.transformTo(R);
468
469 double z1 = gsl_ran_gaussian(rGen_m, 1.0);
470 double z2 = gsl_ran_gaussian(rGen_m, 1.0);
471
472 while(std::abs(z2) > 3.5) {
473 z1 = gsl_ran_gaussian(rGen_m, 1.0);
474 z2 = gsl_ran_gaussian(rGen_m, 1.0);
475 }
476
477 double thetacou = z2 * theta0;
478 double shift = (z1 * sqrtThreeInv + z2) * deltas * theta0 * 0.5;
479 applyRotation(P, R, shift, thetacou);
480
481 P = randomTrafo.rotateFrom(P);
482 R = randomTrafo.transformFrom(R);
483
484 phi += 0.5 * Physics::pi;
485 }
486
487 if (enableRutherford_m && gsl_rng_uniform(rGen_m) < 0.0047) {
488 applyRandomRotation(P, theta0);
489 }
490}
491
493
494 const size_t nL = locParts_m.size();
495 if (nL == 0) return;
496
497 const double elementLength = element_ref_m->getElementLength();
498
499 for (size_t i = 0; i < nL; ++ i) {
500 Vector_t& R = locParts_m[i].Rincol;
501
502 if ( (OpalData::getInstance()->isInOPALTMode() && R[2] >= elementLength) ||
503 (OpalData::getInstance()->isInOPALCyclMode() && !(hitTester_m->checkHit(R))) ) {
504
506
507 /*
508 This particle is back to the bunch, by setting the
509 label to -1.0 the particle will be deleted.
510 */
511 locParts_m[i].label = -1.0;
512
514 }
515 }
516
517 // delete particles that went to the bunch
519}
520
522 const PART& particle, bool pdead) {
523
524 unsigned int numLocalParticles = bunch->getLocalNum();
525
526 bunch->createWithID(particle.IDincol);
527
528 if (!pdead) {
529 bunch->Bin[numLocalParticles] = 1;
530 } else {
531 bunch->Bin[numLocalParticles] = -1;
532 }
533
534 bunch->R[numLocalParticles] = particle.Rincol;
535 bunch->P[numLocalParticles] = particle.Pincol;
536 bunch->Q[numLocalParticles] = particle.Qincol;
537 bunch->M[numLocalParticles] = particle.Mincol;
538 bunch->Bf[numLocalParticles] = 0.0;
539 bunch->Ef[numLocalParticles] = 0.0;
540 bunch->dt[numLocalParticles] = dT_m;
541}
542
543
545 const std::pair<Vector_t, double>& boundingSphere)
546{
547 const size_t nL = bunch->getLocalNum();
548 if (nL == 0) return;
549
551 double zmax = boundingSphere.first(2) + boundingSphere.second;
552 double zmin = boundingSphere.first(2) - boundingSphere.second;
553 if (zmax < 0.0 || zmin > element_ref_m->getElementLength()) {
555 return;
556 }
557
558 size_t ne = 0;
559 std::set<size_t> partsToDel;
560 for (size_t i = 0; i < nL; ++ i) {
561 if ((bunch->Bin[i] == -1 || bunch->Bin[i] == 1) &&
562 hitTester_m->checkHit(bunch->R[i]))
563 {
564 double tau = 1.0;
565 if (OpalData::getInstance()->isInOPALTMode()) {
566 // The z-coordinate is only Opal-T mode the longitudinal coordinate and
567 // the case when elements with ScatteringPhysics solver are closer than one
568 // time step needs to be handled, which isn't done yet in Opal-cycl.
569
570 // Adjust the time step for those particles that enter the material
571 // such that it corresponds to the time needed to reach the current
572 // location form the edge of the material. Only use this time step
573 // for the computation of the interaction with the material, not for
574 // the integration of the particles. This will ensure that the momenta
575 // of all particles are reduced by approximately the same amount in
576 // computeEnergyLoss.
577
578 double betaz = bunch->P[i](2) / Util::getGamma(bunch->P[i]);
579 double stepWidth = betaz * Physics::c * bunch->dt[i];
580 tau = bunch->R[i](2) / stepWidth;
581
582 PAssert_LE(tau, 1.0);
583 PAssert_GE(tau, 0.0);
584 }
585
586 PART x;
587 x.localID = i;
588 x.DTincol = bunch->dt[i] * tau;
589 x.IDincol = bunch->ID[i];
590 x.Binincol = bunch->Bin[i];
591 x.Rincol = bunch->R[i];
592 x.Pincol = bunch->P[i];
593 x.Qincol = bunch->Q[i];
594 x.Mincol = bunch->M[i];
595 x.Bfincol = bunch->Bf[i];
596 x.Efincol = bunch->Ef[i];
597 x.label = 0; // alive in matter
598
599 locParts_m.push_back(x);
600 ++ne;
602
603 partsToDel.insert(i);
604 }
605 }
606
607 for (auto it = partsToDel.begin(); it != partsToDel.end(); ++ it) {
608 bunch->destroy(1, *it);
609 }
610
611 if (ne > 0) {
612 bunch->performDestroy(true);
613 }
614
616}
617
619 Inform::FmtFlags_t ff = msg.flags();
620 if (totalPartsInMat_m > 0 ||
621 bunchToMatStat_m > 0 ||
622 rediffusedStat_m > 0 ||
623 stoppedPartStat_m > 0) {
624
625 OPALTimer::Timer time;
626 msg << level2
627 << "--- ScatteringPhysics ---\n"
628 << "Name: " << name_m << " - "
629 << "Material: " << material_m << " - "
630 << "Element: " << element_ref_m->getName() << "\n"
631 << "Particle Statistics @ " << time.time() << "\n"
632 << std::setw(21) << "entered: " << Util::toStringWithThousandSep(bunchToMatStat_m) << "\n"
633 << std::setw(21) << "rediffused: " << Util::toStringWithThousandSep(rediffusedStat_m) << "\n"
634 << std::setw(21) << "stopped: " << Util::toStringWithThousandSep(stoppedPartStat_m) << "\n"
635 << std::setw(21) << "total in material: " << Util::toStringWithThousandSep(totalPartsInMat_m)
636 << endl;
637 }
638 msg.flags(ff);
639}
640
642 return totalPartsInMat_m != 0;
643}
644
645namespace {
646 bool myCompF(PART x, PART y) {
647 return x.label > y.label;
648 }
649}
650
652 /*
653 the particle to be deleted (label < 0) are all
654 at the end of the vector.
655 */
656 sort(locParts_m.begin(), locParts_m.end(), myCompF);
657
658 // find start of particles to delete
660
661 for (; inv != locParts_m.end(); ++inv) {
662 if ((*inv).label == -1)
663 break;
664 }
665 locParts_m.erase(inv, locParts_m.end());
666 locParts_m.resize(inv - locParts_m.begin());
667
668 // update statistics
669 if (!locParts_m.empty()) {
670 Eavg_m /= locParts_m.size();
671 Emin_m /= locParts_m.size();
672 Emax_m /= locParts_m.size();
673 }
674}
675
677 for (size_t i = 0; i < locParts_m.size(); ++i) {
678 Vector_t& R = locParts_m[i].Rincol;
679 Vector_t& P = locParts_m[i].Pincol;
680 double gamma = Util::getGamma(P);
681
682 R += 0.5 * dT_m * Physics::c * P / gamma;
683 }
684}
685
686// adjust the time step for those particles that will rediffuse to
687// vacuum such that it corresponds to the time needed to reach the
688// end of the material. Only use this time step for the computation
689// of the interaction with the material, not for the integration of
690// the particles. This will ensure that the momenta of all particles
691// are reduced by approximately the same amount in computeEnergyLoss.
693 const double elementLength = element_ref_m->getElementLength();
694
695 for (size_t i = 0; i < locParts_m.size(); ++i) {
696 Vector_t& R = locParts_m[i].Rincol;
697 Vector_t& P = locParts_m[i].Pincol;
698 double& dt = locParts_m[i].DTincol;
699 double gamma = Util::getGamma(P);
700 Vector_t stepLength = dT_m * Physics::c * P / gamma;
701
702 if ( R(2) < elementLength &&
703 R(2) + stepLength(2) > elementLength &&
704 OpalData::getInstance()->isInOPALTMode() ) {
705
706 // particle is likely to leave material
707 double distance = elementLength - R(2);
708 double tau = distance / stepLength(2);
709
710 PAssert_LE(tau, 1.0);
711 PAssert_GE(tau, 0.0);
712
713 dt *= tau;
714 }
715 }
716}
717
719 for (size_t i = 0; i < locParts_m.size(); ++i) {
720 double& dt = locParts_m[i].DTincol;
721 dt = dT_m;
722 }
723}
724
726
727 unsigned int locPartsInMat;
728 locPartsInMat = locParts_m.size();
729
730 constexpr unsigned short numItems = 4;
731 unsigned int partStatistics[numItems] = {locPartsInMat,
735
736 allreduce(&(partStatistics[0]), numItems, std::plus<unsigned int>());
737
738 totalPartsInMat_m = partStatistics[0];
739 bunchToMatStat_m = partStatistics[1];
740 rediffusedStat_m = partStatistics[2];
741 stoppedPartStat_m = partStatistics[3];
742}
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition: Vector3D.cpp:111
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
ElementType
Definition: ElementBase.h:88
ParticleType
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
PETE_TBTree< OpNE, Index::PETE_Expr_t, PETE_Scalar< double > > ne(const Index &idx, double x)
Definition: IndexInlines.h:357
#define X(arg)
Definition: fftpack.cpp:112
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
Definition: PETE.h:727
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
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 PAssert_LE(a, b)
Definition: PAssert.h:107
#define PAssert_GE(a, b)
Definition: PAssert.h:109
#define INFOMSG(msg)
Definition: IpplInfo.h:348
const std::string name
constexpr double amu
The atomic mass unit energy equivalent in GeV.
Definition: Physics.h:75
constexpr double two_pi
The value of.
Definition: Physics.h:33
constexpr double Avo
The Avogadro's number.
Definition: Physics.h:57
constexpr double m_p
The proton rest mass in GeV.
Definition: Physics.h:90
constexpr double m_e
The electron rest mass in GeV.
Definition: Physics.h:78
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 r_e
The classical electron radius in m.
Definition: Physics.h:81
constexpr double GeV2keV
Definition: Units.h:92
constexpr double eV2keV
Definition: Units.h:89
constexpr double m2cm
Definition: Units.h:32
constexpr double keV2MeV
Definition: Units.h:101
constexpr double MeV2keV
Definition: Units.h:98
std::string::iterator iterator
Definition: MSLang.h:16
bool asciidump
Definition: Options.cpp:85
int seed
The current random seed.
Definition: Options.cpp:37
Vector_t getBeta(Vector_t p)
Definition: Util.h:50
double getGamma(Vector_t p)
Definition: Util.h:45
std::string toStringWithThousandSep(T value, char sep='\'')
Definition: Util.h:234
ParticleAttrib< Vector_t > Ef
ParticlePos_t & R
ParticleAttrib< int > Bin
double getQ() const
Access to reference data.
size_t getLocalNum() const
ParticleAttrib< double > M
ParticleAttrib< Vector_t > P
double getdT() const
ParticleAttrib< double > Q
ParticleType getPType() const
void createWithID(unsigned id)
ParticleAttrib< double > dt
void performDestroy(bool updateLocalNum=false)
void destroy(size_t M, size_t I, bool doNow=false)
ParticleAttrib< Vector_t > Bf
ParticleIndex_t & ID
double getM() const
double getT() const
static OpalData * getInstance()
Definition: OpalData.cpp:196
virtual const std::string & getName() const
Get element name.
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:414
virtual ElementType getType() const =0
Get element type std::string.
Vector_t rotateFrom(const Vector_t &r) const
Vector_t transformFrom(const Vector_t &r) const
Vector_t rotateTo(const Vector_t &r) const
static std::shared_ptr< Material > getMaterial(const std::string &name)
Definition: Material.cpp:53
static std::string getParticleTypeString(const ParticleType &type)
virtual bool checkHit(const Vector_t &R)=0
std::unique_ptr< InsideTester > hitTester_m
bool allParticleInMat_m
if all particles are in matter stay inside the particle matter interaction
double Qincol
long IDincol
unsigned localID
double DTincol
double Mincol
int Binincol
Vector_t Rincol
Vector_t Pincol
Vector_t Bfincol
Vector_t Efincol
void addBackToBunch(PartBunchBase< double, 3 > *bunch)
void configureMaterialParameters()
The material of the collimator.
void copyFromBunch(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere)
virtual void apply(PartBunchBase< double, 3 > *bunch, const std::pair< Vector_t, double > &boundingSphere) override
void addParticleBackToBunch(PartBunchBase< double, 3 > *bunch, const PART &particle, bool pdead=false)
unsigned int bunchToMatStat_m
IpplTimings::TimerRef DegraderLoopTimer_m
void applyRotation(Vector_t &P, Vector_t &R, double xplane, double thetacou)
virtual bool computeEnergyLoss(PartBunchBase< double, 3 > *bunch, Vector_t &P, const double deltat, bool includeFluctuations=true) const override
ScatteringPhysics(const std::string &name, ElementBase *element, std::string &mat, bool enableRutherford, double lowEnergyThr)
void computeInteraction(PartBunchBase< double, 3 > *bunch)
unsigned int totalPartsInMat_m
void applyRandomRotation(Vector_t &P, double theta0)
void computeCoulombScattering(Vector_t &R, Vector_t &P, double dt)
std::vector< PART > locParts_m
unsigned int rediffusedStat_m
IpplTimings::TimerRef DegraderApplyTimer_m
unsigned int stoppedPartStat_m
virtual bool stillActive() override
IpplTimings::TimerRef DegraderDestroyTimer_m
virtual std::string getName() override
std::unique_ptr< LossDataSink > lossDs_m
virtual void print(Inform &os) override
std::string time() const
Return time.
Definition: Timer.cpp:42
Definition: Inform.h:42
std::ios_base::fmtflags FmtFlags_t
Definition: Inform.h:99
FmtFlags_t flags() const
Definition: Inform.h:106
static int myNode()
Definition: IpplInfo.cpp:691
static TimerRef getTimer(const char *nm)
Definition: IpplTimings.h:182
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:192
static void startTimer(TimerRef t)
Definition: IpplTimings.h:187
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6