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