ImpactX
Loading...
Searching...
No Matches
PolygonAperture.H
Go to the documentation of this file.
1/* Copyright 2022-2026 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: Eric G. Stern, Chad Mitchell, Axel Huebl
8 * License: BSD-3-Clause-LBNL
9 */
10#ifndef IMPACTX_POLYGONAPERTURE_H
11#define IMPACTX_POLYGONAPERTURE_H
12
14#include "mixin/alignment.H"
15#include "mixin/beamoptic.H"
16#include "mixin/dynamicdata.H"
18#include "mixin/named.H"
19#include "mixin/nofinalize.H"
20#include "mixin/spintransport.H"
21#include "mixin/thin.H"
22
23#include <ablastr/constant.H>
24
25#include <AMReX_Enum.H>
26#include <AMReX_Extension.H>
27#include <AMReX_Math.H>
28#include <AMReX_REAL.H>
29#include <AMReX_SIMD.H>
30#include <AMReX_TrackedVector.H>
31
32#include <cmath>
33#include <map>
34#include <memory>
35#include <stdexcept>
36#include <vector>
37
38namespace impactx::elements
39{
50
52 : public mixin::Named,
53 public mixin::BeamOptic<PolygonAperture>,
54 public mixin::LinearTransport<PolygonAperture>,
55 public mixin::Thin,
56 public mixin::Alignment,
59 // public amrex::simd::Vectorized<amrex::simd::native_simd_size_particlereal>
60 {
61 static constexpr auto type = "PolygonAperture";
63
65
67 transmit,
68 absorb,
69 );
70
71 static std::string
72 action_name (Action const & action);
73
77 static constexpr bool DEFAULT_shift_odd_x = false;
78 static constexpr Action DEFAULT_action = Action::transmit;
79
97 std::vector< amrex::ParticleReal> vertices_x,
98 std::vector< amrex::ParticleReal> vertices_y,
102 bool shift_odd_x = DEFAULT_shift_odd_x,
103 Action action = DEFAULT_action,
107 std::optional<std::string> name = DEFAULT_name
108 )
109 : Named(std::move(name)),
110 Alignment(dx, dy, rotation_degree),
111 m_action(action), m_repeat_x(repeat_x), m_repeat_y(repeat_y), m_shift_odd_x(shift_odd_x),
112 m_id(DynamicData::allocate_id()),
113 m_min_radius2(min_radius2)
114 {
115 using namespace amrex::literals; // for _rt and _prt
116
117 if (m_repeat_y == 0_prt && m_shift_odd_x) {
118 throw std::runtime_error("PolygonAperture: shift_odd_x can only be used if repeat_y is set, too!");
119 }
120
121 m_nvert = vertices_x.size();
122 if (m_nvert != vertices_y.size()) {
123 throw std::runtime_error("PolygonAperture: horizontal and vertical vertices arrays must have same length!");
124 }
125
126 if ((vertices_x[0] != vertices_x[m_nvert-1]) ||
127 (vertices_y[0] != vertices_y[m_nvert-1])) {
128 throw std::runtime_error("PolygonAperture: first and last vertex must be exactly equal!");
129 }
130
131 auto& vert = DynamicData::emplace(
132 m_id,
133 std::move(vertices_x),
134 std::move(vertices_y)
135 );
136 m_vertices_x_h_data = vert.x.host_const().data();
137 m_vertices_y_h_data = vert.y.host_const().data();
138 }
139
141 void reverse () { /* no-op */ }
142
144 using BeamOptic::operator();
145
153 void compute_constants ([[maybe_unused]] RefPart const & refpart)
154 {
155 Alignment::compute_constants(refpart);
156
157 // Ensure dynamic vertex data is on GPU and we have fresh pointers to it
158 auto const & vert = *DynamicData::get(m_id);
159 m_vertices_x_d_data = vert.x.device_const().data();
160 m_vertices_y_d_data = vert.y.device_const().data();
161 }
162
175 template<typename T_Real=amrex::ParticleReal, typename T_IdCpu=uint64_t>
178 T_Real const & AMREX_RESTRICT x,
179 T_Real const & AMREX_RESTRICT y,
180 [[maybe_unused]] T_Real const & AMREX_RESTRICT t,
181 [[maybe_unused]] T_Real const & AMREX_RESTRICT px,
182 [[maybe_unused]] T_Real const & AMREX_RESTRICT py,
183 [[maybe_unused]] T_Real const & AMREX_RESTRICT pt,
184 T_IdCpu & AMREX_RESTRICT idcpu,
185 [[maybe_unused]] RefPart const & AMREX_RESTRICT refpart
186 ) const
187 {
188 // a complex type with two T_Real
190
191 using namespace amrex::literals; // for _rt and _prt
192 namespace stdx = amrex::simd::stdx;
193 using amrex::Math::powi;
194 using std::fmod;
195 using std::abs;
196 using amrex::arg;
197 using VBool = decltype(x>0_prt);
198
199 // define intermediate variables
200 amrex::ParticleReal const dx = m_repeat_x * 0.5_prt;
201 amrex::ParticleReal const dy = m_repeat_y * 0.5_prt;
202
203 // shift every 2nd row by half of m_repeat_x
204 T_Real sx = x;
205 T_Real const sy = y;
206 VBool const shift_x = m_shift_odd_x == false ? VBool{false} : fmod(floor((y+dy)/m_repeat_y), 2) != T_Real{0};
207#ifdef AMREX_USE_SIMD
208 amrex::simd::stdx::where(shift_x, sx) += dx;
209#else
210 sx += shift_x ? dx : 0_prt;
211#endif
212
213 // if the aperture is periodic, shift sx,sy coordinates to the fundamental domain
214 T_Real const u = (m_repeat_x == 0_prt) ? sx : (fmod(abs(sx)+dx, m_repeat_x)-dx);
215 T_Real const v = (m_repeat_y == 0_prt) ? sy : (fmod(abs(sy)+dy, m_repeat_y)-dy);
216
217 // compare against the aperture boundary
218 VBool inside_aperture;
219
220 // calculate whether point is inside polygon or not
221 T_Real const r2 = powi<2>(u) + powi<2>(v);
222 // are we inside the minimum radius?
223 if (r2 < m_min_radius2) {
224 inside_aperture = VBool(true); // yes!
225 } else{
226
227#if AMREX_DEVICE_COMPILE
228 amrex::ParticleReal const * vertices_x = m_vertices_x_d_data;
229 amrex::ParticleReal const * vertices_y = m_vertices_y_d_data;
230#else
231 amrex::ParticleReal const * vertices_x = m_vertices_x_h_data;
232 amrex::ParticleReal const * vertices_y = m_vertices_y_h_data;
233#endif
234
235 // no, we have to do the polygon calculation
236
237 /*
238 * The algorithms works as follows:
239 *
240 * You have a polygon (in 2D) described by points V_1, ..., V_n arranged
241 * counter-clockwise. You have a particle with coordinates w = (x,y).
242 * Get the difference vector from the particle to each of
243 * the vertices in turn expressed as a complex number z_k, k=1,n. Now the angle
244 * between the particle and vertex i and vertex j is
245 *
246 * theta_{ij} = arg(\bar{z_i} z_j)
247 * This is easily demonstrated by expressing the complex numbers in exponential
248 * polar notation and also the angle is positive in the counter-clockwise direction.
249 *
250 * Take the sum of all the angles. The angle sum for particle inside the polygon will
251 * be 2 pi. The sum of angles of particle outside of the polygon will be 0.
252 */
253 T_Real thetasum = 0.0;
254 Complex v1conj, v2;
255
256 for (size_t i = 0; i < m_nvert-1; ++i) {
257 v1conj = Complex(u - vertices_x[i], -(v-vertices_y[i]));
258 v2 = Complex(u - vertices_x[i+1], v-vertices_y[i+1]);
259 thetasum += arg(v2 * v1conj);
260 }
261 inside_aperture = abs(thetasum/(2*ablastr::constant::math::pi)) > 1.0e-12_prt;
262 }
263
264 // For transmit (default): invalidate if outside aperture
265 // For absorb: invalidate if inside aperture
266 auto const invalid_mask = m_action == Action::transmit ? !inside_aperture : inside_aperture;
268 }
269
271 using Thin::operator();
272
289 template<typename T_Real=amrex::ParticleReal, typename T_IdCpu=uint64_t>
292 T_Real const & AMREX_RESTRICT x,
293 T_Real const & AMREX_RESTRICT y,
294 T_Real const & AMREX_RESTRICT t,
295 T_Real const & AMREX_RESTRICT px,
296 T_Real const & AMREX_RESTRICT py,
297 T_Real const & AMREX_RESTRICT pt,
298 [[maybe_unused]] T_Real const & AMREX_RESTRICT sx,
299 [[maybe_unused]] T_Real const & AMREX_RESTRICT sy,
300 [[maybe_unused]] T_Real const & AMREX_RESTRICT sz,
301 T_IdCpu & AMREX_RESTRICT idcpu,
302 RefPart const & AMREX_RESTRICT refpart
303 ) const
304 {
305 // spin is unaffected
306
307 // phase space push
308 (*this)(x, y, t, px, py, pt, idcpu, refpart);
309 }
310
312 using LinearTransport::operator();
313
324 Map6x6
325 transport_map ([[maybe_unused]] RefPart const & AMREX_RESTRICT refpart) const
326 {
327 // apply the transverse rotation (roll) alignment error
329 }
330
331 Action m_action;
335
336 int m_id;
337
338 amrex::ParticleReal m_min_radius2; // minimum radius in which all pass squared
339
340 std::vector<double>::size_type m_nvert = 0;
345
346 };
347
348} // namespace impactx
349
352
353#endif // IMPACTX_POLYGONAPERTURE_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::GpuComplex< amrex::Real > Complex
#define IMPACTX_GPUDATA_EXTERN(ElementType)
Definition dynamicdata.H:169
amrex_particle_real ParticleReal
constexpr T powi(T x) noexcept
__host__ __device__ detail::where_expression< T > where(bool const mask, T &value)
__host__ __device__ T arg(const GpuComplex< T > &a_z) noexcept
__host__ __device__ T abs(const GpuComplex< T > &a_z) noexcept
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
__host__ __device__ void make_invalid() const noexcept
static constexpr __host__ __device__ SmallMatrix< T, NRows, NCols, ORDER, StartIndex > Identity() noexcept
Definition ReferenceParticle.H:33
Definition PolygonAperture.H:60
AMREX_GPU_HOST AMREX_FORCE_INLINE Map6x6 transport_map(RefPart const &AMREX_RESTRICT refpart) const
Definition PolygonAperture.H:325
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void operator()(T_Real const &AMREX_RESTRICT x, T_Real const &AMREX_RESTRICT y, T_Real const &AMREX_RESTRICT t, T_Real const &AMREX_RESTRICT px, T_Real const &AMREX_RESTRICT py, T_Real const &AMREX_RESTRICT pt, T_IdCpu &AMREX_RESTRICT idcpu, RefPart const &AMREX_RESTRICT refpart) const
Definition PolygonAperture.H:177
PolygonAperture(std::vector< amrex::ParticleReal > vertices_x, std::vector< amrex::ParticleReal > vertices_y, amrex::ParticleReal min_radius2=DEFAULT_min_radius2, amrex::ParticleReal repeat_x=DEFAULT_repeat_x, amrex::ParticleReal repeat_y=DEFAULT_repeat_y, bool shift_odd_x=DEFAULT_shift_odd_x, Action action=DEFAULT_action, amrex::ParticleReal dx=DEFAULT_dx, amrex::ParticleReal dy=DEFAULT_dy, amrex::ParticleReal rotation_degree=DEFAULT_rotation_degree, std::optional< std::string > name=DEFAULT_name)
Definition PolygonAperture.H:96
static constexpr Action DEFAULT_action
Definition PolygonAperture.H:78
AMREX_ENUM_IN_CLASS(Action, transmit, absorb,)
amrex::ParticleReal const * m_vertices_y_h_data
non-owning pointer to host x vertices
Definition PolygonAperture.H:342
amrex::ParticleReal const * m_vertices_y_d_data
non-owning pointer to device x vertices
Definition PolygonAperture.H:344
static constexpr amrex::ParticleReal DEFAULT_min_radius2
Definition PolygonAperture.H:74
amrex::ParticleReal m_repeat_y
horizontal period for repeated masking
Definition PolygonAperture.H:333
static constexpr amrex::ParticleReal DEFAULT_repeat_x
Definition PolygonAperture.H:75
amrex::ParticleReal const * m_vertices_x_d_data
non-owning pointer to host vertices
Definition PolygonAperture.H:343
std::vector< double >::size_type m_nvert
Definition PolygonAperture.H:340
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void spin_and_phasespace_push(T_Real const &AMREX_RESTRICT x, T_Real const &AMREX_RESTRICT y, T_Real const &AMREX_RESTRICT t, T_Real const &AMREX_RESTRICT px, T_Real const &AMREX_RESTRICT py, T_Real const &AMREX_RESTRICT pt, T_Real const &AMREX_RESTRICT sx, T_Real const &AMREX_RESTRICT sy, T_Real const &AMREX_RESTRICT sz, T_IdCpu &AMREX_RESTRICT idcpu, RefPart const &AMREX_RESTRICT refpart) const
Definition PolygonAperture.H:291
void compute_constants(RefPart const &refpart)
Definition PolygonAperture.H:153
void reverse()
Definition PolygonAperture.H:141
Action m_action
Definition PolygonAperture.H:331
int m_id
for hexagonal/triangular mask patterns: horizontal shift of every 2nd (odd) vertical period by m_repe...
Definition PolygonAperture.H:336
static constexpr bool DEFAULT_shift_odd_x
Definition PolygonAperture.H:77
static constexpr auto type
Definition PolygonAperture.H:61
bool m_shift_odd_x
vertical period for repeated masking
Definition PolygonAperture.H:334
amrex::ParticleReal m_min_radius2
unique PolygonAperture id used for data lookup map
Definition PolygonAperture.H:338
amrex::ParticleReal const * m_vertices_x_h_data
number of vertices
Definition PolygonAperture.H:341
static std::string action_name(Action const &action)
Definition PolygonAperture.cpp:18
ImpactXParticleContainer::ParticleType PType
Definition PolygonAperture.H:62
amrex::ParticleReal m_repeat_x
action type (transmit, absorb)
Definition PolygonAperture.H:332
mixin::GPUDataRegistry< PolygonVertices > DynamicData
Definition PolygonAperture.H:64
static constexpr amrex::ParticleReal DEFAULT_repeat_y
Definition PolygonAperture.H:76
Definition PolygonAperture.H:46
amrex::Gpu::TrackedVector< amrex::ParticleReal > y
Definition PolygonAperture.H:48
amrex::Gpu::TrackedVector< amrex::ParticleReal > x
Definition PolygonAperture.H:47
Definition alignment.H:29
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal dy() const
Definition alignment.H:193
static constexpr amrex::ParticleReal DEFAULT_dy
Definition alignment.H:34
static constexpr amrex::ParticleReal DEFAULT_dx
Definition alignment.H:33
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal dx() const
Definition alignment.H:183
AMREX_GPU_HOST AMREX_FORCE_INLINE Map6x6 rotate_aligned_map(Map6x6 const &R) const
Definition alignment.H:267
Alignment(amrex::ParticleReal dx, amrex::ParticleReal dy, amrex::ParticleReal rotation_degree)
Definition alignment.H:43
static constexpr amrex::ParticleReal DEFAULT_rotation_degree
Definition alignment.H:35
Definition beamoptic.H:567
static std::shared_ptr< PolygonVertices > const & get(int id)
Definition dynamicdata.H:98
static PolygonVertices & emplace(int id, Args &&... args)
Definition dynamicdata.H:125
Definition lineartransport.H:50
Definition named.H:29
static constexpr std::nullopt_t DEFAULT_name
Definition named.H:30
AMREX_GPU_HOST Named(std::optional< std::string > name)
Definition named.H:59
AMREX_FORCE_INLINE std::string name() const
Definition named.H:124
Definition nofinalize.H:22
Definition spintransport.H:36
Definition thin.H:24