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