WarpX
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 
11 #include "Particles/ShapeFactors.H"
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  */
26 int 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)
42 void 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 template <int depos_order>
68 void depositComponent (const GetParticlePosition<PIdx>& GetPosition,
69  const amrex::ParticleReal * const wp,
70  const amrex::ParticleReal * const uxp,
71  const amrex::ParticleReal * const uyp,
72  const amrex::ParticleReal * const uzp,
73  const int* ion_lev,
74  amrex::Array4<amrex::Real> const& j_buff,
75  amrex::IntVect const j_type,
76  const amrex::Real relative_time,
77  const amrex::XDim3 dinv,
78  const amrex::XDim3 xyzmin,
79  const amrex::Dim3 lo,
80  const amrex::Real q,
81  const int n_rz_azimuthal_modes,
82  const unsigned int ip,
83  const int zdir, const int NODE, const int CELL, const int dir)
84 {
85  using namespace amrex::literals;
86 
87 #if !defined(WARPX_DIM_RZ)
88  amrex::ignore_unused(n_rz_azimuthal_modes);
89 #endif
90 
91  // Whether ion_lev is a null pointer (do_ionization=0) or a real pointer
92  // (do_ionization=1)
93  const bool do_ionization = ion_lev;
94 
95  const amrex::Real invvol = dinv.x*dinv.y*dinv.z;
96 
97  const amrex::Real clightsq = 1.0_rt/PhysConst::c/PhysConst::c;
98 
99  // --- Get particle quantities
100  const amrex::Real gaminv = 1.0_rt/std::sqrt(1.0_rt + uxp[ip]*uxp[ip]*clightsq
101  + uyp[ip]*uyp[ip]*clightsq
102  + uzp[ip]*uzp[ip]*clightsq);
103  amrex::Real wq = q*wp[ip];
104  if (do_ionization){
105  wq *= ion_lev[ip];
106  }
107 
108  amrex::ParticleReal xp, yp, zp;
109  GetPosition(ip, xp, yp, zp);
110 
111  const amrex::Real vx = uxp[ip]*gaminv;
112  const amrex::Real vy = uyp[ip]*gaminv;
113  const amrex::Real vz = uzp[ip]*gaminv;
114  // pcurrent is the particle current in the deposited direction
115 #if defined(WARPX_DIM_RZ)
116  // In RZ, wqx is actually wqr, and wqy is wqtheta
117  // Convert to cylindrical at the mid point
118  const amrex::Real xpmid = xp + relative_time*vx;
119  const amrex::Real ypmid = yp + relative_time*vy;
120  const amrex::Real rpmid = std::sqrt(xpmid*xpmid + ypmid*ypmid);
121  amrex::Real costheta;
122  amrex::Real sintheta;
123  if (rpmid > 0._rt) {
124  costheta = xpmid/rpmid;
125  sintheta = ypmid/rpmid;
126  } else {
127  costheta = 1._rt;
128  sintheta = 0._rt;
129  }
130  const Complex xy0 = Complex{costheta, sintheta};
131  const amrex::Real wqx = wq*invvol*(+vx*costheta + vy*sintheta);
132  const amrex::Real wqy = wq*invvol*(-vx*sintheta + vy*costheta);
133 #else
134  const amrex::Real wqx = wq*invvol*vx;
135  const amrex::Real wqy = wq*invvol*vy;
136 #endif
137  const amrex::Real wqz = wq*invvol*vz;
138 
139  amrex::Real pcurrent = 0.0;
140  if (dir == 0) {
141  pcurrent = wqx;
142  } else if (dir == 1) {
143  pcurrent = wqy;
144  } else if (dir == 2) {
145  pcurrent = wqz;
146  }
147 
148  // --- Compute shape factors
149  Compute_shape_factor< depos_order > const compute_shape_factor;
150 #if defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ) || defined(WARPX_DIM_3D)
151 
152  // x direction
153  // Get particle position after 1/2 push back in position
154 #if defined(WARPX_DIM_RZ)
155  // Keep these double to avoid bug in single precision
156  const double xmid = (rpmid - xyzmin.x)*dinv.x;
157 #else
158  const double xmid = ((xp - xyzmin.x) + relative_time*vx)*dinv.x;
159 #endif
160  // j_j[xyz] leftmost grid point in x that the particle touches for the centering of each current
161  // sx_j[xyz] shape factor along x for the centering of each current
162  // There are only two possible centerings, node or cell centered, so at most only two shape factor
163  // arrays will be needed.
164  // Keep these double to avoid bug in single precision
165  double sx_node[depos_order + 1] = {0.};
166  double sx_cell[depos_order + 1] = {0.};
167  int j_node = 0;
168  int j_cell = 0;
169  if (j_type[0] == NODE) {
170  j_node = compute_shape_factor(sx_node, xmid);
171  }
172  if (j_type[0] == CELL) {
173  j_cell = compute_shape_factor(sx_cell, xmid - 0.5);
174  }
175 
176  amrex::Real sx_j[depos_order + 1] = {0._rt};
177  for (int ix=0; ix<=depos_order; ix++)
178  {
179  sx_j[ix] = ((j_type[0] == NODE) ? amrex::Real(sx_node[ix]) : amrex::Real(sx_cell[ix]));
180  }
181 
182  int const j_j = ((j_type[0] == NODE) ? j_node : j_cell);
183 #endif //AMREX_SPACEDIM >= 2
184 
185 #if defined(WARPX_DIM_3D)
186  // y direction
187  // Keep these double to avoid bug in single precision
188  const double ymid = ((yp - xyzmin.y) + relative_time*vy)*dinv.y;
189  double sy_node[depos_order + 1] = {0.};
190  double sy_cell[depos_order + 1] = {0.};
191  int k_node = 0;
192  int k_cell = 0;
193  if (j_type[1] == NODE) {
194  k_node = compute_shape_factor(sy_node, ymid);
195  }
196  if (j_type[1] == CELL) {
197  k_cell = compute_shape_factor(sy_cell, ymid - 0.5);
198  }
199  amrex::Real sy_j[depos_order + 1] = {0._rt};
200  for (int iy=0; iy<=depos_order; iy++)
201  {
202  sy_j[iy] = ((j_type[1] == NODE) ? amrex::Real(sy_node[iy]) : amrex::Real(sy_cell[iy]));
203  }
204  int const k_j = ((j_type[1] == NODE) ? k_node : k_cell);
205 #endif
206 
207  // z direction
208  // Keep these double to avoid bug in single precision
209  const double zmid = ((zp - xyzmin.z) + relative_time*vz)*dinv.z;
210  double sz_node[depos_order + 1] = {0.};
211  double sz_cell[depos_order + 1] = {0.};
212  int l_node = 0;
213  int l_cell = 0;
214  if (j_type[zdir] == NODE) {
215  l_node = compute_shape_factor(sz_node, zmid);
216  }
217  if (j_type[zdir] == CELL) {
218  l_cell = compute_shape_factor(sz_cell, zmid - 0.5);
219  }
220  amrex::Real sz_j[depos_order + 1] = {0._rt};
221  for (int iz=0; iz<=depos_order; iz++)
222  {
223  sz_j[iz] = ((j_type[zdir] == NODE) ? amrex::Real(sz_node[iz]) : amrex::Real(sz_cell[iz]));
224  }
225  int const l_j = ((j_type[zdir] == NODE) ? l_node : l_cell);
226 
227  // Deposit current into j_buff
228 #if defined(WARPX_DIM_1D_Z)
229  for (int iz=0; iz<=depos_order; iz++){
231  &j_buff(lo.x+l_j+iz, 0, 0, 0),
232  sz_j[iz]*pcurrent);
233  }
234 #endif
235 #if defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
236  for (int iz=0; iz<=depos_order; iz++){
237  for (int ix=0; ix<=depos_order; ix++){
239  &j_buff(lo.x+j_j+ix, lo.y+l_j+iz, 0, 0),
240  sx_j[ix]*sz_j[iz]*pcurrent);
241 #if defined(WARPX_DIM_RZ)
242  Complex xy = xy0; // Note that xy is equal to e^{i m theta}
243  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
244  // The factor 2 on the weighting comes from the normalization of the modes
245  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());
246  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());
247  xy = xy*xy0;
248  }
249 #endif
250  }
251  }
252 #elif defined(WARPX_DIM_3D)
253  for (int iz=0; iz<=depos_order; iz++){
254  for (int iy=0; iy<=depos_order; iy++){
255  for (int ix=0; ix<=depos_order; ix++){
257  &j_buff(lo.x+j_j+ix, lo.y+k_j+iy, lo.z+l_j+iz),
258  sx_j[ix]*sy_j[iy]*sz_j[iz]*pcurrent);
259  }
260  }
261  }
262 #endif
263 }
264 #endif
265 
266 #endif // WARPX_SHAREDDEPOSITIONUTILS_H_
#define AMREX_FORCE_INLINE
#define AMREX_GPU_HOST_DEVICE
AMREX_FORCE_INLINE int getMaxTboxAlongDim(int nCells, int tilesize)
Definition: SharedDepositionUtils.H:26
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
const int[]
i
Definition: check_interp_points_and_weights.py:174
Definition: ShapeFactors.H:29
AMREX_GPU_HOST_DEVICE constexpr AMREX_FORCE_INLINE T real() const noexcept
AMREX_GPU_HOST_DEVICE constexpr AMREX_FORCE_INLINE T imag() const noexcept