ImpactX
Loading...
Searching...
No Matches
SoftQuad.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_SOFTQUAD_H
11#define IMPACTX_SOFTQUAD_H
12
15#include "mixin/alignment.H"
16#include "mixin/pipeaperture.H"
17#include "mixin/beamoptic.H"
19#include "mixin/named.H"
20#include "mixin/thick.H"
21
22#include <ablastr/constant.H>
23
24#include <AMReX.H>
25#include <AMReX_Extension.H>
26#include <AMReX_Math.H>
27#include <AMReX_REAL.H>
28#include <AMReX_SIMD.H>
29#include <AMReX_SmallMatrix.H>
30
31#include <cmath>
32#include <stdexcept>
33#include <tuple>
34#include <vector>
35
36
37namespace impactx::elements
38{
58 {
60 0.834166514794446,
61 0.598104328994702,
62 0.141852844428785,
63 -0.118211272182381,
64 -9.056149864743113E-002,
65 1.803476331179615E-002,
66 4.464887700797893E-002,
67 7.364410636252136E-003,
68 -1.697541023436736E-002,
69 -9.012679515542771E-003,
70 4.367667630047725E-003,
71 5.444030542119803E-003,
72 -5.889959910931886E-005,
73 -2.409098101409192E-003,
74 -7.962712154165590E-004,
75 7.855814707106538E-004,
76 6.174930463182168E-004,
77 -1.340154094301854E-004,
78 -3.167213724698439E-004,
79 -4.925292460592617E-005,
80 1.221580597451921E-004,
81 6.331025910961789E-005,
82 -3.202416719002774E-005,
83 -3.872103053895529E-005,
84 8.212882937116278E-007
85 };
86
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0
91 };
92 };
93
101{
103 inline int next_id = 0;
104
106 inline std::map<int, std::vector<amrex::ParticleReal>> h_cos_coef = {};
108 inline std::map<int, std::vector<amrex::ParticleReal>> h_sin_coef = {};
109
111 inline std::map<int, amrex::Gpu::DeviceVector<amrex::ParticleReal>> d_cos_coef = {};
113 inline std::map<int, amrex::Gpu::DeviceVector<amrex::ParticleReal>> d_sin_coef = {};
114
115} // namespace SoftQuadrupoleData
116
118 : public mixin::Named,
119 public mixin::BeamOptic<SoftQuadrupole>,
120 public mixin::LinearTransport<SoftQuadrupole>,
121 public mixin::Thick,
122 public mixin::Alignment,
123 public mixin::PipeAperture,
124 public amrex::simd::Vectorized<amrex::simd::native_simd_size_particlereal>
125 {
126 static constexpr auto type = "SoftQuadrupole";
128
146 amrex::ParticleReal ds,
147 amrex::ParticleReal gscale,
148 std::vector<amrex::ParticleReal> cos_coef,
149 std::vector<amrex::ParticleReal> sin_coef,
150 amrex::ParticleReal dx = 0,
151 amrex::ParticleReal dy = 0,
152 amrex::ParticleReal rotation_degree = 0,
153 amrex::ParticleReal aperture_x = 0,
154 amrex::ParticleReal aperture_y = 0,
155 int mapsteps = 1,
156 int nslice = 1,
157 std::optional<std::string> name = std::nullopt
158 )
159 : Named(std::move(name)),
160 Thick(ds, nslice),
161 Alignment(dx, dy, rotation_degree),
163 m_gscale(gscale), m_mapsteps(mapsteps), m_id(SoftQuadrupoleData::next_id)
164 {
165 // next created soft quad has another id for its data
167
168 // validate sin and cos coefficients are the same length
169 m_ncoef = int(cos_coef.size());
170 if (m_ncoef != int(sin_coef.size()))
171 throw std::runtime_error("SoftQuadrupole: cos and sin coefficients must have same length!");
172
173 // host data
178
179 // device data
183 cos_coef.begin(), cos_coef.end(),
186 sin_coef.begin(), sin_coef.end(),
189
190 // low-level objects we can use on device
193 }
194
196 using BeamOptic::operator();
197
205 void compute_constants (RefPart const & refpart)
206 {
207 using namespace amrex::literals; // for _rt and _prt
208
209 Alignment::compute_constants(refpart);
210 }
211
226 template<typename T_Real=amrex::ParticleReal, typename T_IdCpu=uint64_t>
229 T_Real & AMREX_RESTRICT x,
230 T_Real & AMREX_RESTRICT y,
231 T_Real & AMREX_RESTRICT t,
232 T_Real & AMREX_RESTRICT px,
233 T_Real & AMREX_RESTRICT py,
234 T_Real & AMREX_RESTRICT pt,
235 T_IdCpu & AMREX_RESTRICT idcpu,
236 RefPart const & AMREX_RESTRICT refpart
237 ) const
238 {
239 using namespace amrex::literals; // for _rt and _prt
240
241 // shift due to alignment errors of the element
242 shift_in(x, y, px, py);
243
244 // get the linear map
246
247 // symplectic linear map for a quadrupole is computed using the
248 // Hamiltonian formalism as described in:
249 // https://uspas.fnal.gov/materials/09UNM/ComputationalMethods.pdf .
250 // R denotes the transfer matrix in the basis (x,px,y,py,t,pt),
251 // so that, e.g., R(3,4) = dyf/dpyi.
252 amrex::SmallVector<T_Real, 6, 1> const v{x, px, y, py, t, pt};
253
254 // push particles using the linear map
255 auto const out = R * v;
256
257 // assign updated values
258 x = out[1];
259 px = out[2];
260 y = out[3];
261 py = out[4];
262 t = out[5];
263 pt = out[6];
264
265 // apply transverse aperture
266 apply_aperture(x, y, idcpu);
267
268 // undo shift due to alignment errors of the element
269 shift_out(x, y, px, py);
270 }
271
277 void operator() (RefPart & AMREX_RESTRICT refpart) const
278 {
279 using namespace amrex::literals; // for _rt and _prt
280 using amrex::Math::powi;
281
282 // assign input reference particle values
283 amrex::ParticleReal const x = refpart.x;
284 amrex::ParticleReal const px = refpart.px;
285 amrex::ParticleReal const y = refpart.y;
286 amrex::ParticleReal const py = refpart.py;
287 amrex::ParticleReal const z = refpart.z;
288 amrex::ParticleReal const pz = refpart.pz;
289 amrex::ParticleReal const pt = refpart.pt;
290 amrex::ParticleReal const s = refpart.s;
291 amrex::ParticleReal const sedge = refpart.sedge;
292
293 // initialize linear map (deviation) values
294 refpart.map = decltype(refpart.map)::Identity();
295
296 // length of the current slice
297 amrex::ParticleReal const slice_ds = m_ds / nslice();
298
299 // compute initial value of beta*gamma
300 amrex::ParticleReal const bgi = std::sqrt(powi<2>(pt) - 1.0_prt);
301
302 // call integrator to advance (t,pt)
303 amrex::ParticleReal const zin = s - sedge;
304 amrex::ParticleReal const zout = zin + slice_ds;
305 int const nsteps = m_mapsteps;
306
307 integrators::symp2_integrate(refpart,zin,zout,nsteps,*this);
308 amrex::ParticleReal const ptf = refpart.pt;
309
310 /*
311 // print computed linear map:
312 for(int i=1; i<7; ++i){
313 for(int j=1; j<7; ++j){
314 amrex::PrintToFile("QuadMap.txt") << i << " " <<
315 j << " " << refpart.map(i,j) << "\n";
316 }
317 }
318 //
319 */
320
321 // advance position (x,y,z)
322 refpart.x = x + slice_ds*px/bgi;
323 refpart.y = y + slice_ds*py/bgi;
324 refpart.z = z + slice_ds*pz/bgi;
325
326 // compute final value of beta*gamma
327 amrex::ParticleReal const bgf = std::sqrt(powi<2>(ptf) - 1.0_prt);
328
329 // advance momentum (px,py,pz)
330 refpart.px = px*bgf/bgi;
331 refpart.py = py*bgf/bgi;
332 refpart.pz = pz*bgf/bgi;
333
334 // advance integrated path length
335 refpart.s = s + slice_ds;
336 }
337
339 using LinearTransport::operator();
340
347 Map6x6
348 transport_map ([[maybe_unused]] RefPart const & AMREX_RESTRICT refpart) const
349 {
350
352 R = refpart.map;
353
354 return R;
355 }
356
363 std::tuple<amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal>
365 Quad_Bfield (amrex::ParticleReal const zeval) const
366 {
367 using namespace amrex::literals; // for _rt and _prt
368
369 // pick the right data depending if we are on the host side
370 // (reference particle push) or device side (particles):
371#if AMREX_DEVICE_COMPILE
372 amrex::ParticleReal* cos_data = m_cos_d_data;
373 amrex::ParticleReal* sin_data = m_sin_d_data;
374#else
375 amrex::ParticleReal* cos_data = m_cos_h_data;
376 amrex::ParticleReal* sin_data = m_sin_h_data;
377#endif
378
379 // specify constants
381 amrex::ParticleReal const zlen = m_ds;
382 amrex::ParticleReal const zmid = zlen * 0.5_prt;
383
384 // compute on-axis magnetic field (z is relative to quadrupole midpoint)
385 amrex::ParticleReal bfield = 0.0;
386 amrex::ParticleReal bfieldp = 0.0;
387 amrex::ParticleReal bfieldint = 0.0;
388 amrex::ParticleReal const z = zeval - zmid;
389
390 if (std::abs(z) <= zmid)
391 {
392 bfield = 0.5_prt*cos_data[0];
393 bfieldint = z*bfield;
394 for (int j=1; j < m_ncoef; ++j)
395 {
396 bfield = bfield + cos_data[j] *std::cos(j * 2 * pi * z / zlen) +
397 sin_data[j] *std::sin(j * 2 * pi * z / zlen);
398 bfieldp = bfieldp - j * 2 * pi * cos_data[j] *std::sin(j * 2 * pi * z / zlen) / zlen +
399 j * 2 * pi * sin_data[j] *std::cos(j * 2 * pi * z / zlen) / zlen;
400 bfieldint = bfieldint + zlen * cos_data[j] *std::sin(j * 2 * pi * z / zlen) / (j * 2 * pi) -
401 zlen * sin_data[j] *std::cos(j * 2 * pi * z / zlen) / (j * 2 * pi);
402 }
403 }
404 return std::make_tuple(bfield, bfieldp, bfieldint);
405 }
406
416 void map1 (amrex::ParticleReal const tau,
417 RefPart & refpart,
418 [[maybe_unused]] amrex::ParticleReal & zeval) const
419 {
420 using namespace amrex::literals; // for _rt and _prt
421 using amrex::Math::powi;
422
423 // push the reference particle
424 amrex::ParticleReal const t = refpart.t;
425 amrex::ParticleReal const pt = refpart.pt;
426 amrex::ParticleReal const z = zeval;
427
428 if (pt < -1.0_prt) {
429 refpart.t = t + tau/std::sqrt(1.0_prt - powi<-2>(pt));
430 refpart.pt = pt;
431 }
432 else {
433 refpart.t = t;
434 refpart.pt = pt;
435 }
436
437 zeval = z + tau;
438
439 // push the linear map equations
441 amrex::ParticleReal const betgam = refpart.beta_gamma();
442
443 refpart.map(1,1) = R(1,1) + tau*R(2,1);
444 refpart.map(1,2) = R(1,2) + tau*R(2,2);
445 refpart.map(1,3) = R(1,3) + tau*R(2,3);
446 refpart.map(1,4) = R(1,4) + tau*R(2,4);
447
448 refpart.map(3,1) = R(3,1) + tau*R(4,1);
449 refpart.map(3,2) = R(3,2) + tau*R(4,2);
450 refpart.map(3,3) = R(3,3) + tau*R(4,3);
451 refpart.map(3,4) = R(3,4) + tau*R(4,4);
452
453 refpart.map(5,5) = R(5,5) + tau*R(6,5)/powi<2>(betgam);
454 refpart.map(5,6) = R(5,6) + tau*R(6,6)/powi<2>(betgam);
455
456 }
457
467 void map2 (amrex::ParticleReal const tau,
468 RefPart & refpart,
469 amrex::ParticleReal & zeval) const
470 {
471 using namespace amrex::literals; // for _rt and _prt
472
473 amrex::ParticleReal const t = refpart.t;
474 amrex::ParticleReal const pt = refpart.pt;
475
476 // Define parameters and intermediate constants
477 amrex::ParticleReal const G0 = m_gscale;
478
479 // push the reference particle
480 auto [bz, bzp, bzint] = Quad_Bfield(zeval);
481 amrex::ignore_unused(bzp, bzint);
482
483 refpart.t = t;
484 refpart.pt = pt;
485
486 // push the linear map equations
488 amrex::ParticleReal const alpha = G0*bz;
489
490 refpart.map(2,1) = R(2,1) - tau*alpha*R(1,1);
491 refpart.map(2,2) = R(2,2) - tau*alpha*R(1,2);
492 refpart.map(2,3) = R(2,3) - tau*alpha*R(1,3);
493 refpart.map(2,4) = R(2,4) - tau*alpha*R(1,4);
494
495 refpart.map(4,1) = R(4,1) + tau*alpha*R(3,1);
496 refpart.map(4,2) = R(4,2) + tau*alpha*R(3,2);
497 refpart.map(4,3) = R(4,3) + tau*alpha*R(3,3);
498 refpart.map(4,4) = R(4,4) + tau*alpha*R(3,4);
499
500 }
501
504 void
506 {
507 // remove from unique data map
508 if (SoftQuadrupoleData::h_cos_coef.count(m_id) != 0u)
510 if (SoftQuadrupoleData::h_sin_coef.count(m_id) != 0u)
512
513 if (SoftQuadrupoleData::d_cos_coef.count(m_id) != 0u)
515 if (SoftQuadrupoleData::d_sin_coef.count(m_id) != 0u)
517 }
518
519 amrex::ParticleReal m_gscale;
521 int m_id;
522
523 int m_ncoef = 0;
524 amrex::ParticleReal* m_cos_h_data = nullptr;
525 amrex::ParticleReal* m_sin_h_data = nullptr;
526 amrex::ParticleReal* m_cos_d_data = nullptr;
527 amrex::ParticleReal* m_sin_d_data = nullptr;
528 };
529
530} // namespace impactx
531
532#endif // IMPACTX_SOFTQUAD_H
#define AMREX_FORCE_INLINE
#define AMREX_RESTRICT
#define AMREX_GPU_HOST_DEVICE
#define AMREX_GPU_HOST
static constexpr amrex::Real pi
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr HostToDevice hostToDevice
void streamSynchronize() noexcept
PODVector< T, ArenaAllocator< T > > DeviceVector
constexpr T powi(T x) noexcept
__host__ __device__ void ignore_unused(const Ts &...)
SmallMatrix< T, N, 1, Order::F, StartIndex > SmallVector
Definition SoftQuad.H:101
std::map< int, amrex::Gpu::DeviceVector< amrex::ParticleReal > > d_cos_coef
device: cosine coefficients in Fourier expansion of on-axis magnetic field Bz
Definition SoftQuad.H:111
std::map< int, std::vector< amrex::ParticleReal > > h_sin_coef
host: sine coefficients in Fourier expansion of on-axis magnetic field Bz
Definition SoftQuad.H:108
std::map< int, amrex::Gpu::DeviceVector< amrex::ParticleReal > > d_sin_coef
device: sine coefficients in Fourier expansion of on-axis magnetic field Bz
Definition SoftQuad.H:113
std::map< int, std::vector< amrex::ParticleReal > > h_cos_coef
host: cosine coefficients in Fourier expansion of on-axis magnetic field Bz
Definition SoftQuad.H:106
int next_id
last used id for a created soft quad
Definition SoftQuad.H:103
Definition All.H:54
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void symp2_integrate(RefPart &refpart, amrex::ParticleReal const zin, amrex::ParticleReal const zout, int const nsteps, T_Element const &element)
Definition Integrators.H:36
@ s
fixed s as the independent variable
Definition ImpactXParticleContainer.H:37
@ 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 amrex::ParticleReal beta_gamma() const
Definition ReferenceParticle.H:110
amrex::ParticleReal pt
energy, normalized by rest energy
Definition ReferenceParticle.H:40
amrex::SmallMatrix< amrex::ParticleReal, 6, 6, amrex::Order::F, 1 > map
linearized map
Definition ReferenceParticle.H:45
amrex::ParticleReal t
clock time * c in meters
Definition ReferenceParticle.H:36
Definition SoftQuad.H:58
amrex::Vector< amrex::ParticleReal > default_cos_coef
Definition SoftQuad.H:59
amrex::Vector< amrex::ParticleReal > default_sin_coef
Definition SoftQuad.H:87
static constexpr auto type
Definition SoftQuad.H:126
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void map1(amrex::ParticleReal const tau, RefPart &refpart, amrex::ParticleReal &zeval) const
Definition SoftQuad.H:416
amrex::ParticleReal * m_sin_h_data
non-owning pointer to host cosine coefficients
Definition SoftQuad.H:525
int m_ncoef
unique soft quad id used for data lookup map
Definition SoftQuad.H:523
ImpactXParticleContainer::ParticleType PType
Definition SoftQuad.H:127
amrex::ParticleReal * m_cos_d_data
non-owning pointer to host sine coefficients
Definition SoftQuad.H:526
SoftQuadrupole(amrex::ParticleReal ds, amrex::ParticleReal gscale, std::vector< amrex::ParticleReal > cos_coef, std::vector< amrex::ParticleReal > sin_coef, amrex::ParticleReal dx=0, amrex::ParticleReal dy=0, amrex::ParticleReal rotation_degree=0, amrex::ParticleReal aperture_x=0, amrex::ParticleReal aperture_y=0, int mapsteps=1, int nslice=1, std::optional< std::string > name=std::nullopt)
Definition SoftQuad.H:145
int m_id
number of map integration steps per slice
Definition SoftQuad.H:521
AMREX_GPU_HOST AMREX_FORCE_INLINE Map6x6 transport_map(RefPart const &AMREX_RESTRICT refpart) const
Definition SoftQuad.H:348
amrex::ParticleReal * m_cos_h_data
number of Fourier coefficients
Definition SoftQuad.H:524
std::tuple< amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal > AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Quad_Bfield(amrex::ParticleReal const zeval) const
Definition SoftQuad.H:365
void finalize()
Definition SoftQuad.H:505
amrex::ParticleReal m_gscale
Definition SoftQuad.H:519
int m_mapsteps
scaling factor for quad field gradient
Definition SoftQuad.H:520
amrex::ParticleReal * m_sin_d_data
non-owning pointer to device cosine coefficients
Definition SoftQuad.H:527
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 SoftQuad.H:228
void compute_constants(RefPart const &refpart)
Definition SoftQuad.H:205
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void map2(amrex::ParticleReal const tau, RefPart &refpart, amrex::ParticleReal &zeval) const
Definition SoftQuad.H:467
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 pipeaperture.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void apply_aperture(T_Real &AMREX_RESTRICT x, T_Real &AMREX_RESTRICT y, T_IdCpu &AMREX_RESTRICT idcpu) const
Definition pipeaperture.H:59
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal aperture_x() const
Definition pipeaperture.H:90
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal aperture_y() const
Definition pipeaperture.H:101
PipeAperture(amrex::ParticleReal aperture_x, amrex::ParticleReal aperture_y)
Definition pipeaperture.H:32
Definition thick.H:24
Thick(amrex::ParticleReal ds, int nslice)
Definition thick.H:30
amrex::ParticleReal m_ds
Definition thick.H:58
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal ds() const
Definition thick.H:53
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int nslice() const
Definition thick.H:43