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