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