WarpX
Loading...
Searching...
No Matches
SharedDepositionUtils.H
Go to the documentation of this file.
1/* Copyright 2022 Noah Kaplan, Andrew Myers, Phil Miller
2 *
3 * This file is part of WarpX.
4 *
5 * License: BSD-3-Clause-LBNL
6 */
7#ifndef WARPX_SHAREDDEPOSITIONUTILS_H_
8#define WARPX_SHAREDDEPOSITIONUTILS_H_
9
13#include "Utils/WarpXConst.H"
14#ifdef WARPX_DIM_RZ
15# include "Utils/WarpX_Complex.H"
16#endif
17
18#include <AMReX.H>
19
20/*
21 * \brief gets the maximum width, height, or length of a tilebox. In number of cells.
22 * \param nCells : Number of cells in the direction to be considered
23 * \param tilesize : The 1D tilesize in the direction to be considered
24 */
26int getMaxTboxAlongDim (int nCells, int tilesize){
27 int maxTilesize = 0;
28 const int nTiles = nCells / tilesize;
29 const int remainder = nCells % tilesize;
30 maxTilesize = tilesize + int(std::ceil((amrex::Real) remainder / nTiles));
31 return maxTilesize;
32}
33
34/*
35 * \brief atomically add the values from the local deposition buffer back to the global array.
36 * \param bx : Box defining the index space of the local buffer
37 * \param global : The global array
38 * \param local : The local array
39 */
40#if defined(AMREX_USE_HIP) || defined(AMREX_USE_CUDA)
42void addLocalToGlobal (const amrex::Box& bx,
43 const amrex::Array4<amrex::Real>& global,
44 const amrex::Array4<amrex::Real>& local) noexcept
45{
46 using namespace amrex::literals;
47
48 const auto lo = amrex::lbound(bx);
49 const auto len = amrex::length(bx);
50 for (int icell = threadIdx.x; icell < bx.numPts(); icell += blockDim.x)
51 {
52 int k = icell / (len.x*len.y);
53 int j = (icell - k*(len.x*len.y)) / len.x;
54 int i = (icell - k*(len.x*len.y)) - j*len.x;
55 i += lo.x;
56 j += lo.y;
57 k += lo.z;
58 if (amrex::Math::abs(local(i, j, k)) > 0.0_rt) {
59 amrex::Gpu::Atomic::AddNoRet( &global(i, j, k), local(i, j, k));
60 }
61 }
62}
63#endif
64
65#if (defined(AMREX_USE_HIP) || defined(AMREX_USE_CUDA)) && \
66 !(defined(WARPX_DIM_RCYLINDER) || defined(WARPX_DIM_RSPHERE))
67template <int depos_order>
69void depositComponent (const GetParticlePosition<PIdx>& GetPosition,
70 const amrex::ParticleReal * const wp,
71 const amrex::ParticleReal * const uxp,
72 const amrex::ParticleReal * const uyp,
73 const amrex::ParticleReal * const uzp,
74 const int* ion_lev,
75 amrex::Array4<amrex::Real> const& j_buff,
76 amrex::IntVect const j_type,
77 const amrex::Real relative_time,
78 const amrex::XDim3 dinv,
79 const amrex::XDim3 xyzmin,
80 const amrex::Dim3 lo,
81 const amrex::Real q,
82 const int n_rz_azimuthal_modes,
83 const unsigned int ip,
84 const int zdir, const int NODE, const int CELL, const int dir)
85{
86 using namespace amrex::literals;
87
88#if !defined(WARPX_DIM_RZ)
89 amrex::ignore_unused(n_rz_azimuthal_modes);
90#endif
91
92 // Whether ion_lev is a null pointer (do_ionization=0) or a real pointer
93 // (do_ionization=1)
94 const bool do_ionization = ion_lev;
95
96 const amrex::Real invvol = dinv.x*dinv.y*dinv.z;
97
98 const amrex::Real clightsq = 1.0_rt/PhysConst::c/PhysConst::c;
99
100 // --- Get particle quantities
101 const amrex::Real gaminv = 1.0_rt/std::sqrt(1.0_rt + uxp[ip]*uxp[ip]*clightsq
102 + uyp[ip]*uyp[ip]*clightsq
103 + uzp[ip]*uzp[ip]*clightsq);
104 amrex::Real wq = q*wp[ip];
105 if (do_ionization){
106 wq *= ion_lev[ip];
107 }
108
109 amrex::ParticleReal xp, yp, zp;
110 GetPosition(ip, xp, yp, zp);
111
112 const amrex::Real vx = uxp[ip]*gaminv;
113 const amrex::Real vy = uyp[ip]*gaminv;
114 const amrex::Real vz = uzp[ip]*gaminv;
115 // pcurrent is the particle current in the deposited direction
116#if defined(WARPX_DIM_RZ)
117 // In RZ, wqx is actually wqr, and wqy is wqtheta
118 // Convert to cylindrical at the mid point
119 const amrex::Real xpmid = xp + relative_time*vx;
120 const amrex::Real ypmid = yp + relative_time*vy;
121 const amrex::Real rpmid = std::sqrt(xpmid*xpmid + ypmid*ypmid);
122 amrex::Real costheta;
123 amrex::Real sintheta;
124 if (rpmid > 0._rt) {
125 costheta = xpmid/rpmid;
126 sintheta = ypmid/rpmid;
127 } else {
128 costheta = 1._rt;
129 sintheta = 0._rt;
130 }
131 const Complex xy0 = Complex{costheta, sintheta};
132 const amrex::Real wqx = wq*invvol*(+vx*costheta + vy*sintheta);
133 const amrex::Real wqy = wq*invvol*(-vx*sintheta + vy*costheta);
134#else
135 const amrex::Real wqx = wq*invvol*vx;
136 const amrex::Real wqy = wq*invvol*vy;
137#endif
138 const amrex::Real wqz = wq*invvol*vz;
139
140 amrex::Real pcurrent = 0.0;
141 if (dir == 0) {
142 pcurrent = wqx;
143 } else if (dir == 1) {
144 pcurrent = wqy;
145 } else if (dir == 2) {
146 pcurrent = wqz;
147 }
148
149 // --- Compute shape factors
150 Compute_shape_factor< depos_order > const compute_shape_factor;
151#if defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ) || defined(WARPX_DIM_3D)
152
153 // x direction
154 // Get particle position after 1/2 push back in position
155#if defined(WARPX_DIM_RZ)
156 // Keep these double to avoid bug in single precision
157 const double xmid = (rpmid - xyzmin.x)*dinv.x;
158#else
159 const double xmid = ((xp - xyzmin.x) + relative_time*vx)*dinv.x;
160#endif
161 // j_j[xyz] leftmost grid point in x that the particle touches for the centering of each current
162 // sx_j[xyz] shape factor along x for the centering of each current
163 // There are only two possible centerings, node or cell centered, so at most only two shape factor
164 // arrays will be needed.
165 // Keep these double to avoid bug in single precision
166 double sx_node[depos_order + 1] = {0.};
167 double sx_cell[depos_order + 1] = {0.};
168 int j_node = 0;
169 int j_cell = 0;
170 if (j_type[0] == NODE) {
171 j_node = compute_shape_factor(sx_node, xmid);
172 }
173 if (j_type[0] == CELL) {
174 j_cell = compute_shape_factor(sx_cell, xmid - 0.5);
175 }
176
177 amrex::Real sx_j[depos_order + 1] = {0._rt};
178 for (int ix=0; ix<=depos_order; ix++)
179 {
180 sx_j[ix] = ((j_type[0] == NODE) ? amrex::Real(sx_node[ix]) : amrex::Real(sx_cell[ix]));
181 }
182
183 int const j_j = ((j_type[0] == NODE) ? j_node : j_cell);
184#endif //AMREX_SPACEDIM >= 2
185
186#if defined(WARPX_DIM_3D)
187 // y direction
188 // Keep these double to avoid bug in single precision
189 const double ymid = ((yp - xyzmin.y) + relative_time*vy)*dinv.y;
190 double sy_node[depos_order + 1] = {0.};
191 double sy_cell[depos_order + 1] = {0.};
192 int k_node = 0;
193 int k_cell = 0;
194 if (j_type[1] == NODE) {
195 k_node = compute_shape_factor(sy_node, ymid);
196 }
197 if (j_type[1] == CELL) {
198 k_cell = compute_shape_factor(sy_cell, ymid - 0.5);
199 }
200 amrex::Real sy_j[depos_order + 1] = {0._rt};
201 for (int iy=0; iy<=depos_order; iy++)
202 {
203 sy_j[iy] = ((j_type[1] == NODE) ? amrex::Real(sy_node[iy]) : amrex::Real(sy_cell[iy]));
204 }
205 int const k_j = ((j_type[1] == NODE) ? k_node : k_cell);
206#endif
207
208 // z direction
209 // Keep these double to avoid bug in single precision
210 const double zmid = ((zp - xyzmin.z) + relative_time*vz)*dinv.z;
211 double sz_node[depos_order + 1] = {0.};
212 double sz_cell[depos_order + 1] = {0.};
213 int l_node = 0;
214 int l_cell = 0;
215 if (j_type[zdir] == NODE) {
216 l_node = compute_shape_factor(sz_node, zmid);
217 }
218 if (j_type[zdir] == CELL) {
219 l_cell = compute_shape_factor(sz_cell, zmid - 0.5);
220 }
221 amrex::Real sz_j[depos_order + 1] = {0._rt};
222 for (int iz=0; iz<=depos_order; iz++)
223 {
224 sz_j[iz] = ((j_type[zdir] == NODE) ? amrex::Real(sz_node[iz]) : amrex::Real(sz_cell[iz]));
225 }
226 int const l_j = ((j_type[zdir] == NODE) ? l_node : l_cell);
227
228 // Deposit current into j_buff
229#if defined(WARPX_DIM_1D_Z)
230 for (int iz=0; iz<=depos_order; iz++){
232 &j_buff(lo.x+l_j+iz, 0, 0, 0),
233 sz_j[iz]*pcurrent);
234 }
235#endif
236#if defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
237 for (int iz=0; iz<=depos_order; iz++){
238 for (int ix=0; ix<=depos_order; ix++){
240 &j_buff(lo.x+j_j+ix, lo.y+l_j+iz, 0, 0),
241 sx_j[ix]*sz_j[iz]*pcurrent);
242#if defined(WARPX_DIM_RZ)
243 Complex xy = xy0; // Note that xy is equal to e^{i m theta}
244 for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
245 // The factor 2 on the weighting comes from the normalization of the modes
246 amrex::Gpu::Atomic::AddNoRet( &j_buff(lo.x+j_j+ix, lo.y+l_j+iz, 0, 2*imode-1), 2._rt*sx_j[ix]*sz_j[iz]*wqx*xy.real());
247 amrex::Gpu::Atomic::AddNoRet( &j_buff(lo.x+j_j+ix, lo.y+l_j+iz, 0, 2*imode ), 2._rt*sx_j[ix]*sz_j[iz]*wqx*xy.imag());
248 xy = xy*xy0;
249 }
250#endif
251 }
252 }
253#elif defined(WARPX_DIM_3D)
254 for (int iz=0; iz<=depos_order; iz++){
255 for (int iy=0; iy<=depos_order; iy++){
256 for (int ix=0; ix<=depos_order; ix++){
258 &j_buff(lo.x+j_j+ix, lo.y+k_j+iy, lo.z+l_j+iz),
259 sx_j[ix]*sy_j[iy]*sz_j[iz]*pcurrent);
260 }
261 }
262 }
263#endif
264}
265#endif
266
267#endif // WARPX_SHAREDDEPOSITIONUTILS_H_
#define AMREX_FORCE_INLINE
#define AMREX_GPU_HOST_DEVICE
@ vz
Definition RigidInjectedParticleContainer.H:27
AMREX_FORCE_INLINE int getMaxTboxAlongDim(int nCells, int tilesize)
Definition SharedDepositionUtils.H:26
amrex::GpuComplex< amrex::Real > Complex
Definition WarpX_Complex.H:22
NODE
constexpr auto c
vacuum speed of light [m/s]
Definition constant.H:149
__host__ __device__ AMREX_FORCE_INLINE void AddNoRet(T *sum, T value) noexcept
constexpr int iz
constexpr int iy
constexpr int ix
__host__ __device__ void ignore_unused(const Ts &...)
__host__ __device__ Dim3 length(Array4< T > const &a) noexcept
BoxND< 3 > Box
IntVectND< 3 > IntVect
__host__ __device__ Dim3 lbound(Array4< T > const &a) noexcept
Definition ShapeFactors.H:29
Functor that can be used to extract the positions of the macroparticles inside a ParallelFor kernel.
Definition GetAndSetPosition.H:75
__host__ __device__ constexpr T real() const noexcept
__host__ __device__ constexpr T imag() const noexcept