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