WarpX
Loading...
Searching...
No Matches
AddPlasmaUtilities.H
Go to the documentation of this file.
1/* Copyright 2024 The WarpX Community
2 *
3 * This file is part of WarpX.
4 *
5 * License: BSD-3-Clause-LBNL
6 * Authors: Andrew Myers
7 */
8#ifndef WARPX_ADDPLASMAUTILITIES_H_
9#define WARPX_ADDPLASMAUTILITIES_H_
10
12
13#ifdef WARPX_QED
16#endif
17
18#include <AMReX_Array.H>
19#include <AMReX_Box.H>
20#include <AMReX_GpuContainers.H>
21#include <AMReX_IntVect.H>
22#include <AMReX_REAL.H>
23#include <AMReX_RealBox.H>
24
25struct PDim3 {
27
29 explicit
31 x{static_cast<amrex::ParticleReal>(a.x)},
32 y{static_cast<amrex::ParticleReal>(a.y)},
33 z{static_cast<amrex::ParticleReal>(a.z)}
34 {}
35
37 ~PDim3() = default;
38
40 PDim3(PDim3 const &) = default;
42 PDim3& operator=(PDim3 const &) = default;
44 PDim3(PDim3&&) = default;
46 PDim3& operator=(PDim3&&) = default;
47};
48
49/*
50 Finds the overlap region between the given tile_realbox and part_realbox, returning true
51 if an overlap exists and false if otherwise. This also sets the parameters overlap_realbox,
52 overlap_box, and shifted to the appropriate values.
53 */
54bool find_overlap (const amrex::RealBox& tile_realbox, const amrex::RealBox& part_realbox,
57 amrex::RealBox& overlap_realbox, amrex::Box& overlap_box, amrex::IntVect& shifted);
58
59/*
60 Finds the overlap region between the given tile_realbox, part_realbox and the surface used for
61 flux injection, returning true if an overlap exists and false if otherwise. This also sets the
62 parameters overlap_realbox, overlap_box, and shifted to the appropriate values.
63 */
64bool find_overlap_flux (const amrex::RealBox& tile_realbox, const amrex::RealBox& part_realbox,
67 const PlasmaInjector& plasma_injector,
68 amrex::RealBox& overlap_realbox, amrex::Box& overlap_box, amrex::IntVect& shifted);
69
70/*
71 This computes the scale_fac (used for setting the particle weights) on a volumetric basis.
72 */
75 const amrex::Long pcount) {
76 using namespace amrex::literals;
77 return (pcount != 0) ? AMREX_D_TERM(dx[0],*dx[1],*dx[2])/pcount : 0.0_rt;
78}
79
80/*
81 Given a refinement ratio, this computes the total increase in resolution for a plane
82 defined by the normal_axis.
83 */
85int compute_area_weights (const amrex::IntVect& iv, const int normal_axis) {
86 int r = AMREX_D_TERM(iv[0],*iv[1],*iv[2]);
87#if defined(WARPX_DIM_3D)
88 r /= iv[normal_axis];
89#elif defined(WARPX_DIM_RZ) || defined(WARPX_DIM_XZ)
90 if (normal_axis == 0) { r /= iv[0]; }
91 else if (normal_axis == 2) { r /= iv[1]; }
92#elif defined(WARPX_DIM_1D_Z)
93 if (normal_axis == 2) { r /= iv[0]; }
94#elif defined(WARPX_DIM_RCYLINDER) || defined(WARPX_DIM_RSPHERE)
95 if (normal_axis == 0) { r /= iv[0]; }
96#endif
97 return r;
98}
99
100
101#ifdef AMREX_USE_EB
102/*
103 * \brief This computes the scale_fac (used for setting the particle weights) on a on area basis
104 * (used for flux injection from the embedded boundary).
105 *
106 * \param[in] dx: cell size in each direction
107 * \param[in] num_ppc_real: number of particles per cell
108 * \param[in] eb_bnd_normal_arr: array containing the normal to the embedded boundary
109 * \param[in] i, j, k: indices of the cell
110 *
111 * \return scale_fac: the scaling factor to be applied to the weight of the particles
112 */
114amrex::Real compute_scale_fac_area_eb (
116 const amrex::Real num_ppc_real,
117 AMREX_D_DECL(const amrex::Real n0,
118 const amrex::Real n1,
119 const amrex::Real n2)) {
120 using namespace amrex::literals;
121 // Scale particle weight by the area of the emitting surface, within one cell
122 // By definition, eb_bnd_area_arr is normalized (unitless).
123 // Here we undo the normalization (i.e. multiply by the surface used for normalization in amrex:
124 // see https://amrex-codes.github.io/amrex/docs_html/EB.html#embedded-boundary-data-structures)
125#if defined(WARPX_DIM_3D)
126 amrex::Real scale_fac = std::sqrt(amrex::Math::powi<2>(n0*dx[1]*dx[2]) +
127 amrex::Math::powi<2>(n1*dx[0]*dx[2]) +
128 amrex::Math::powi<2>(n2*dx[0]*dx[1]));
129
130#elif defined(WARPX_DIM_RZ) || defined(WARPX_DIM_XZ)
131 amrex::Real scale_fac = std::sqrt(amrex::Math::powi<2>(n0*dx[1]) +
132 amrex::Math::powi<2>(n1*dx[0]));
133#else
134 amrex::ignore_unused(dx, AMREX_D_DECL(n0,n1,n2));
135 amrex::Real scale_fac = 0.0_rt;
136#endif
137 // Do not multiply by eb_bnd_area_arr(i,j,k) here because this
138 // already taken into account by emitting a number of macroparticles
139 // that is proportional to the area of eb_bnd_area_arr(i,j,k).
140 scale_fac /= num_ppc_real;
141 return scale_fac;
142}
143
144/* \brief Rotate the momentum of the particle so that the z direction
145 * transforms to the normal of the embedded boundary.
146 *
147 * More specifically, before calling this function, `pu.z` has the
148 * momentum distribution that is meant for the direction normal to the
149 * embedded boundary, and `pu.x`/`pu.y` have the momentum distribution that
150 * is meant for the tangentional direction. After calling this function,
151 * `pu.x`, `pu.y`, `pu.z` will have the correct momentum distribution,
152 * consistent with the local normal to the embedded boundary.
153 *
154 * \param[inout] pu momentum of the particle
155 * \param[in] eb_bnd_normal_arr: array containing the normal to the embedded boundary
156 * \param[in] i, j, k: indices of the cell
157 * */
159void rotate_momentum_eb (
160 PDim3 & pu,
161 AMREX_D_DECL(const amrex::Real n0,
162 const amrex::Real n1,
163 const amrex::Real n2))
164{
165 using namespace amrex::literals;
166
167#if defined(WARPX_DIM_3D)
168 // The minus sign below takes into account the fact that eb_bnd_normal_arr
169 // points towards the covered region, while particles are to be emitted
170 // *away* from the covered region.
171 amrex::Real const nx = -n0;
172 amrex::Real const ny = -n1;
173 amrex::Real const nz = -n2;
174
175 // Rotate the momentum in theta and phi
176 amrex::Real const cos_theta = nz;
177 amrex::Real const sin_theta = std::sqrt(1._rt-nz*nz);
178 amrex::Real const nperp = std::sqrt(nx*nx + ny*ny);
179 amrex::Real cos_phi = 1;
180 amrex::Real sin_phi = 0;
181 if ( nperp > 0.0 ) {
182 cos_phi = nx/nperp;
183 sin_phi = ny/nperp;
184 }
185 // Apply rotation matrix
186 amrex::Real const ux = pu.x*cos_theta*cos_phi - pu.y*sin_phi + pu.z*sin_theta*cos_phi;
187 amrex::Real const uy = pu.x*cos_theta*sin_phi + pu.y*cos_phi + pu.z*sin_theta*sin_phi;
188 amrex::Real const uz = -pu.x*sin_theta + pu.z*cos_theta;
189 pu.x = ux;
190 pu.y = uy;
191 pu.z = uz;
192
193#elif defined(WARPX_DIM_RZ) || defined(WARPX_DIM_XZ)
194 // The minus sign below takes into account the fact that eb_bnd_normal_arr
195 // points towards the covered region, while particles are to be emitted
196 // *away* from the covered region.
197 amrex::Real const sin_theta = -n0;
198 amrex::Real const cos_theta = -n1;
199 amrex::Real const uz = pu.z*cos_theta - pu.x*sin_theta;
200 amrex::Real const ux = pu.x*cos_theta + pu.z*sin_theta;
201 pu.x = ux;
202 pu.z = uz;
203#else
204 amrex::ignore_unused(pu, AMREX_D_DECL(n0,n1,n2));
205#endif
206}
207#endif //AMREX_USE_EB
208
209/*
210 This computes the scale_fac (used for setting the particle weights) on a on area basis
211 (used for flux injection from a plane).
212 */
215 const amrex::Real num_ppc_real, const int flux_normal_axis) {
216 using namespace amrex::literals;
217 amrex::Real scale_fac = AMREX_D_TERM(dx[0],*dx[1],*dx[2])/num_ppc_real;
218 // Scale particle weight by the area of the emitting surface, within one cell
219#if defined(WARPX_DIM_3D)
220 scale_fac /= dx[flux_normal_axis];
221#elif defined(WARPX_DIM_RZ) || defined(WARPX_DIM_XZ)
222 // When emission is in the r direction, the emitting surface is a cylinder.
223 // The factor 2*pi*r is added later below.
224 if (flux_normal_axis == 0) { scale_fac /= dx[0]; }
225 // When emission is in the z direction, the emitting surface is an annulus
226 // The factor 2*pi*r is added later below.
227 if (flux_normal_axis == 2) { scale_fac /= dx[1]; }
228 // When emission is in the theta direction (flux_normal_axis == 1),
229 // the emitting surface is a rectangle, within the plane of the simulation
230#elif defined(WARPX_DIM_1D_Z)
231 if (flux_normal_axis == 2) { scale_fac /= dx[0]; }
232#elif defined(WARPX_DIM_RCYLINDER) || defined(WARPX_DIM_RSPHERE)
233 if (flux_normal_axis == 0) { scale_fac /= dx[0]; }
234#endif
235 return scale_fac;
236}
237
238/*
239 These structs encapsulates several data structures needed for using the parser during plasma
240 injection.
241 */
243{
244 PlasmaParserWrapper (std::size_t a_num_user_int_attribs,
245 std::size_t a_num_user_real_attribs,
246 const amrex::Vector< std::unique_ptr<amrex::Parser> >& a_user_int_attrib_parser,
247 const amrex::Vector< std::unique_ptr<amrex::Parser> >& a_user_real_attrib_parser);
248
251};
252
254{
255 template <typename SoAType>
256 PlasmaParserHelper (SoAType& a_soa, std::size_t old_size,
257 const std::vector<std::string>& a_user_int_attribs,
258 const std::vector<std::string>& a_user_real_attribs,
259 const PlasmaParserWrapper& wrapper) :
260 m_wrapper_ptr(&wrapper) {
261 m_pa_user_int_pinned.resize(a_user_int_attribs.size());
262 m_pa_user_real_pinned.resize(a_user_real_attribs.size());
263
264#ifdef AMREX_USE_GPU
265 m_d_pa_user_int.resize(a_user_int_attribs.size());
266 m_d_pa_user_real.resize(a_user_real_attribs.size());
267 m_d_user_int_attrib_parserexec.resize(a_user_int_attribs.size());
268 m_d_user_real_attrib_parserexec.resize(a_user_real_attribs.size());
269#endif
270
271 for (std::size_t ia = 0; ia < a_user_int_attribs.size(); ++ia) {
272 m_pa_user_int_pinned[ia] = a_soa.GetIntData(a_user_int_attribs[ia]).data() + old_size;
273 }
274 for (std::size_t ia = 0; ia < a_user_real_attribs.size(); ++ia) {
275 m_pa_user_real_pinned[ia] = a_soa.GetRealData(a_user_real_attribs[ia]).data() + old_size;
276 }
277
278#ifdef AMREX_USE_GPU
280 m_pa_user_int_pinned.end(), m_d_pa_user_int.begin());
282 m_pa_user_real_pinned.end(), m_d_pa_user_real.begin());
284 wrapper.m_user_int_attrib_parserexec_pinned.end(), m_d_user_int_attrib_parserexec.begin());
286 wrapper.m_user_real_attrib_parserexec_pinned.end(), m_d_user_real_attrib_parserexec.begin());
287#endif
288 }
289
290 int** getUserIntDataPtrs ();
292 [[nodiscard]] amrex::ParserExecutor<7> const* getUserIntParserExecData () const;
293 [[nodiscard]] amrex::ParserExecutor<7> const* getUserRealParserExecData () const;
294
297
298#ifdef AMREX_USE_GPU
299 // To avoid using managed memory, we first define pinned memory vector, initialize on cpu,
300 // and them memcpy to device from host
301 amrex::Gpu::DeviceVector<int*> m_d_pa_user_int;
303 amrex::Gpu::DeviceVector< amrex::ParserExecutor<7> > m_d_user_int_attrib_parserexec;
304 amrex::Gpu::DeviceVector< amrex::ParserExecutor<7> > m_d_user_real_attrib_parserexec;
305#endif
307};
308
309#ifdef WARPX_QED
311{
312 template <typename SoAType>
313 QEDHelper (SoAType& a_soa, std::size_t old_size,
314 bool a_has_quantum_sync, bool a_has_breit_wheeler,
315 const std::shared_ptr<QuantumSynchrotronEngine>& a_shr_p_qs_engine,
316 const std::shared_ptr<BreitWheelerEngine>& a_shr_p_bw_engine)
317 : has_quantum_sync(a_has_quantum_sync), has_breit_wheeler(a_has_breit_wheeler)
318 {
321 a_shr_p_qs_engine->build_optical_depth_functor();
322 p_optical_depth_QSR = a_soa.GetRealData("opticalDepthQSR").data() + old_size;
323 }
326 a_shr_p_bw_engine->build_optical_depth_functor();
327 p_optical_depth_BW = a_soa.GetRealData("opticalDepthBW").data() + old_size;
328 }
329 }
330
333
336
339};
340#endif
341
342#endif /*WARPX_ADDPLASMAUTILITIES_H_*/
#define AMREX_FORCE_INLINE
#define AMREX_GPU_HOST_DEVICE
#define AMREX_D_TERM(a, b, c)
#define AMREX_D_DECL(a, b, c)
bool find_overlap_flux(const amrex::RealBox &tile_realbox, const amrex::RealBox &part_realbox, const amrex::GpuArray< amrex::Real, 3 > &dx, const amrex::GpuArray< amrex::Real, 3 > &prob_lo, const PlasmaInjector &plasma_injector, amrex::RealBox &overlap_realbox, amrex::Box &overlap_box, amrex::IntVect &shifted)
Definition AddPlasmaUtilities.cpp:45
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real compute_scale_fac_area_plane(const amrex::GpuArray< amrex::Real, 3 > &dx, const amrex::Real num_ppc_real, const int flux_normal_axis)
Definition AddPlasmaUtilities.H:214
bool find_overlap(const amrex::RealBox &tile_realbox, const amrex::RealBox &part_realbox, const amrex::GpuArray< amrex::Real, 3 > &dx, const amrex::GpuArray< amrex::Real, 3 > &prob_lo, amrex::RealBox &overlap_realbox, amrex::Box &overlap_box, amrex::IntVect &shifted)
Definition AddPlasmaUtilities.cpp:12
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int compute_area_weights(const amrex::IntVect &iv, const int normal_axis)
Definition AddPlasmaUtilities.H:85
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real compute_scale_fac_volume(const amrex::GpuArray< amrex::Real, 3 > &dx, const amrex::Long pcount)
Definition AddPlasmaUtilities.H:74
Definition BreitWheelerEngineWrapper.H:78
Definition PlasmaInjector.H:39
Definition QuantumSyncEngineWrapper.H:76
amrex_real Real
amrex_particle_real ParticleReal
amrex_long Long
PODVector< T, PinnedArenaAllocator< T > > PinnedVector
PODVector< T, ArenaAllocator< T > > DeviceVector
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr HostToDevice hostToDevice
constexpr T powi(T x) noexcept
__host__ __device__ void ignore_unused(const Ts &...)
BoxND< 3 > Box
IntVectND< 3 > IntVect
Definition AddPlasmaUtilities.H:25
amrex::ParticleReal z
Definition AddPlasmaUtilities.H:26
AMREX_GPU_HOST_DEVICE PDim3(PDim3 const &)=default
amrex::ParticleReal x
Definition AddPlasmaUtilities.H:26
AMREX_GPU_HOST_DEVICE PDim3(PDim3 &&)=default
AMREX_GPU_HOST_DEVICE ~PDim3()=default
AMREX_GPU_HOST_DEVICE PDim3 & operator=(PDim3 &&)=default
amrex::ParticleReal y
Definition AddPlasmaUtilities.H:26
AMREX_GPU_HOST_DEVICE PDim3 & operator=(PDim3 const &)=default
AMREX_GPU_HOST_DEVICE PDim3(const amrex::XDim3 &a)
Definition AddPlasmaUtilities.H:30
amrex::ParserExecutor< 7 > const * getUserRealParserExecData() const
Definition AddPlasmaUtilities.cpp:154
amrex::ParticleReal ** getUserRealDataPtrs()
Definition AddPlasmaUtilities.cpp:138
PlasmaParserHelper(SoAType &a_soa, std::size_t old_size, const std::vector< std::string > &a_user_int_attribs, const std::vector< std::string > &a_user_real_attribs, const PlasmaParserWrapper &wrapper)
Definition AddPlasmaUtilities.H:256
const PlasmaParserWrapper * m_wrapper_ptr
Definition AddPlasmaUtilities.H:306
amrex::ParserExecutor< 7 > const * getUserIntParserExecData() const
Definition AddPlasmaUtilities.cpp:146
amrex::Gpu::PinnedVector< amrex::ParticleReal * > m_pa_user_real_pinned
Definition AddPlasmaUtilities.H:296
amrex::Gpu::PinnedVector< int * > m_pa_user_int_pinned
Definition AddPlasmaUtilities.H:295
int ** getUserIntDataPtrs()
Definition AddPlasmaUtilities.cpp:130
Definition AddPlasmaUtilities.H:243
amrex::Gpu::PinnedVector< amrex::ParserExecutor< 7 > > m_user_int_attrib_parserexec_pinned
Definition AddPlasmaUtilities.H:249
PlasmaParserWrapper(std::size_t a_num_user_int_attribs, std::size_t a_num_user_real_attribs, const amrex::Vector< std::unique_ptr< amrex::Parser > > &a_user_int_attrib_parser, const amrex::Vector< std::unique_ptr< amrex::Parser > > &a_user_real_attrib_parser)
Definition AddPlasmaUtilities.cpp:113
amrex::Gpu::PinnedVector< amrex::ParserExecutor< 7 > > m_user_real_attrib_parserexec_pinned
Definition AddPlasmaUtilities.H:250
QuantumSynchrotronGetOpticalDepth quantum_sync_get_opt
Definition AddPlasmaUtilities.H:337
QEDHelper(SoAType &a_soa, std::size_t old_size, bool a_has_quantum_sync, bool a_has_breit_wheeler, const std::shared_ptr< QuantumSynchrotronEngine > &a_shr_p_qs_engine, const std::shared_ptr< BreitWheelerEngine > &a_shr_p_bw_engine)
Definition AddPlasmaUtilities.H:313
amrex::ParticleReal * p_optical_depth_BW
Definition AddPlasmaUtilities.H:332
bool has_breit_wheeler
Definition AddPlasmaUtilities.H:335
bool has_quantum_sync
Definition AddPlasmaUtilities.H:334
amrex::ParticleReal * p_optical_depth_QSR
Definition AddPlasmaUtilities.H:331
BreitWheelerGetOpticalDepth breit_wheeler_get_opt
Definition AddPlasmaUtilities.H:338