File indexing completed on 2025-09-17 08:53:39
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <type_traits>
0010
0011 #include "corecel/Types.hh"
0012 #include "corecel/math/Algorithms.hh"
0013
0014 #include "Types.hh"
0015
0016 namespace celeritas
0017 {
0018 class UniformZField;
0019
0020
0021
0022
0023
0024
0025
0026 template<class EquationT>
0027 class ZHelixIntegrator
0028 {
0029 static_assert(
0030 std::is_same<std::remove_cv_t<std::remove_reference_t<
0031 typename std::remove_reference_t<EquationT>::Field_t>>,
0032 UniformZField>::value,
0033 "ZHelix stepper only works with UniformZField");
0034
0035 public:
0036
0037
0038 using result_type = FieldIntegration;
0039
0040
0041 public:
0042
0043 explicit CELER_FUNCTION ZHelixIntegrator(EquationT&& eq)
0044 : calc_rhs_(::celeritas::forward<EquationT>(eq))
0045 {
0046 }
0047
0048
0049 CELER_FUNCTION auto
0050 operator()(real_type step, OdeState const& beg_state) const -> result_type;
0051
0052 private:
0053
0054
0055
0056 EquationT calc_rhs_;
0057
0058
0059 enum class Helicity : bool
0060 {
0061 positive,
0062 negative
0063 };
0064
0065
0066
0067
0068 CELER_FUNCTION OdeState move(real_type step,
0069 real_type radius,
0070 Helicity helicity,
0071 OdeState const& beg_state,
0072 OdeState const& rhs) const;
0073
0074
0075
0076 static CELER_CONSTEXPR_FUNCTION real_type tolerance()
0077 {
0078 if constexpr (std::is_same_v<real_type, double>)
0079 return 1e-10;
0080 else if constexpr (std::is_same_v<real_type, float>)
0081 return 1e-5f;
0082 }
0083 };
0084
0085
0086
0087
0088 template<class EquationT>
0089 CELER_FUNCTION ZHelixIntegrator(EquationT&&) -> ZHelixIntegrator<EquationT>;
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 template<class E>
0106 CELER_FUNCTION auto
0107 ZHelixIntegrator<E>::operator()(real_type step,
0108 OdeState const& beg_state) const -> result_type
0109 {
0110 result_type result;
0111
0112
0113 OdeState rhs = calc_rhs_(beg_state);
0114
0115
0116 real_type radius = std::sqrt(dot_product(beg_state.mom, beg_state.mom)
0117 - ipow<2>(beg_state.mom[2]))
0118 / norm(rhs.mom);
0119
0120
0121 Helicity helicity = Helicity(rhs.mom[0] / rhs.pos[1] > 0);
0122
0123
0124 result.mid_state
0125 = this->move(real_type(0.5) * step, radius, helicity, beg_state, rhs);
0126
0127
0128 result.end_state = this->move(step, radius, helicity, beg_state, rhs);
0129
0130
0131 result.err_state.pos.fill(ZHelixIntegrator::tolerance());
0132 result.err_state.mom.fill(ZHelixIntegrator::tolerance());
0133
0134 return result;
0135 }
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 template<class E>
0162 CELER_FUNCTION OdeState ZHelixIntegrator<E>::move(real_type step,
0163 real_type radius,
0164 Helicity helicity,
0165 OdeState const& beg_state,
0166 OdeState const& rhs) const
0167 {
0168
0169 real_type del_phi = (helicity == Helicity::positive) ? step / radius
0170 : -step / radius;
0171 real_type sin_phi = std::sin(del_phi);
0172 real_type cos_phi = std::cos(del_phi);
0173
0174 OdeState end_state;
0175 end_state.pos = {(beg_state.pos[0] * cos_phi - beg_state.pos[1] * sin_phi),
0176 (beg_state.pos[0] * sin_phi + beg_state.pos[1] * cos_phi),
0177 beg_state.pos[2] + del_phi * radius * rhs.pos[2]};
0178
0179 end_state.mom = {rhs.pos[0] * cos_phi - rhs.pos[1] * sin_phi,
0180 rhs.pos[0] * sin_phi + rhs.pos[1] * cos_phi,
0181 rhs.pos[2]};
0182
0183 real_type momentum = norm(beg_state.mom);
0184 for (int i = 0; i < 3; ++i)
0185 {
0186 end_state.mom[i] *= momentum;
0187 }
0188
0189 return end_state;
0190 }
0191
0192
0193 }