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
99 dipedge::Model model,
100 dipedge::Location location,
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 void reverse ()
114 {
115 m_psi = -m_psi;
116 m_K2 = -m_K2;
117 m_location = (m_location == dipedge::Location::entry)
118 ? dipedge::Location::exit
119 : dipedge::Location::entry;
120 }
121
123 using BeamOptic::operator();
124
132 void compute_constants ([[maybe_unused]] RefPart const & refpart)
133 {
134 using namespace amrex::literals; // for _rt and _prt
135 using amrex::Math::powi;
136
137 Alignment::compute_constants(refpart);
138
139 // constants for linear map:
140
141 // edge focusing matrix elements (zero gap)
142 m_R21 = std::tan(m_psi) / m_rc;
143
144 // first-order effect of nonzero gap
145 auto const [sin_psi, cos_psi] = amrex::Math::sincos(m_psi);
146 amrex::ParticleReal const vf = (1.0_prt + powi<2>(sin_psi))
147 / powi<3>(cos_psi)
148 * m_g * m_K2 / powi<2>(m_rc);
149
150 m_R43 = vf - m_R21;
151
152 // constants for nonlinear map:
153
154 // access reference particle values to find beta
155 m_beta = refpart.beta();
156
157 // expressions from eq (14) of Mitchell and Hwang, NAPAC2025
158 amrex::ParticleReal const tan_psi = sin_psi/cos_psi;
159 amrex::ParticleReal const sec_psi = 1_prt/cos_psi;
160
161 // the scale constant specifying entry or exit
162 amrex::ParticleReal const loc = m_location == dipedge::Location::entry ? 1_prt : -1_prt;
163
164 m_c1 = (m_g / m_rc) * m_K1 / cos_psi;
165 m_c2_times_1plusdelta = powi<2>(m_g/m_rc) * m_K0 * sin_psi * powi<3>(sec_psi)/2_prt;
166 m_c3_times_1plusdelta = loc * powi<2>(m_g)/m_rc * m_K0 * powi<2>(sec_psi);
167 m_c4_times_1plusdelta = loc * (m_g / m_rc) * m_K1 * sin_psi / (powi<2>(cos_psi));
168 m_c5 = tan_psi / (2_prt * m_rc);
169 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;
170 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));
171 m_c8_times_1plusdelta = (1_prt/6_prt) * powi<3>(tan_psi) / (2_prt * powi<2>(m_rc));
172 m_c9_times_1plusdelta = 0.5_prt * tan_psi * powi<2>(sec_psi) / (2_prt * powi<2>(m_rc));
173 m_c10_times_1plusdelta = loc * powi<2>(tan_psi) / (2_prt * m_rc);
174 m_c11_times_1plusdelta = loc * 1_prt / (2_prt * m_rc);
175 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;
176 m_c13 = powi<2>(sin_psi) / (2_prt*powi<3>(cos_psi)) * powi<2>(m_g)/(m_rc*m_R) * m_K4;
177 m_c14 = 0.5_prt * sin_psi/(powi<3>(cos_psi)) * m_g/(m_rc*m_R) * m_K5;
178 m_c15 = (m_K6 / (m_rc*m_R)) / (powi<3>(cos_psi));
179 }
180
195 template<typename T_Real=amrex::ParticleReal, typename T_IdCpu=uint64_t>
198 T_Real & AMREX_RESTRICT x,
199 T_Real & AMREX_RESTRICT y,
200 [[maybe_unused]] T_Real & AMREX_RESTRICT t,
201 T_Real & AMREX_RESTRICT px,
202 T_Real & AMREX_RESTRICT py,
203 [[maybe_unused]] T_Real & AMREX_RESTRICT pt,
204 [[maybe_unused]] T_IdCpu & AMREX_RESTRICT idcpu,
205 [[maybe_unused]] RefPart const & AMREX_RESTRICT refpart
206 ) const
207 {
208
209 using namespace amrex::literals; // for _rt and _prt
210 using namespace std; // for cmath(float)
211 using amrex::Math::powi;
212
213 // shift due to alignment errors of the element
214 shift_in(x, y, px, py);
215
216 if (m_model == dipedge::Model::linear) {
217 // apply linear model
218 px = px + m_R21 * x;
219 py = py + m_R43 * y;
220 } else {
221 // apply nonlinear model
222 T_Real xout = x;
223 T_Real pxout = px;
224 T_Real yout = y;
225 T_Real pyout = py;
226 T_Real tout = t;
227 T_Real ptout = pt;
228
229 // compute particle momentum deviation delta + 1 (reciprocal)
230 T_Real const inv_delta1 = 1_prt / sqrt(1_prt - 2_prt*pt/m_beta + powi<2>(pt));
231
232 T_Real const c2 = m_c2_times_1plusdelta * inv_delta1;
233 T_Real const c3 = m_c3_times_1plusdelta * inv_delta1;
234 //T_Real const c4 = m_c4_times_1plusdelta * inv_delta1; //not currently used
235 //T_Real const c6 = m_c6_times_1plusdelta * inv_delta1; //not currently used
236 T_Real const c7 = m_c7_times_1plusdelta * inv_delta1;
237 T_Real const c8 = m_c8_times_1plusdelta * inv_delta1;
238 T_Real const c9 = m_c9_times_1plusdelta * inv_delta1;
239 T_Real const c10 = m_c10_times_1plusdelta * inv_delta1;
240 T_Real const c11 = m_c11_times_1plusdelta * inv_delta1;
241 T_Real const c12 = m_c12_times_1plusdelta * inv_delta1;
242
243 // update transverse coordinates
244 xout = x - c3 - c10*powi<2>(x) + (c10 + c11)*powi<2>(y);
245 yout = y + 2_prt * c10 * x * y;
246
247 // update transverse momenta
248 T_Real const D = 1_prt - 4_prt*c10*c11*powi<2>(y) - 4_prt*powi<2>(c10)*(powi<2>(x)+powi<2>(y));
249 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)
250 + (-m_c15/2_prt + c10*m_c5 - c11*m_c5 - c9)*powi<2>(y);
251 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);
252 T_Real const dXdx = 1_prt - 2_prt*c10*x;
253 T_Real const dXdy = 2_prt*(c10 + c11)*y;
254 T_Real const dYdx = 2_prt*c10*y;
255 T_Real const dYdy = 1_prt + 2_prt*c10*x;
256
257 pxout = (dYdy * (px - dRdx) - dYdx * (py - dRdy)) / D;
258 pyout = (-dXdy * (px - dRdx) + dXdx * (py - dRdy)) / D;
259
260 // update temporal coordinate
261 T_Real const dDelta_dpt = (pt - 1_prt/m_beta) * inv_delta1;
262 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)
263 + (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);
264
265 x = xout;
266 px = pxout;
267 y = yout;
268 py = pyout;
269 t = tout;
270 pt = ptout;
271 }
272
273 // undo shift due to alignment errors of the element
274 shift_out(x, y, px, py);
275 }
276
278 using Thin::operator();
279
281 using LinearTransport::operator();
282
289 Map6x6
290 transport_map ([[maybe_unused]] RefPart const & AMREX_RESTRICT refpart) const
291 {
292 using namespace amrex::literals; // for _rt and _prt
293 using amrex::Math::powi;
294
295 // initialize linear map matrix elements
297
298 // edge focusing matrix elements (zero gap)
299 amrex::ParticleReal const R21 = std::tan(m_psi) / m_rc;
300
301 // first-order effect of nonzero gap
302 auto const [sin_psi, cos_psi] = amrex::Math::sincos(m_psi);
303 amrex::ParticleReal const vf = (1.0_prt + powi<2>(sin_psi))
304 / powi<3>(cos_psi)
305 * m_g * m_K2 / powi<2>(m_rc);
306
307 amrex::ParticleReal const R43 = vf - R21;
308
309 // set non-identity matrix elements
310 R(2,1) = R21;
311 R(4,3) = R43;
312
313 return R;
314 }
315
327 dipedge::Model m_model;
328 dipedge::Location m_location;
329
330 private:
331 // constants that are independent of the individually tracked particle,
332 // see: compute_constants() to refresh
338 };
339
340} // namespace impactx
341
343
344#endif // IMPACTX_DIPEDGE_H
#define AMREX_FORCE_INLINE
#define AMREX_RESTRICT
#define AMREX_GPU_HOST_DEVICE
#define AMREX_GPU_HOST
#define IMPACTX_PUSH_EXTERN_TEMPLATE(ElementType)
Definition PushAll.H:78
amrex_particle_real ParticleReal
__host__ __device__ std::pair< double, double > sincos(double x)
constexpr T powi(T x) noexcept
__host__ __device__ GpuComplex< T > sqrt(const GpuComplex< T > &a_z) noexcept
Definition DipEdge.H:34
AMREX_ENUM(Model, linear, nonlinear)
Definition All.H:56
@ 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:33
Definition DipEdge.H:56
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:197
amrex::ParticleReal m_c11_times_1plusdelta
Definition DipEdge.H:337
static constexpr auto type
Definition DipEdge.H:57
amrex::ParticleReal m_g
bend radius in m
Definition DipEdge.H:318
amrex::ParticleReal m_K5
fringe field integral
Definition DipEdge.H:325
amrex::ParticleReal m_K3
fringe field integral
Definition DipEdge.H:323
amrex::ParticleReal m_c5
Definition DipEdge.H:334
amrex::ParticleReal m_c9_times_1plusdelta
Definition DipEdge.H:336
amrex::ParticleReal m_c15
Definition DipEdge.H:334
amrex::ParticleReal m_c14
Definition DipEdge.H:334
amrex::ParticleReal m_K0
scale length in m
Definition DipEdge.H:320
amrex::ParticleReal m_beta
Definition DipEdge.H:333
amrex::ParticleReal m_R21
fringe field location: entry, or exit
Definition DipEdge.H:333
amrex::ParticleReal m_R43
Definition DipEdge.H:333
amrex::ParticleReal m_c4_times_1plusdelta
Definition DipEdge.H:335
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:334
amrex::ParticleReal m_c1
Definition DipEdge.H:334
amrex::ParticleReal m_K4
fringe field integral
Definition DipEdge.H:324
dipedge::Location m_location
fringe field model: linear or nonlinear
Definition DipEdge.H:328
amrex::ParticleReal m_K2
fringe field integral
Definition DipEdge.H:322
amrex::ParticleReal m_c8_times_1plusdelta
Definition DipEdge.H:336
amrex::ParticleReal m_c12_times_1plusdelta
Definition DipEdge.H:337
amrex::ParticleReal m_c3_times_1plusdelta
Definition DipEdge.H:335
dipedge::Model m_model
fringe field integral
Definition DipEdge.H:327
void compute_constants(RefPart const &refpart)
Definition DipEdge.H:132
AMREX_GPU_HOST AMREX_FORCE_INLINE Map6x6 transport_map(RefPart const &AMREX_RESTRICT refpart) const
Definition DipEdge.H:290
amrex::ParticleReal m_c7_times_1plusdelta
Definition DipEdge.H:336
amrex::ParticleReal m_K6
fringe field integral
Definition DipEdge.H:326
void reverse()
Definition DipEdge.H:113
amrex::ParticleReal m_c10_times_1plusdelta
Definition DipEdge.H:336
amrex::ParticleReal m_c2_times_1plusdelta
Definition DipEdge.H:335
amrex::ParticleReal m_psi
Definition DipEdge.H:316
amrex::ParticleReal m_c6_times_1plusdelta
Definition DipEdge.H:335
amrex::ParticleReal m_R
gap parameter in m
Definition DipEdge.H:319
amrex::ParticleReal m_rc
pole face angle in rad
Definition DipEdge.H:317
ImpactXParticleContainer::ParticleType PType
Definition DipEdge.H:58
amrex::ParticleReal m_K1
fringe field integral
Definition DipEdge.H:321
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:436
Definition lineartransport.H:50
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