16 uint64_t decayRngSeed(std::size_t containerIndex) {
17 const uint64_t seedBase =
19 return seedBase + 104729ULL *
static_cast<uint64_t
>(containerIndex + 1)
20 + 8191ULL *
static_cast<uint64_t
>(ippl::Comm->rank() + 1);
26 double restLifetimeSeconds, std::size_t containerIndex,
double parentMassGeV,
28 : tau0_m(restLifetimeSeconds),
29 randPool_m(decayRngSeed(containerIndex)),
30 parentMassGeV_m(parentMassGeV),
31 parentChargeSign_m(parentChargeSign) {}
35 [[maybe_unused]]
size_t containerIdx) {
36 using pc_size_type = ippl::detail::size_type;
38 if (dt <= 0.0 || !(
tau0_m > 0.0) || !std::isfinite(
tau0_m)) {
42 const pc_size_type nLocal = pc.getLocalNum();
45 Kokkos::View<bool*> decayed(
"Decay::decayed", nLocal);
50 "Decay::orInvalidMask", nLocal,
51 KOKKOS_LAMBDA(
const pc_size_type i) { invalidMask(i) = invalidMask(i) || decayed(i); });
54 pc_size_type globalDestroyNum = 0;
55 ippl::Comm->allreduce(localDestroyNum, globalDestroyNum, 1, std::plus<pc_size_type>());
56 if (globalDestroyNum == 0) {
63 Kokkos::View<ippl::Vector<float, 3>*> parentPolView;
65 parentPolView = pc.
Pol.getView();
68 nLocal, localDestroyNum, decayed, pc.R.getView(), pc.
P.getView(), pc.
dt.getView(),
73 const pc_size_type oldDaughterLocal =
daughterPC_m->getLocalNum();
76 if (localDestroyNum > 0) {
78 localDestroyNum, oldDaughterLocal, parents.
R, parents.
P, parents.
dt,
83 return static_cast<size_t>(globalDestroyNum);
87 ippl::detail::size_type nLocal,
double dt, Kokkos::View<ippl::Vector<double, 3>*> Pview,
88 Kokkos::View<bool*> decayed) {
89 using pc_size_type = ippl::detail::size_type;
92 const double tau0 =
tau0_m;
95 pc_size_type localDestroyNum = 0;
96 Kokkos::parallel_reduce(
97 "Decay::mark", nLocal,
98 KOKKOS_LAMBDA(
const pc_size_type i, pc_size_type& count) {
99 auto generator = pool.get_state();
100 const double p2 = Pview(i)[0] * Pview(i)[0] + Pview(i)[1] * Pview(i)[1]
101 + Pview(i)[2] * Pview(i)[2];
102 const double gamma = Kokkos::sqrt(1.0 + p2);
103 const double tauLab = gamma * tau0;
104 const double pDecay = 1.0 - Kokkos::exp(-dt / tauLab);
105 const bool didDecay = generator.drand(0.0, 1.0) < pDecay;
106 decayed(i) = didDecay;
107 count += didDecay ? 1 : 0;
108 pool.free_state(generator);
112 return localDestroyNum;
116 ippl::detail::size_type nLocal, ippl::detail::size_type localDestroyNum,
117 Kokkos::View<bool*> decayed, Kokkos::View<ippl::Vector<double, 3>*> Rview,
118 Kokkos::View<ippl::Vector<double, 3>*> Pview, Kokkos::View<double*> dtView,
119 Kokkos::View<ippl::Vector<float, 3>*> PolView) {
120 using pc_size_type = ippl::detail::size_type;
122 Kokkos::View<pc_size_type*> compactIdx(
"Decay::compactIdx", nLocal);
123 Kokkos::parallel_scan(
124 "Decay::compact", nLocal,
125 KOKKOS_LAMBDA(
const pc_size_type i, pc_size_type& runningTotal,
const bool isFinal) {
128 compactIdx(i) = runningTotal;
135 const bool hasPol = PolView.extent(0) > 0;
137 Kokkos::View<ippl::Vector<double, 3>*>(
"Decay::parentR", localDestroyNum),
138 Kokkos::View<ippl::Vector<double, 3>*>(
"Decay::parentP", localDestroyNum),
139 Kokkos::View<double*>(
"Decay::parentDt", localDestroyNum),
140 Kokkos::View<ippl::Vector<float, 3>*>(
141 "Decay::parentPol", hasPol ? localDestroyNum : 0)};
143 Kokkos::parallel_for(
144 "Decay::collectParents", nLocal, KOKKOS_LAMBDA(
const pc_size_type i) {
146 const pc_size_type j = compactIdx(i);
149 out.dt(j) = dtView(i);
153 out.Pol(j) = PolView(i);
165 const auto actual =
static_cast<ParticleType>(daughterPC->Sp);
167 "Decay::setDaughterContainer",
168 "Daughter container species mismatch: expected \""
DecayedParentViews collectDecayedParents(ippl::detail::size_type nLocal, ippl::detail::size_type localDestroyNum, Kokkos::View< bool * > decayed, Kokkos::View< ippl::Vector< double, 3 > * > Rview, Kokkos::View< ippl::Vector< double, 3 > * > Pview, Kokkos::View< double * > dtView, Kokkos::View< ippl::Vector< float, 3 > * > PolView)
Gather R/P/dt of parents marked for decay into compact views.
ippl::detail::size_type markDecayedParticles(ippl::detail::size_type nLocal, double dt, Kokkos::View< ippl::Vector< double, 3 > * > Pview, Kokkos::View< bool * > decayed)
Mark particles for decay using the relativistic exponential law.
Kokkos::View< ippl::Vector< double, 3 > * > R
double tau0_m
Mean lifetime at rest [s].
Kokkos::Random_XorShift64_Pool randPool_m
Random pool for decay sampling.
virtual void createDaughterParticles(std::size_t localDestroyNum, std::size_t oldDaughterLocal, const Kokkos::View< ippl::Vector< double, 3 > * > &parentR, const Kokkos::View< ippl::Vector< double, 3 > * > &parentP, const Kokkos::View< double * > &parentDt, const Kokkos::View< ippl::Vector< float, 3 > * > &parentPol)=0
Create daughter particles from collected parent data.
Kokkos::View< ippl::Vector< double, 3 > * > P
Kokkos::View< double * > dt
Decay(double restLifetimeSeconds, std::size_t containerIndex, double parentMassGeV, int parentChargeSign)
size_t apply(ParticleContainer< double, 3 > &pc, double dt, long long globalTrackStep, size_t containerIdx) override
Kokkos::View< ippl::Vector< float, 3 > * > Pol
std::shared_ptr< ParticleContainer< double, 3 > > daughterPC_m
Daughter container for decay products (nullptr = destroy-only mode).
short allowedDaughterSpecies_m
void setDaughterContainer(std::shared_ptr< ParticleContainer< double, 3 > > daughterPC, double daughterMassGeV)
Set the daughter particle container and its rest mass.
double daughterMassGeV_m
Rest mass of the daughter particle [GeV].
Container for all per-particle (and per-simulation) fields tracked during OPALX tracking.
ippl::ParticleAttrib< bool > InvalidMask
particle deletion mask (indicates which particles are deleted every timestep)
ippl::ParticleAttrib< double > dt
timestep in [s]
ippl::ParticleAttrib< spin_vector_type > Pol
Base::particle_position_type P
particle momenta [\beta\gamma]
static std::string getParticleTypeString(const ParticleType &type)
int seed
The current random seed.