File indexing completed on 2026-11-10 10:14:24
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Assert.hh"
0010 #include "corecel/Macros.hh"
0011 #include "corecel/Types.hh"
0012 #include "corecel/cont/IdStack.hh"
0013 #include "corecel/cont/Span.hh"
0014 #include "corecel/random/distribution/IsotropicDistribution.hh"
0015 #include "corecel/random/distribution/Selector.hh"
0016 #include "celeritas/Quantities.hh"
0017 #include "celeritas/Types.hh"
0018 #include "celeritas/em/data/AtomicRelaxationData.hh"
0019 #include "celeritas/phys/CutoffView.hh"
0020 #include "celeritas/phys/Secondary.hh"
0021
0022 namespace celeritas
0023 {
0024
0025
0026
0027
0028
0029
0030
0031
0032 class AtomicRelaxation
0033 {
0034 public:
0035
0036
0037 using Energy = units::MevEnergy;
0038
0039
0040 struct result_type
0041 {
0042 size_type count{};
0043 Energy energy{};
0044 };
0045
0046 public:
0047
0048 inline CELER_FUNCTION AtomicRelaxation(AtomicRelaxParamsRef const& shared,
0049 CutoffView const& cutoffs,
0050 ElementId el_id,
0051 SubshellId shell_id,
0052 Span<Secondary> secondaries,
0053 Span<SubshellId> vacancies);
0054
0055
0056 template<class Engine>
0057 inline CELER_FUNCTION result_type operator()(Engine& rng);
0058
0059 private:
0060
0061 AtomicRelaxParamsRef const& shared_;
0062
0063 Energy gamma_cutoff_;
0064
0065 Energy electron_cutoff_;
0066
0067 ElementId el_id_;
0068
0069 SubshellId shell_id_;
0070
0071 Span<Secondary> secondaries_;
0072
0073 Span<SubshellId> vacancies_;
0074
0075 IsotropicDistribution<real_type> sample_direction_;
0076
0077 private:
0078 using TransitionId = OpaqueId<AtomicRelaxTransition>;
0079 };
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 CELER_FUNCTION AtomicRelaxation::AtomicRelaxation(
0097 AtomicRelaxParamsRef const& shared,
0098 CutoffView const& cutoffs,
0099 ElementId el_id,
0100 SubshellId shell_id,
0101 Span<Secondary> secondaries,
0102 Span<SubshellId> vacancies)
0103 : shared_(shared)
0104 , gamma_cutoff_(cutoffs.energy(shared_.ids.gamma))
0105 , electron_cutoff_(cutoffs.energy(shared_.ids.electron))
0106 , el_id_(el_id)
0107 , shell_id_(shell_id)
0108 , secondaries_(secondaries)
0109 , vacancies_(vacancies)
0110 {
0111 CELER_EXPECT(shared_ && el_id_ < shared_.elements.size()
0112 && shared_.elements[el_id_]);
0113 CELER_EXPECT(shell_id);
0114 }
0115
0116
0117
0118
0119
0120 template<class Engine>
0121 CELER_FUNCTION AtomicRelaxation::result_type AtomicRelaxation::operator()(
0122 Engine& rng)
0123 {
0124 using namespace celeritas::literals;
0125
0126 AtomicRelaxElement const& el = shared_.elements[el_id_];
0127 auto const& shells = shared_.shells[el.shells];
0128 IdStack<SubshellId> vacancies(vacancies_);
0129
0130
0131 vacancies.push(shell_id_);
0132
0133
0134 size_type count = 0;
0135 real_type sum_energy = 0;
0136
0137
0138
0139 while (!vacancies.empty())
0140 {
0141
0142 if (!(vacancies.top() < shells.size()))
0143 {
0144 vacancies.pop();
0145 continue;
0146 }
0147
0148
0149 AtomicRelaxSubshell const& shell = shells[vacancies.top().get()];
0150 vacancies.pop();
0151
0152
0153 auto transitions = shared_.transitions[shell.transitions];
0154 TransitionId const trans_id = make_unnormalized_selector(
0155 [&transitions](TransitionId i) {
0156 CELER_ASSERT(i < transitions.size());
0157 return transitions[i.unchecked_get()].probability;
0158 },
0159 id_cast<TransitionId>(transitions.size()),
0160 1_r)(rng);
0161
0162 if (trans_id == id_cast<TransitionId>(transitions.size()))
0163 {
0164
0165 continue;
0166 }
0167
0168
0169 auto const& transition = transitions[trans_id.get()];
0170 vacancies.push(transition.initial_shell);
0171 if (transition.auger_shell)
0172 {
0173 vacancies.push(transition.auger_shell);
0174
0175 if (transition.energy >= electron_cutoff_)
0176 {
0177
0178 CELER_ASSERT(count < secondaries_.size());
0179 Secondary& secondary = secondaries_[count++];
0180 secondary.direction = sample_direction_(rng);
0181 secondary.energy = transition.energy;
0182 secondary.particle_id = shared_.ids.electron;
0183
0184
0185 sum_energy += value_as<Energy>(transition.energy);
0186 }
0187 }
0188 else if (transition.energy >= gamma_cutoff_)
0189 {
0190
0191 CELER_ASSERT(count < secondaries_.size());
0192 Secondary& secondary = secondaries_[count++];
0193 secondary.direction = sample_direction_(rng);
0194 secondary.energy = transition.energy;
0195 secondary.particle_id = shared_.ids.gamma;
0196
0197
0198 sum_energy += value_as<Energy>(transition.energy);
0199 }
0200 }
0201
0202 result_type result;
0203 result.count = count;
0204 result.energy = Energy{sum_energy};
0205 return result;
0206 }
0207
0208
0209 }