ImpactX
Loading...
Searching...
No Matches
DipEdge.H
Go to the documentation of this file.
1/* Copyright 2022-2023 The Regents of the University of California, through Lawrence
2 * Berkeley National Laboratory (subject to receipt of any required
3 * approvals from the U.S. Dept. of Energy). All rights reserved.
4 *
5 * This file is part of ImpactX.
6 *
7 * Authors: Chad Mitchell, Axel Huebl
8 * License: BSD-3-Clause-LBNL
9 */
10#ifndef IMPACTX_DIPEDGE_H
11#define IMPACTX_DIPEDGE_H
12
14#include "mixin/alignment.H"
15#include "mixin/beamoptic.H"
16#include "mixin/thin.H"
18#include "mixin/named.H"
19#include "mixin/nofinalize.H"
20
21#include <AMReX_Enum.H>
22#include <AMReX_Extension.H>
23#include <AMReX_Math.H>
24#include <AMReX_REAL.H>
25#include <AMReX_SIMD.H>
26
27#include <cmath>
28#include <stdexcept>
29
30
31namespace impactx::elements
32{
33 namespace dipedge
34 {
36 linear,
37 nonlinear
38 );
39 AMREX_ENUM(Location,
40 entry,
41 exit
42 );
43 }
44
45 struct DipEdge
46 : public mixin::Named,
47 public mixin::BeamOptic<DipEdge>,
48 public mixin::LinearTransport<DipEdge>,
49 public mixin::Thin,
50 public mixin::Alignment,
52 // At least on Intel AVX512, there is a small overhead to vectorize this element, see
53 // https://github.com/BLAST-ImpactX/impactx/pull/1002
54 // verify again after https://github.com/BLAST-ImpactX/impactx/pull/1158
55 // public amrex::simd::Vectorized<amrex::simd::native_simd_size_particlereal>
56 {
57 static constexpr auto type = "DipEdge";
59
88 amrex::ParticleReal psi,
89 amrex::ParticleReal rc,
90 amrex::ParticleReal g,
91 amrex::ParticleReal R,
92 amrex::ParticleReal K0,
93 amrex::ParticleReal K1,
94 amrex::ParticleReal K2,
95 amrex::ParticleReal K3,
96 amrex::ParticleReal K4,
97 amrex::ParticleReal K5,
98 amrex::ParticleReal K6,
99 dipedge::Model model,
100 dipedge::Location location,
101 amrex::ParticleReal dx = 0,
102 amrex::ParticleReal dy = 0,
103 amrex::ParticleReal rotation_degree = 0,
104 std::optional<std::string> name = std::nullopt
105 )
106 : Named(std::move(name)),
107 Alignment(dx, dy, rotation_degree),
108 m_psi(psi), m_rc(rc), m_g(g), m_R(R), m_K0(K0), m_K1(K1), m_K2(K2), m_K3(K3), m_K4(K4), m_K5(K5), m_K6(K6), m_model(model), m_location(location)
109 {
110 }
111
113 using BeamOptic::operator();
114
122 void compute_constants ([[maybe_unused]] RefPart const & refpart)
123 {
124 using namespace amrex::literals; // for _rt and _prt
125 using amrex::Math::powi;
126
127 Alignment::compute_constants(refpart);
128
129 // constants for linear map:
130
131 // edge focusing matrix elements (zero gap)
132 m_R21 = std::tan(m_psi) / m_rc;
133
134 // first-order effect of nonzero gap
135 auto const [sin_psi, cos_psi] = amrex::Math::sincos(m_psi);
136 amrex::ParticleReal const vf = (1.0_prt + powi<2>(sin_psi))
137 / powi<3>(cos_psi)
138 * m_g * m_K2 / powi<2>(m_rc);
139
140 m_R43 = vf - m_R21;
141
142 // constants for nonlinear map:
143
144 // access reference particle values to find beta
145 m_beta = refpart.beta();
146
147 // expressions from eq (14) of Mitchell and Hwang, NAPAC2025
148 amrex::ParticleReal const tan_psi = sin_psi/cos_psi;
149 amrex::ParticleReal const sec_psi = 1_prt/cos_psi;
150
151 // the scale constant specifying entry or exit
152 amrex::ParticleReal const loc = m_location == dipedge::Location::entry ? 1_prt : -1_prt;
153
154 m_c1 = (m_g / m_rc) * m_K1 / cos_psi;
155 m_c2_times_1plusdelta = powi<2>(m_g/m_rc) * m_K0 * sin_psi * powi<3>(sec_psi)/2_prt;
156 m_c3_times_1plusdelta = loc * powi<2>(m_g)/m_rc * m_K0 * powi<2>(sec_psi);
157 m_c4_times_1plusdelta = loc * (m_g / m_rc) * m_K1 * sin_psi / (powi<2>(cos_psi));
158 m_c5 = tan_psi / (2_prt * m_rc);
159 m_c6_times_1plusdelta = 0.5_prt * powi<2>(sin_psi)/(2_prt * m_rc * powi<3>(cos_psi)) * m_g/m_rc * m_K1;
160 m_c7_times_1plusdelta = 0.5_prt * powi<3>(sec_psi) * (m_g * m_K1 / (2_prt*powi<2>(m_rc)) + (1_prt+powi<2>(sin_psi))*m_g*m_K2/powi<2>(m_rc));
161 m_c8_times_1plusdelta = (1_prt/6_prt) * powi<3>(tan_psi) / (2_prt * powi<2>(m_rc));
162 m_c9_times_1plusdelta = 0.5_prt * tan_psi * powi<2>(sec_psi) / (2_prt * powi<2>(m_rc));
163 m_c10_times_1plusdelta = loc * powi<2>(tan_psi) / (2_prt * m_rc);
164 m_c11_times_1plusdelta = loc * 1_prt / (2_prt * m_rc);
165 m_c12_times_1plusdelta = (m_g > 0_prt) ? 1_prt / (24_prt) * (4_prt/cos_psi - 8_prt/(powi<3>(cos_psi))) * m_K3/(powi<2>(m_rc) * m_g) : 0_prt;
166 m_c13 = powi<2>(sin_psi) / (2_prt*powi<3>(cos_psi)) * powi<2>(m_g)/(m_rc*m_R) * m_K4;
167 m_c14 = 0.5_prt * sin_psi/(powi<3>(cos_psi)) * m_g/(m_rc*m_R) * m_K5;
168 m_c15 = (m_K6 / (m_rc*m_R)) / (powi<3>(cos_psi));
169 }
170
185 template<typename T_Real=amrex::ParticleReal, typename T_IdCpu=uint64_t>
188 T_Real & AMREX_RESTRICT x,
189 T_Real & AMREX_RESTRICT y,
190 [[maybe_unused]] T_Real & AMREX_RESTRICT t,
191 T_Real & AMREX_RESTRICT px,
192 T_Real & AMREX_RESTRICT py,
193 [[maybe_unused]] T_Real & AMREX_RESTRICT pt,
194 [[maybe_unused]] T_IdCpu & AMREX_RESTRICT idcpu,
195 [[maybe_unused]] RefPart const & AMREX_RESTRICT refpart
196 ) const
197 {
198
199 using namespace amrex::literals; // for _rt and _prt
200 using namespace std; // for cmath(float)
201 using amrex::Math::powi;
202
203 // shift due to alignment errors of the element
204 shift_in(x, y, px, py);
205
206 if (m_model == dipedge::Model::linear) {
207 // apply linear model
208 px = px + m_R21 * x;
209 py = py + m_R43 * y;
210 } else {
211 // apply nonlinear model
212 T_Real xout = x;
213 T_Real pxout = px;
214 T_Real yout = y;
215 T_Real pyout = py;
216 T_Real tout = t;
217 T_Real ptout = pt;
218
219 // compute particle momentum deviation delta + 1 (reciprocal)
220 T_Real const inv_delta1 = 1_prt / sqrt(1_prt - 2_prt*pt/m_beta + powi<2>(pt));
221
222 T_Real const c2 = m_c2_times_1plusdelta * inv_delta1;
223 T_Real const c3 = m_c3_times_1plusdelta * inv_delta1;
224 //T_Real const c4 = m_c4_times_1plusdelta * inv_delta1; //not currently used
225 //T_Real const c6 = m_c6_times_1plusdelta * inv_delta1; //not currently used
226 T_Real const c7 = m_c7_times_1plusdelta * inv_delta1;
227 T_Real const c8 = m_c8_times_1plusdelta * inv_delta1;
228 T_Real const c9 = m_c9_times_1plusdelta * inv_delta1;
229 T_Real const c10 = m_c10_times_1plusdelta * inv_delta1;
230 T_Real const c11 = m_c11_times_1plusdelta * inv_delta1;
231 T_Real const c12 = m_c12_times_1plusdelta * inv_delta1;
232
233 // update transverse coordinates
234 xout = x - c3 - c10*powi<2>(x) + (c10 + c11)*powi<2>(y);
235 yout = y + 2_prt * c10 * x * y;
236
237 // update transverse momenta
238 T_Real const D = 1_prt - 4_prt*c10*c11*powi<2>(y) - 4_prt*powi<2>(c10)*(powi<2>(x)+powi<2>(y));
239 T_Real const dRdx = -m_c13 + c2 + c3*m_c5 + 2_prt*(m_c14 - m_c5)*x + 3_prt*(m_c15/6_prt + c10*m_c5 + c8)*powi<2>(x)
240 + (-m_c15/2_prt + c10*m_c5 - c11*m_c5 - c9)*powi<2>(y);
241 T_Real const dRdy = 2_prt*(-m_c14 + m_c5 - c7)*y + 2_prt*(-m_c15/2_prt + c10*m_c5 - c11*m_c5 - c9)*x*y - 4_prt*c12*powi<3>(y);
242 T_Real const dXdx = 1_prt - 2_prt*c10*x;
243 T_Real const dXdy = 2_prt*(c10 + c11)*y;
244 T_Real const dYdx = 2_prt*c10*y;
245 T_Real const dYdy = 1_prt + 2_prt*c10*x;
246
247 pxout = (dYdy * (px - dRdx) - dYdx * (py - dRdy)) / D;
248 pyout = (-dXdy * (px - dRdx) + dXdx * (py - dRdy)) / D;
249
250 // update temporal coordinate
251 T_Real const dDelta_dpt = (pt - 1_prt/m_beta) * inv_delta1;
252 tout = t - dDelta_dpt * inv_delta1 * ((c2 + c3*m_c5)*x + (c10*m_c5 + c8)*powi<3>(x) - c7*powi<2>(y) - c12*powi<4>(y)
253 + (c10*m_c5 - c11*m_c5 - c9)*x*powi<2>(y) + pxout*(-c3 + (c11 + c10)*powi<2>(y) - c10*powi<2>(x)) + 2_prt*pyout*c10*x*y);
254
255 x = xout;
256 px = pxout;
257 y = yout;
258 py = pyout;
259 t = tout;
260 pt = ptout;
261 }
262
263 // undo shift due to alignment errors of the element
264 shift_out(x, y, px, py);
265 }
266
268 using Thin::operator();
269
271 using LinearTransport::operator();
272
279 Map6x6
280 transport_map ([[maybe_unused]] RefPart const & AMREX_RESTRICT refpart) const
281 {
282 using namespace amrex::literals; // for _rt and _prt
283 using amrex::Math::powi;
284
285 // initialize linear map matrix elements
287
288 // edge focusing matrix elements (zero gap)
289 amrex::ParticleReal const R21 = std::tan(m_psi) / m_rc;
290
291 // first-order effect of nonzero gap
292 auto const [sin_psi, cos_psi] = amrex::Math::sincos(m_psi);
293 amrex::ParticleReal const vf = (1.0_prt + powi<2>(sin_psi))
294 / powi<3>(cos_psi)
295 * m_g * m_K2 / powi<2>(m_rc);
296
297 amrex::ParticleReal const R43 = vf - R21;
298
299 // set non-identity matrix elements
300 R(2,1) = R21;
301 R(4,3) = R43;
302
303 return R;
304 }
305
306 amrex::ParticleReal m_psi;
307 amrex::ParticleReal m_rc;
308 amrex::ParticleReal m_g;
309 amrex::ParticleReal m_R;
310 amrex::ParticleReal m_K0;
311 amrex::ParticleReal m_K1;
312 amrex::ParticleReal m_K2;
313 amrex::ParticleReal m_K3;
314 amrex::ParticleReal m_K4;
315 amrex::ParticleReal m_K5;
316 amrex::ParticleReal m_K6;
317 dipedge::Model m_model;
318 dipedge::Location m_location;
319
320 private:
321 // constants that are independent of the individually tracked particle,
322 // see: compute_constants() to refresh
323 amrex::ParticleReal m_R21, m_R43, m_beta;
324 amrex::ParticleReal m_c1, m_c5, m_c13, m_c14, m_c15;
328 };
329
330} // namespace impactx
331
332#endif // IMPACTX_DIPEDGE_H
#define AMREX_FORCE_INLINE
#define AMREX_RESTRICT
#define AMREX_GPU_HOST_DEVICE
#define AMREX_GPU_HOST
__host__ __device__ std::pair< double, double > sincos(double x)
constexpr T powi(T x) noexcept
Definition DipEdge.H:34
AMREX_ENUM(Model, linear, nonlinear)
Definition All.H:55
@ t
fixed t as the independent variable
Definition ImpactXParticleContainer.H:38
amrex::SmallMatrix< amrex::ParticleReal, 6, 6, amrex::Order::F, 1 > Map6x6
Definition CovarianceMatrix.H:20
static constexpr __host__ __device__ SmallMatrix< T, NRows, NCols, ORDER, StartIndex > Identity() noexcept
Definition ReferenceParticle.H:31
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void operator()(T_Real &AMREX_RESTRICT x, T_Real &AMREX_RESTRICT y, T_Real &AMREX_RESTRICT t, T_Real &AMREX_RESTRICT px, T_Real &AMREX_RESTRICT py, T_Real &AMREX_RESTRICT pt, T_IdCpu &AMREX_RESTRICT idcpu, RefPart const &AMREX_RESTRICT refpart) const
Definition DipEdge.H:187
amrex::ParticleReal m_c11_times_1plusdelta
Definition DipEdge.H:327
static constexpr auto type
Definition DipEdge.H:57
amrex::ParticleReal m_g
bend radius in m
Definition DipEdge.H:308
amrex::ParticleReal m_K5
fringe field integral
Definition DipEdge.H:315
amrex::ParticleReal m_K3
fringe field integral
Definition DipEdge.H:313
amrex::ParticleReal m_c5
Definition DipEdge.H:324
amrex::ParticleReal m_c9_times_1plusdelta
Definition DipEdge.H:326
amrex::ParticleReal m_c15
Definition DipEdge.H:324
amrex::ParticleReal m_c14
Definition DipEdge.H:324
amrex::ParticleReal m_K0
scale length in m
Definition DipEdge.H:310
amrex::ParticleReal m_beta
Definition DipEdge.H:323
amrex::ParticleReal m_R21
fringe field location: entry, or exit
Definition DipEdge.H:323
amrex::ParticleReal m_R43
Definition DipEdge.H:323
amrex::ParticleReal m_c4_times_1plusdelta
Definition DipEdge.H:325
DipEdge(amrex::ParticleReal psi, amrex::ParticleReal rc, amrex::ParticleReal g, amrex::ParticleReal R, amrex::ParticleReal K0, amrex::ParticleReal K1, amrex::ParticleReal K2, amrex::ParticleReal K3, amrex::ParticleReal K4, amrex::ParticleReal K5, amrex::ParticleReal K6, dipedge::Model model, dipedge::Location location, amrex::ParticleReal dx=0, amrex::ParticleReal dy=0, amrex::ParticleReal rotation_degree=0, std::optional< std::string > name=std::nullopt)
Definition DipEdge.H:87
amrex::ParticleReal m_c13
Definition DipEdge.H:324
amrex::ParticleReal m_c1
Definition DipEdge.H:324
amrex::ParticleReal m_K4
fringe field integral
Definition DipEdge.H:314
dipedge::Location m_location
fringe field model: linear or nonlinear
Definition DipEdge.H:318
amrex::ParticleReal m_K2
fringe field integral
Definition DipEdge.H:312
amrex::ParticleReal m_c8_times_1plusdelta
Definition DipEdge.H:326
amrex::ParticleReal m_c12_times_1plusdelta
Definition DipEdge.H:327
amrex::ParticleReal m_c3_times_1plusdelta
Definition DipEdge.H:325
dipedge::Model m_model
fringe field integral
Definition DipEdge.H:317
void compute_constants(RefPart const &refpart)
Definition DipEdge.H:122
AMREX_GPU_HOST AMREX_FORCE_INLINE Map6x6 transport_map(RefPart const &AMREX_RESTRICT refpart) const
Definition DipEdge.H:280
amrex::ParticleReal m_c7_times_1plusdelta
Definition DipEdge.H:326
amrex::ParticleReal m_K6
fringe field integral
Definition DipEdge.H:316
amrex::ParticleReal m_c10_times_1plusdelta
Definition DipEdge.H:326
amrex::ParticleReal m_c2_times_1plusdelta
Definition DipEdge.H:325
amrex::ParticleReal m_psi
Definition DipEdge.H:306
amrex::ParticleReal m_c6_times_1plusdelta
Definition DipEdge.H:325
amrex::ParticleReal m_R
gap parameter in m
Definition DipEdge.H:309
amrex::ParticleReal m_rc
pole face angle in rad
Definition DipEdge.H:307
ImpactXParticleContainer::ParticleType PType
Definition DipEdge.H:58
amrex::ParticleReal m_K1
fringe field integral
Definition DipEdge.H:311
Definition alignment.H:27
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void shift_out(T_Real &AMREX_RESTRICT x, T_Real &AMREX_RESTRICT y, T_Real &AMREX_RESTRICT px, T_Real &AMREX_RESTRICT py) const
Definition alignment.H:109
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal dy() const
Definition alignment.H:146
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal dx() const
Definition alignment.H:136
Alignment(amrex::ParticleReal dx, amrex::ParticleReal dy, amrex::ParticleReal rotation_degree)
Definition alignment.H:36
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void shift_in(T_Real &AMREX_RESTRICT x, T_Real &AMREX_RESTRICT y, T_Real &AMREX_RESTRICT px, T_Real &AMREX_RESTRICT py) const
Definition alignment.H:78
Definition beamoptic.H:219
Definition lineartransport.H:29
Definition named.H:29
AMREX_GPU_HOST Named(std::optional< std::string > name)
Definition named.H:57
AMREX_FORCE_INLINE std::string name() const
Definition named.H:122
Definition nofinalize.H:22
Definition thin.H:24