WarpX
CurrentDeposition.H
Go to the documentation of this file.
1 /* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
2  * Remi Lehe, Weiqun Zhang, Michael Rowan
3  *
4  * This file is part of WarpX.
5  *
6  * License: BSD-3-Clause-LBNL
7  */
8 #ifndef CURRENTDEPOSITION_H_
9 #define CURRENTDEPOSITION_H_
10 
13 #include "Particles/ShapeFactors.H"
15 #ifdef WARPX_DIM_RZ
16 # include "Utils/WarpX_Complex.H"
17 #endif
18 
19 #include <AMReX.H>
20 #include <AMReX_Arena.H>
21 #include <AMReX_Array4.H>
22 #include <AMReX_REAL.H>
23 
24 using namespace amrex::literals;
25 
52 template <int depos_order>
53 void doDepositionShapeN(const GetParticlePosition& GetPosition,
54  const amrex::ParticleReal * const wp,
55  const amrex::ParticleReal * const uxp,
56  const amrex::ParticleReal * const uyp,
57  const amrex::ParticleReal * const uzp,
58  const int * const ion_lev,
59  amrex::FArrayBox& jx_fab,
60  amrex::FArrayBox& jy_fab,
61  amrex::FArrayBox& jz_fab,
62  const long np_to_depose,
63  const amrex::Real relative_t,
64  const std::array<amrex::Real,3>& dx,
65  const std::array<amrex::Real,3>& xyzmin,
66  const amrex::Dim3 lo,
67  const amrex::Real q,
68  const int n_rz_azimuthal_modes,
69  amrex::Real* cost,
70  const long load_balance_costs_update_algo)
71 {
72 #if !defined(WARPX_DIM_RZ)
73  amrex::ignore_unused(n_rz_azimuthal_modes);
74 #endif
75 
76 #if !defined(AMREX_USE_GPU)
77  amrex::ignore_unused(cost, load_balance_costs_update_algo);
78 #endif
79 
80  // Whether ion_lev is a null pointer (do_ionization=0) or a real pointer
81  // (do_ionization=1)
82  const bool do_ionization = ion_lev;
83  const amrex::Real dxi = 1.0_rt/dx[0];
84  const amrex::Real dzi = 1.0_rt/dx[2];
85 #if (AMREX_SPACEDIM == 2)
86  const amrex::Real invvol = dxi*dzi;
87 #elif (defined WARPX_DIM_3D)
88  const amrex::Real dyi = 1.0_rt/dx[1];
89  const amrex::Real invvol = dxi*dyi*dzi;
90 #endif
91 
92  const amrex::Real xmin = xyzmin[0];
93 #if (defined WARPX_DIM_3D)
94  const amrex::Real ymin = xyzmin[1];
95 #endif
96  const amrex::Real zmin = xyzmin[2];
97 
98  const amrex::Real clightsq = 1.0_rt/PhysConst::c/PhysConst::c;
99 
100  amrex::Array4<amrex::Real> const& jx_arr = jx_fab.array();
101  amrex::Array4<amrex::Real> const& jy_arr = jy_fab.array();
102  amrex::Array4<amrex::Real> const& jz_arr = jz_fab.array();
103  amrex::IntVect const jx_type = jx_fab.box().type();
104  amrex::IntVect const jy_type = jy_fab.box().type();
105  amrex::IntVect const jz_type = jz_fab.box().type();
106 
107  constexpr int zdir = (AMREX_SPACEDIM - 1);
108  constexpr int NODE = amrex::IndexType::NODE;
109  constexpr int CELL = amrex::IndexType::CELL;
110 
111  // Loop over particles and deposit into jx_fab, jy_fab and jz_fab
112 #if defined(WARPX_USE_GPUCLOCK)
113  amrex::Real* cost_real = nullptr;
114  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
115  cost_real = (amrex::Real *) amrex::The_Managed_Arena()->alloc(sizeof(amrex::Real));
116  *cost_real = 0._rt;
117  }
118 #endif
119  amrex::ParallelFor(
120  np_to_depose,
121  [=] AMREX_GPU_DEVICE (long ip) {
122 #if defined(WARPX_USE_GPUCLOCK)
123  KernelTimer kernelTimer(cost && load_balance_costs_update_algo
125 #endif
126 
127  // --- Get particle quantities
128  const amrex::Real gaminv = 1.0_rt/std::sqrt(1.0_rt + uxp[ip]*uxp[ip]*clightsq
129  + uyp[ip]*uyp[ip]*clightsq
130  + uzp[ip]*uzp[ip]*clightsq);
131  amrex::Real wq = q*wp[ip];
132  if (do_ionization){
133  wq *= ion_lev[ip];
134  }
135 
136  amrex::ParticleReal xp, yp, zp;
137  GetPosition(ip, xp, yp, zp);
138 
139  const amrex::Real vx = uxp[ip]*gaminv;
140  const amrex::Real vy = uyp[ip]*gaminv;
141  const amrex::Real vz = uzp[ip]*gaminv;
142  // wqx, wqy wqz are particle current in each direction
143 #if (defined WARPX_DIM_RZ)
144  // In RZ, wqx is actually wqr, and wqy is wqtheta
145  // Convert to cylinderical at the mid point
146  const amrex::Real xpmid = xp + relative_t*vx;
147  const amrex::Real ypmid = yp + relative_t*vy;
148  const amrex::Real rpmid = std::sqrt(xpmid*xpmid + ypmid*ypmid);
149  amrex::Real costheta;
150  amrex::Real sintheta;
151  if (rpmid > 0._rt) {
152  costheta = xpmid/rpmid;
153  sintheta = ypmid/rpmid;
154  } else {
155  costheta = 1._rt;
156  sintheta = 0._rt;
157  }
158  const Complex xy0 = Complex{costheta, sintheta};
159  const amrex::Real wqx = wq*invvol*(+vx*costheta + vy*sintheta);
160  const amrex::Real wqy = wq*invvol*(-vx*sintheta + vy*costheta);
161 #else
162  const amrex::Real wqx = wq*invvol*vx;
163  const amrex::Real wqy = wq*invvol*vy;
164 #endif
165  const amrex::Real wqz = wq*invvol*vz;
166 
167  // --- Compute shape factors
168  // x direction
169  // Get particle position after 1/2 push back in position
170 #if (defined WARPX_DIM_RZ)
171  // Keep these double to avoid bug in single precision
172  const double xmid = (rpmid - xmin)*dxi;
173 #else
174  const double xmid = ((xp - xmin) + relative_t*vx)*dxi;
175 #endif
176  // j_j[xyz] leftmost grid point in x that the particle touches for the centering of each current
177  // sx_j[xyz] shape factor along x for the centering of each current
178  // There are only two possible centerings, node or cell centered, so at most only two shape factor
179  // arrays will be needed.
180  // Keep these double to avoid bug in single precision
181  double sx_node[depos_order + 1] = {0.};
182  double sx_cell[depos_order + 1] = {0.};
183  int j_node = 0;
184  int j_cell = 0;
185  Compute_shape_factor< depos_order > const compute_shape_factor;
186  if (jx_type[0] == NODE || jy_type[0] == NODE || jz_type[0] == NODE) {
187  j_node = compute_shape_factor(sx_node, xmid);
188  }
189  if (jx_type[0] == CELL || jy_type[0] == CELL || jz_type[0] == CELL) {
190  j_cell = compute_shape_factor(sx_cell, xmid - 0.5);
191  }
192 
193  amrex::Real sx_jx[depos_order + 1] = {0._rt};
194  amrex::Real sx_jy[depos_order + 1] = {0._rt};
195  amrex::Real sx_jz[depos_order + 1] = {0._rt};
196  for (int ix=0; ix<=depos_order; ix++)
197  {
198  sx_jx[ix] = ((jx_type[0] == NODE) ? amrex::Real(sx_node[ix]) : amrex::Real(sx_cell[ix]));
199  sx_jy[ix] = ((jy_type[0] == NODE) ? amrex::Real(sx_node[ix]) : amrex::Real(sx_cell[ix]));
200  sx_jz[ix] = ((jz_type[0] == NODE) ? amrex::Real(sx_node[ix]) : amrex::Real(sx_cell[ix]));
201  }
202 
203  int const j_jx = ((jx_type[0] == NODE) ? j_node : j_cell);
204  int const j_jy = ((jy_type[0] == NODE) ? j_node : j_cell);
205  int const j_jz = ((jz_type[0] == NODE) ? j_node : j_cell);
206 
207 #if (defined WARPX_DIM_3D)
208  // y direction
209  // Keep these double to avoid bug in single precision
210  const double ymid = ( (yp - ymin) + relative_t*vy )*dyi;
211  double sy_node[depos_order + 1] = {0.};
212  double sy_cell[depos_order + 1] = {0.};
213  int k_node = 0;
214  int k_cell = 0;
215  if (jx_type[1] == NODE || jy_type[1] == NODE || jz_type[1] == NODE) {
216  k_node = compute_shape_factor(sy_node, ymid);
217  }
218  if (jx_type[1] == CELL || jy_type[1] == CELL || jz_type[1] == CELL) {
219  k_cell = compute_shape_factor(sy_cell, ymid - 0.5);
220  }
221  amrex::Real sy_jx[depos_order + 1] = {0._rt};
222  amrex::Real sy_jy[depos_order + 1] = {0._rt};
223  amrex::Real sy_jz[depos_order + 1] = {0._rt};
224  for (int iy=0; iy<=depos_order; iy++)
225  {
226  sy_jx[iy] = ((jx_type[1] == NODE) ? amrex::Real(sy_node[iy]) : amrex::Real(sy_cell[iy]));
227  sy_jy[iy] = ((jy_type[1] == NODE) ? amrex::Real(sy_node[iy]) : amrex::Real(sy_cell[iy]));
228  sy_jz[iy] = ((jz_type[1] == NODE) ? amrex::Real(sy_node[iy]) : amrex::Real(sy_cell[iy]));
229  }
230  int const k_jx = ((jx_type[1] == NODE) ? k_node : k_cell);
231  int const k_jy = ((jy_type[1] == NODE) ? k_node : k_cell);
232  int const k_jz = ((jz_type[1] == NODE) ? k_node : k_cell);
233 #endif
234 
235  // z direction
236  // Keep these double to avoid bug in single precision
237  const double zmid = ((zp - zmin) + relative_t*vz)*dzi;
238  double sz_node[depos_order + 1] = {0.};
239  double sz_cell[depos_order + 1] = {0.};
240  int l_node = 0;
241  int l_cell = 0;
242  if (jx_type[zdir] == NODE || jy_type[zdir] == NODE || jz_type[zdir] == NODE) {
243  l_node = compute_shape_factor(sz_node, zmid);
244  }
245  if (jx_type[zdir] == CELL || jy_type[zdir] == CELL || jz_type[zdir] == CELL) {
246  l_cell = compute_shape_factor(sz_cell, zmid - 0.5);
247  }
248  amrex::Real sz_jx[depos_order + 1] = {0._rt};
249  amrex::Real sz_jy[depos_order + 1] = {0._rt};
250  amrex::Real sz_jz[depos_order + 1] = {0._rt};
251  for (int iz=0; iz<=depos_order; iz++)
252  {
253  sz_jx[iz] = ((jx_type[zdir] == NODE) ? amrex::Real(sz_node[iz]) : amrex::Real(sz_cell[iz]));
254  sz_jy[iz] = ((jy_type[zdir] == NODE) ? amrex::Real(sz_node[iz]) : amrex::Real(sz_cell[iz]));
255  sz_jz[iz] = ((jz_type[zdir] == NODE) ? amrex::Real(sz_node[iz]) : amrex::Real(sz_cell[iz]));
256  }
257  int const l_jx = ((jx_type[zdir] == NODE) ? l_node : l_cell);
258  int const l_jy = ((jy_type[zdir] == NODE) ? l_node : l_cell);
259  int const l_jz = ((jz_type[zdir] == NODE) ? l_node : l_cell);
260 
261  // Deposit current into jx_arr, jy_arr and jz_arr
262 #if (defined WARPX_DIM_XZ) || (defined WARPX_DIM_RZ)
263  for (int iz=0; iz<=depos_order; iz++){
264  for (int ix=0; ix<=depos_order; ix++){
265  amrex::Gpu::Atomic::AddNoRet(
266  &jx_arr(lo.x+j_jx+ix, lo.y+l_jx+iz, 0, 0),
267  sx_jx[ix]*sz_jx[iz]*wqx);
268  amrex::Gpu::Atomic::AddNoRet(
269  &jy_arr(lo.x+j_jy+ix, lo.y+l_jy+iz, 0, 0),
270  sx_jy[ix]*sz_jy[iz]*wqy);
271  amrex::Gpu::Atomic::AddNoRet(
272  &jz_arr(lo.x+j_jz+ix, lo.y+l_jz+iz, 0, 0),
273  sx_jz[ix]*sz_jz[iz]*wqz);
274 #if (defined WARPX_DIM_RZ)
275  Complex xy = xy0; // Note that xy is equal to e^{i m theta}
276  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
277  // The factor 2 on the weighting comes from the normalization of the modes
278  amrex::Gpu::Atomic::AddNoRet( &jx_arr(lo.x+j_jx+ix, lo.y+l_jx+iz, 0, 2*imode-1), 2._rt*sx_jx[ix]*sz_jx[iz]*wqx*xy.real());
279  amrex::Gpu::Atomic::AddNoRet( &jx_arr(lo.x+j_jx+ix, lo.y+l_jx+iz, 0, 2*imode ), 2._rt*sx_jx[ix]*sz_jx[iz]*wqx*xy.imag());
280  amrex::Gpu::Atomic::AddNoRet( &jy_arr(lo.x+j_jy+ix, lo.y+l_jy+iz, 0, 2*imode-1), 2._rt*sx_jy[ix]*sz_jy[iz]*wqy*xy.real());
281  amrex::Gpu::Atomic::AddNoRet( &jy_arr(lo.x+j_jy+ix, lo.y+l_jy+iz, 0, 2*imode ), 2._rt*sx_jy[ix]*sz_jy[iz]*wqy*xy.imag());
282  amrex::Gpu::Atomic::AddNoRet( &jz_arr(lo.x+j_jz+ix, lo.y+l_jz+iz, 0, 2*imode-1), 2._rt*sx_jz[ix]*sz_jz[iz]*wqz*xy.real());
283  amrex::Gpu::Atomic::AddNoRet( &jz_arr(lo.x+j_jz+ix, lo.y+l_jz+iz, 0, 2*imode ), 2._rt*sx_jz[ix]*sz_jz[iz]*wqz*xy.imag());
284  xy = xy*xy0;
285  }
286 #endif
287  }
288  }
289 #elif (defined WARPX_DIM_3D)
290  for (int iz=0; iz<=depos_order; iz++){
291  for (int iy=0; iy<=depos_order; iy++){
292  for (int ix=0; ix<=depos_order; ix++){
293  amrex::Gpu::Atomic::AddNoRet(
294  &jx_arr(lo.x+j_jx+ix, lo.y+k_jx+iy, lo.z+l_jx+iz),
295  sx_jx[ix]*sy_jx[iy]*sz_jx[iz]*wqx);
296  amrex::Gpu::Atomic::AddNoRet(
297  &jy_arr(lo.x+j_jy+ix, lo.y+k_jy+iy, lo.z+l_jy+iz),
298  sx_jy[ix]*sy_jy[iy]*sz_jy[iz]*wqy);
299  amrex::Gpu::Atomic::AddNoRet(
300  &jz_arr(lo.x+j_jz+ix, lo.y+k_jz+iy, lo.z+l_jz+iz),
301  sx_jz[ix]*sy_jz[iy]*sz_jz[iz]*wqz);
302  }
303  }
304  }
305 #endif
306  }
307  );
308 #if defined(WARPX_USE_GPUCLOCK)
309  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
310  amrex::Gpu::streamSynchronize();
311  *cost += *cost_real;
312  amrex::The_Managed_Arena()->free(cost_real);
313  }
314 #endif
315 }
316 
340 template <int depos_order>
342  const amrex::ParticleReal * const wp,
343  const amrex::ParticleReal * const uxp,
344  const amrex::ParticleReal * const uyp,
345  const amrex::ParticleReal * const uzp,
346  const int * const ion_lev,
347  const amrex::Array4<amrex::Real>& Jx_arr,
348  const amrex::Array4<amrex::Real>& Jy_arr,
349  const amrex::Array4<amrex::Real>& Jz_arr,
350  const long np_to_depose,
351  const amrex::Real dt,
352  const std::array<amrex::Real,3>& dx,
353  const std::array<amrex::Real, 3> xyzmin,
354  const amrex::Dim3 lo,
355  const amrex::Real q,
356  const int n_rz_azimuthal_modes,
357  amrex::Real * const cost,
358  const long load_balance_costs_update_algo)
359 {
360  using namespace amrex;
361 #if !defined(WARPX_DIM_RZ)
362  ignore_unused(n_rz_azimuthal_modes);
363 #endif
364 
365 #if !defined(AMREX_USE_GPU)
366  amrex::ignore_unused(cost, load_balance_costs_update_algo);
367 #endif
368 
369  // Whether ion_lev is a null pointer (do_ionization=0) or a real pointer
370  // (do_ionization=1)
371  bool const do_ionization = ion_lev;
372  Real const dxi = 1.0_rt / dx[0];
373 #if !(defined WARPX_DIM_RZ)
374  Real const dtsdx0 = dt*dxi;
375 #endif
376  Real const xmin = xyzmin[0];
377 #if (defined WARPX_DIM_3D)
378  Real const dyi = 1.0_rt / dx[1];
379  Real const dtsdy0 = dt*dyi;
380  Real const ymin = xyzmin[1];
381 #endif
382  Real const dzi = 1.0_rt / dx[2];
383  Real const dtsdz0 = dt*dzi;
384  Real const zmin = xyzmin[2];
385 
386 #if (defined WARPX_DIM_3D)
387  Real const invdtdx = 1.0_rt / (dt*dx[1]*dx[2]);
388  Real const invdtdy = 1.0_rt / (dt*dx[0]*dx[2]);
389  Real const invdtdz = 1.0_rt / (dt*dx[0]*dx[1]);
390 #elif (defined WARPX_DIM_XZ) || (defined WARPX_DIM_RZ)
391  Real const invdtdx = 1.0_rt / (dt*dx[2]);
392  Real const invdtdz = 1.0_rt / (dt*dx[0]);
393  Real const invvol = 1.0_rt / (dx[0]*dx[2]);
394 #endif
395 
396 #if (defined WARPX_DIM_RZ)
397  Complex const I = Complex{0._rt, 1._rt};
398 #endif
399 
400  Real const clightsq = 1.0_rt / ( PhysConst::c * PhysConst::c );
401 
402  // Loop over particles and deposit into Jx_arr, Jy_arr and Jz_arr
403 #if defined(WARPX_USE_GPUCLOCK)
404  amrex::Real* cost_real = nullptr;
405  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
406  cost_real = (amrex::Real *) amrex::The_Managed_Arena()->alloc(sizeof(amrex::Real));
407  *cost_real = 0._rt;
408  }
409 #endif
410  amrex::ParallelFor(
411  np_to_depose,
412  [=] AMREX_GPU_DEVICE (long const ip) {
413 #if defined(WARPX_USE_GPUCLOCK)
414  KernelTimer kernelTimer(cost && load_balance_costs_update_algo
416 #endif
417 
418  // --- Get particle quantities
419  Real const gaminv = 1.0_rt/std::sqrt(1.0_rt + uxp[ip]*uxp[ip]*clightsq
420  + uyp[ip]*uyp[ip]*clightsq
421  + uzp[ip]*uzp[ip]*clightsq);
422 
423  // wqx, wqy wqz are particle current in each direction
424  Real wq = q*wp[ip];
425  if (do_ionization){
426  wq *= ion_lev[ip];
427  }
428 
429  ParticleReal xp, yp, zp;
430  GetPosition(ip, xp, yp, zp);
431 
432  Real const wqx = wq*invdtdx;
433 #if (defined WARPX_DIM_3D)
434  Real const wqy = wq*invdtdy;
435 #endif
436  Real const wqz = wq*invdtdz;
437 
438  // computes current and old position in grid units
439 #if (defined WARPX_DIM_RZ)
440  Real const xp_mid = xp - 0.5_rt * dt*uxp[ip]*gaminv;
441  Real const yp_mid = yp - 0.5_rt * dt*uyp[ip]*gaminv;
442  Real const xp_old = xp - dt*uxp[ip]*gaminv;
443  Real const yp_old = yp - dt*uyp[ip]*gaminv;
444  Real const rp_new = std::sqrt(xp*xp
445  + yp*yp);
446  Real const rp_mid = std::sqrt(xp_mid*xp_mid + yp_mid*yp_mid);
447  Real const rp_old = std::sqrt(xp_old*xp_old + yp_old*yp_old);
448  Real costheta_new, sintheta_new;
449  if (rp_new > 0._rt) {
450  costheta_new = xp/rp_new;
451  sintheta_new = yp/rp_new;
452  } else {
453  costheta_new = 1._rt;
454  sintheta_new = 0._rt;
455  }
456  amrex::Real costheta_mid, sintheta_mid;
457  if (rp_mid > 0._rt) {
458  costheta_mid = xp_mid/rp_mid;
459  sintheta_mid = yp_mid/rp_mid;
460  } else {
461  costheta_mid = 1._rt;
462  sintheta_mid = 0._rt;
463  }
464  amrex::Real costheta_old, sintheta_old;
465  if (rp_old > 0._rt) {
466  costheta_old = xp_old/rp_old;
467  sintheta_old = yp_old/rp_old;
468  } else {
469  costheta_old = 1._rt;
470  sintheta_old = 0._rt;
471  }
472  const Complex xy_new0 = Complex{costheta_new, sintheta_new};
473  const Complex xy_mid0 = Complex{costheta_mid, sintheta_mid};
474  const Complex xy_old0 = Complex{costheta_old, sintheta_old};
475  // Keep these double to avoid bug in single precision
476  double const x_new = (rp_new - xmin)*dxi;
477  double const x_old = (rp_old - xmin)*dxi;
478 #else
479  // Keep these double to avoid bug in single precision
480  double const x_new = (xp - xmin)*dxi;
481  double const x_old = x_new - dtsdx0*uxp[ip]*gaminv;
482 #endif
483 #if (defined WARPX_DIM_3D)
484  // Keep these double to avoid bug in single precision
485  double const y_new = (yp - ymin)*dyi;
486  double const y_old = y_new - dtsdy0*uyp[ip]*gaminv;
487 #endif
488  // Keep these double to avoid bug in single precision
489  double const z_new = (zp - zmin)*dzi;
490  double const z_old = z_new - dtsdz0*uzp[ip]*gaminv;
491 
492 #if (defined WARPX_DIM_RZ)
493  Real const vy = (-uxp[ip]*sintheta_mid + uyp[ip]*costheta_mid)*gaminv;
494 #elif (defined WARPX_DIM_XZ)
495  Real const vy = uyp[ip]*gaminv;
496 #endif
497 
498  // Shape factor arrays
499  // Note that there are extra values above and below
500  // to possibly hold the factor for the old particle
501  // which can be at a different grid location.
502  // Keep these double to avoid bug in single precision
503  double sx_new[depos_order + 3] = {0.};
504  double sx_old[depos_order + 3] = {0.};
505 #if (defined WARPX_DIM_3D)
506  // Keep these double to avoid bug in single precision
507  double sy_new[depos_order + 3] = {0.};
508  double sy_old[depos_order + 3] = {0.};
509 #endif
510  // Keep these double to avoid bug in single precision
511  double sz_new[depos_order + 3] = {0.};
512  double sz_old[depos_order + 3] = {0.};
513 
514  // --- Compute shape factors
515  // Compute shape factors for position as they are now and at old positions
516  // [ijk]_new: leftmost grid point that the particle touches
517  Compute_shape_factor< depos_order > compute_shape_factor;
518  Compute_shifted_shape_factor< depos_order > compute_shifted_shape_factor;
519 
520  const int i_new = compute_shape_factor(sx_new+1, x_new);
521  const int i_old = compute_shifted_shape_factor(sx_old, x_old, i_new);
522 #if (defined WARPX_DIM_3D)
523  const int j_new = compute_shape_factor(sy_new+1, y_new);
524  const int j_old = compute_shifted_shape_factor(sy_old, y_old, j_new);
525 #endif
526  const int k_new = compute_shape_factor(sz_new+1, z_new);
527  const int k_old = compute_shifted_shape_factor(sz_old, z_old, k_new);
528 
529  // computes min/max positions of current contributions
530  int dil = 1, diu = 1;
531  if (i_old < i_new) dil = 0;
532  if (i_old > i_new) diu = 0;
533 #if (defined WARPX_DIM_3D)
534  int djl = 1, dju = 1;
535  if (j_old < j_new) djl = 0;
536  if (j_old > j_new) dju = 0;
537 #endif
538  int dkl = 1, dku = 1;
539  if (k_old < k_new) dkl = 0;
540  if (k_old > k_new) dku = 0;
541 
542 #if (defined WARPX_DIM_3D)
543 
544  for (int k=dkl; k<=depos_order+2-dku; k++) {
545  for (int j=djl; j<=depos_order+2-dju; j++) {
546  amrex::Real sdxi = 0._rt;
547  for (int i=dil; i<=depos_order+1-diu; i++) {
548  sdxi += wqx*(sx_old[i] - sx_new[i])*((sy_new[j] + 0.5_rt*(sy_old[j] - sy_new[j]))*sz_new[k] +
549  (0.5_rt*sy_new[j] + 1._rt/3._rt*(sy_old[j] - sy_new[j]))*(sz_old[k] - sz_new[k]));
550  amrex::Gpu::Atomic::AddNoRet( &Jx_arr(lo.x+i_new-1+i, lo.y+j_new-1+j, lo.z+k_new-1+k), sdxi);
551  }
552  }
553  }
554  for (int k=dkl; k<=depos_order+2-dku; k++) {
555  for (int i=dil; i<=depos_order+2-diu; i++) {
556  amrex::Real sdyj = 0._rt;
557  for (int j=djl; j<=depos_order+1-dju; j++) {
558  sdyj += wqy*(sy_old[j] - sy_new[j])*((sz_new[k] + 0.5_rt*(sz_old[k] - sz_new[k]))*sx_new[i] +
559  (0.5_rt*sz_new[k] + 1._rt/3._rt*(sz_old[k] - sz_new[k]))*(sx_old[i] - sx_new[i]));
560  amrex::Gpu::Atomic::AddNoRet( &Jy_arr(lo.x+i_new-1+i, lo.y+j_new-1+j, lo.z+k_new-1+k), sdyj);
561  }
562  }
563  }
564  for (int j=djl; j<=depos_order+2-dju; j++) {
565  for (int i=dil; i<=depos_order+2-diu; i++) {
566  amrex::Real sdzk = 0._rt;
567  for (int k=dkl; k<=depos_order+1-dku; k++) {
568  sdzk += wqz*(sz_old[k] - sz_new[k])*((sx_new[i] + 0.5_rt*(sx_old[i] - sx_new[i]))*sy_new[j] +
569  (0.5_rt*sx_new[i] + 1._rt/3._rt*(sx_old[i] - sx_new[i]))*(sy_old[j] - sy_new[j]));
570  amrex::Gpu::Atomic::AddNoRet( &Jz_arr(lo.x+i_new-1+i, lo.y+j_new-1+j, lo.z+k_new-1+k), sdzk);
571  }
572  }
573  }
574 
575 #elif (defined WARPX_DIM_XZ) || (defined WARPX_DIM_RZ)
576 
577  for (int k=dkl; k<=depos_order+2-dku; k++) {
578  amrex::Real sdxi = 0._rt;
579  for (int i=dil; i<=depos_order+1-diu; i++) {
580  sdxi += wqx*(sx_old[i] - sx_new[i])*(sz_new[k] + 0.5_rt*(sz_old[k] - sz_new[k]));
581  amrex::Gpu::Atomic::AddNoRet( &Jx_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 0), sdxi);
582 #if (defined WARPX_DIM_RZ)
583  Complex xy_mid = xy_mid0; // Throughout the following loop, xy_mid takes the value e^{i m theta}
584  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
585  // The factor 2 comes from the normalization of the modes
586  const Complex djr_cmplx = 2._rt *sdxi*xy_mid;
587  amrex::Gpu::Atomic::AddNoRet( &Jx_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode-1), djr_cmplx.real());
588  amrex::Gpu::Atomic::AddNoRet( &Jx_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode), djr_cmplx.imag());
589  xy_mid = xy_mid*xy_mid0;
590  }
591 #endif
592  }
593  }
594  for (int k=dkl; k<=depos_order+2-dku; k++) {
595  for (int i=dil; i<=depos_order+2-diu; i++) {
596  Real const sdyj = wq*vy*invvol*((sz_new[k] + 0.5_rt * (sz_old[k] - sz_new[k]))*sx_new[i] +
597  (0.5_rt * sz_new[k] + 1._rt / 3._rt *(sz_old[k] - sz_new[k]))*(sx_old[i] - sx_new[i]));
598  amrex::Gpu::Atomic::AddNoRet( &Jy_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 0), sdyj);
599 #if (defined WARPX_DIM_RZ)
600  Complex xy_new = xy_new0;
601  Complex xy_mid = xy_mid0;
602  Complex xy_old = xy_old0;
603  // Throughout the following loop, xy_ takes the value e^{i m theta_}
604  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
605  // The factor 2 comes from the normalization of the modes
606  // The minus sign comes from the different convention with respect to Davidson et al.
607  const Complex djt_cmplx = -2._rt * I*(i_new-1 + i + xmin*dxi)*wq*invdtdx/(amrex::Real)imode
608  *(Complex(sx_new[i]*sz_new[k], 0._rt)*(xy_new - xy_mid)
609  + Complex(sx_old[i]*sz_old[k], 0._rt)*(xy_mid - xy_old));
610  amrex::Gpu::Atomic::AddNoRet( &Jy_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode-1), djt_cmplx.real());
611  amrex::Gpu::Atomic::AddNoRet( &Jy_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode), djt_cmplx.imag());
612  xy_new = xy_new*xy_new0;
613  xy_mid = xy_mid*xy_mid0;
614  xy_old = xy_old*xy_old0;
615  }
616 #endif
617  }
618  }
619  for (int i=dil; i<=depos_order+2-diu; i++) {
620  Real sdzk = 0._rt;
621  for (int k=dkl; k<=depos_order+1-dku; k++) {
622  sdzk += wqz*(sz_old[k] - sz_new[k])*(sx_new[i] + 0.5_rt * (sx_old[i] - sx_new[i]));
623  amrex::Gpu::Atomic::AddNoRet( &Jz_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 0), sdzk);
624 #if (defined WARPX_DIM_RZ)
625  Complex xy_mid = xy_mid0; // Throughout the following loop, xy_mid takes the value e^{i m theta}
626  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
627  // The factor 2 comes from the normalization of the modes
628  const Complex djz_cmplx = 2._rt * sdzk * xy_mid;
629  amrex::Gpu::Atomic::AddNoRet( &Jz_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode-1), djz_cmplx.real());
630  amrex::Gpu::Atomic::AddNoRet( &Jz_arr(lo.x+i_new-1+i, lo.y+k_new-1+k, 0, 2*imode), djz_cmplx.imag());
631  xy_mid = xy_mid*xy_mid0;
632  }
633 #endif
634  }
635  }
636 #endif
637  }
638  );
639 #if defined(WARPX_USE_GPUCLOCK)
640  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
641  amrex::Gpu::streamSynchronize();
642  *cost += *cost_real;
643  amrex::The_Managed_Arena()->free(cost_real);
644  }
645 #endif
646 }
647 
676 template <int depos_order>
678  const amrex::ParticleReal* const wp,
679  const amrex::ParticleReal* const uxp,
680  const amrex::ParticleReal* const uyp,
681  const amrex::ParticleReal* const uzp,
682  const int* const ion_lev,
683  amrex::FArrayBox& jx_fab,
684  amrex::FArrayBox& jy_fab,
685  amrex::FArrayBox& jz_fab,
686  const long np_to_depose,
687  const amrex::Real dt,
688  const std::array<amrex::Real,3>& dx,
689  const std::array<amrex::Real,3>& xyzmin,
690  const amrex::Dim3 lo,
691  const amrex::Real q,
692  const int n_rz_azimuthal_modes,
693  amrex::Real* cost,
694  const long load_balance_costs_update_algo)
695 {
696 #if (defined WARPX_DIM_RZ)
697  amrex::ignore_unused(GetPosition,
698  wp, uxp, uyp, uzp, ion_lev, jx_fab, jy_fab, jz_fab,
699  np_to_depose, dt, dx, xyzmin, lo, q, n_rz_azimuthal_modes);
700  amrex::Abort("Vay deposition not implemented in RZ geometry");
701 #endif
702 
703 #if !defined(AMREX_USE_GPU)
704  amrex::ignore_unused(cost, load_balance_costs_update_algo);
705 #endif
706 
707 #if !(defined WARPX_DIM_RZ)
708  amrex::ignore_unused(n_rz_azimuthal_modes);
709 
710  // If ion_lev is a null pointer, then do_ionization=0, else do_ionization=1
711  const bool do_ionization = ion_lev;
712 
713  // Inverse cell volume in each direction
714  const amrex::Real dxi = 1._rt / dx[0];
715  const amrex::Real dzi = 1._rt / dx[2];
716 #if (defined WARPX_DIM_3D)
717  const amrex::Real dyi = 1._rt / dx[1];
718 #endif
719 
720  // Inverse of time step
721  const amrex::Real invdt = 1._rt / dt;
722 
723  // Total inverse cell volume
724 #if (defined WARPX_DIM_XZ)
725  const amrex::Real invvol = dxi * dzi;
726 #elif (defined WARPX_DIM_3D)
727  const amrex::Real invvol = dxi * dyi * dzi;
728 #endif
729 
730  // Lower bound of physical domain in each direction
731  const amrex::Real xmin = xyzmin[0];
732  const amrex::Real zmin = xyzmin[2];
733 #if (defined WARPX_DIM_3D)
734  const amrex::Real ymin = xyzmin[1];
735 #endif
736 
737  // Auxiliary constants
738 #if (defined WARPX_DIM_3D)
739  const amrex::Real onethird = 1._rt / 3._rt;
740  const amrex::Real onesixth = 1._rt / 6._rt;
741 #endif
742 
743  // Inverse of light speed squared
744  const amrex::Real invcsq = 1._rt / (PhysConst::c * PhysConst::c);
745 
746  // Arrays where D will be stored
747  amrex::Array4<amrex::Real> const& jx_arr = jx_fab.array();
748  amrex::Array4<amrex::Real> const& jy_arr = jy_fab.array();
749  amrex::Array4<amrex::Real> const& jz_arr = jz_fab.array();
750 
751  // Loop over particles and deposit (Dx,Dy,Dz) into jx_fab, jy_fab and jz_fab
752 #if defined(WARPX_USE_GPUCLOCK)
753  amrex::Real* cost_real = nullptr;
754  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
755  cost_real = (amrex::Real *) amrex::The_Managed_Arena()->alloc(sizeof(amrex::Real));
756  *cost_real = 0._rt;
757  }
758 #endif
759  amrex::ParallelFor(np_to_depose, [=] AMREX_GPU_DEVICE (long ip)
760  {
761 #if defined(WARPX_USE_GPUCLOCK)
762  KernelTimer kernelTimer(cost && load_balance_costs_update_algo
764 #endif
765 
766  // Inverse of Lorentz factor gamma
767  const amrex::Real invgam = 1._rt / std::sqrt(1._rt + uxp[ip] * uxp[ip] * invcsq
768  + uyp[ip] * uyp[ip] * invcsq
769  + uzp[ip] * uzp[ip] * invcsq);
770  // Product of particle charges and weights
771  amrex::Real wq = q * wp[ip];
772  if (do_ionization) wq *= ion_lev[ip];
773 
774  // Current particle positions (in physical units)
775  amrex::ParticleReal xp, yp, zp;
776  GetPosition(ip, xp, yp, zp);
777 
778  // Particle velocities
779  const amrex::Real vx = uxp[ip] * invgam;
780  const amrex::Real vy = uyp[ip] * invgam;
781  const amrex::Real vz = uzp[ip] * invgam;
782 
783  // Particle current densities
784 #if (defined WARPX_DIM_XZ)
785  const amrex::Real wqy = wq * vy * invvol;
786 #endif
787 
788  // Current and old particle positions in grid units
789  // Keep these double to avoid bug in single precision.
790  double const x_new = (xp - xmin) * dxi;
791  double const x_old = x_new - vx * dt * dxi;
792 #if (defined WARPX_DIM_3D)
793  // Keep these double to avoid bug in single precision.
794  double const y_new = (yp - ymin) * dyi;
795  double const y_old = y_new - vy * dt * dyi;
796 #endif
797  // Keep these double to avoid bug in single precision.
798  double const z_new = (zp - zmin) * dzi;
799  double const z_old = z_new - vz * dt * dzi;
800 
801  // Shape factor arrays for current and old positions (nodal)
802  // Keep these double to avoid bug in single precision.
803  double sx_new[depos_order+1] = {0.};
804  double sx_old[depos_order+1] = {0.};
805 #if (defined WARPX_DIM_3D)
806  // Keep these double to avoid bug in single precision.
807  double sy_new[depos_order+1] = {0.};
808  double sy_old[depos_order+1] = {0.};
809 #endif
810  // Keep these double to avoid bug in single precision.
811  double sz_new[depos_order+1] = {0.};
812  double sz_old[depos_order+1] = {0.};
813 
814  // Compute shape factors for current positions
815 
816  // i_new leftmost grid point in x that the particle touches
817  // sx_new shape factor along x for the centering of each current
818  Compute_shape_factor< depos_order > const compute_shape_factor;
819  const int i_new = compute_shape_factor(sx_new, x_new);
820 #if (defined WARPX_DIM_3D)
821  // j_new leftmost grid point in y that the particle touches
822  // sy_new shape factor along y for the centering of each current
823  const int j_new = compute_shape_factor(sy_new, y_new);
824 #endif
825  // k_new leftmost grid point in z that the particle touches
826  // sz_new shape factor along z for the centering of each current
827  const int k_new = compute_shape_factor(sz_new, z_new);
828 
829  // Compute shape factors for old positions
830 
831  // i_old leftmost grid point in x that the particle touches
832  // sx_old shape factor along x for the centering of each current
833  const int i_old = compute_shape_factor(sx_old, x_old);
834 #if (defined WARPX_DIM_3D)
835  // j_old leftmost grid point in y that the particle touches
836  // sy_old shape factor along y for the centering of each current
837  const int j_old = compute_shape_factor(sy_old, y_old);
838 #endif
839  // k_old leftmost grid point in z that the particle touches
840  // sz_old shape factor along z for the centering of each current
841  const int k_old = compute_shape_factor(sz_old, z_old);
842 
843  // Deposit current into jx_arr, jy_arr and jz_arr
844 #if (defined WARPX_DIM_XZ)
845 
846  for (int k=0; k<=depos_order; k++) {
847  for (int i=0; i<=depos_order; i++) {
848 
849  // Re-casting sx_new and sz_new from double to amrex::Real so that
850  // Atomic::Add has consistent types in its argument
851  amrex::Real const sxn_szn = sx_new[i] * sz_new[k];
852  amrex::Real const sxo_szn = sx_old[i] * sz_new[k];
853  amrex::Real const sxn_szo = sx_new[i] * sz_old[k];
854  amrex::Real const sxo_szo = sx_old[i] * sz_old[k];
855 
856  // Jx
857  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + k_new + k, 0, 0),
858  wq * invvol * invdt * 0.5_rt * sxn_szn);
859 
860  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + k_new + k, 0, 0),
861  - wq * invvol * invdt * 0.5_rt * sxo_szn);
862 
863  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + k_old + k, 0, 0),
864  wq * invvol * invdt * 0.5_rt * sxn_szo);
865 
866  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + k_old + k, 0, 0),
867  - wq * invvol * invdt * 0.5_rt * sxo_szo);
868 
869  // Jy
870  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + k_new + k, 0, 0),
871  wqy * 0.25_rt * sxn_szn);
872 
873  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + k_old + k, 0, 0),
874  wqy * 0.25_rt * sxn_szo);
875 
876  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + k_new + k, 0, 0),
877  wqy * 0.25_rt * sxo_szn);
878 
879  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + k_old + k, 0, 0),
880  wqy * 0.25_rt * sxo_szo);
881 
882  // Jz
883  amrex::Gpu::Atomic::AddNoRet(&jz_arr(lo.x + i_new + i, lo.y + k_new + k, 0, 0),
884  wq * invvol * invdt * 0.5_rt * sxn_szn);
885 
886  amrex::Gpu::Atomic::AddNoRet(&jz_arr(lo.x+i_new+i,lo.y+k_old+k,0,0),
887  - wq * invvol * invdt * 0.5_rt * sxn_szo);
888 
889  amrex::Gpu::Atomic::AddNoRet(&jz_arr(lo.x+i_old+i,lo.y+k_new+k,0,0),
890  wq * invvol * invdt * 0.5_rt * sxo_szn);
891 
892  amrex::Gpu::Atomic::AddNoRet(&jz_arr(lo.x + i_old + i, lo.y + k_old + k, 0, 0),
893  - wq * invvol * invdt * 0.5_rt * sxo_szo);
894  }
895  }
896 
897 #elif (defined WARPX_DIM_3D)
898 
899  for (int k=0; k<=depos_order; k++) {
900  for (int j=0; j<=depos_order; j++) {
901 
902  amrex::Real const syn_szn = sy_new[j] * sz_new[k];
903  amrex::Real const syo_szn = sy_old[j] * sz_new[k];
904  amrex::Real const syn_szo = sy_new[j] * sz_old[k];
905  amrex::Real const syo_szo = sy_old[j] * sz_old[k];
906 
907  for (int i=0; i<=depos_order; i++) {
908 
909  amrex::Real const sxn_syn_szn = sx_new[i] * syn_szn;
910  amrex::Real const sxo_syn_szn = sx_old[i] * syn_szn;
911  amrex::Real const sxn_syo_szn = sx_new[i] * syo_szn;
912  amrex::Real const sxo_syo_szn = sx_old[i] * syo_szn;
913  amrex::Real const sxn_syn_szo = sx_new[i] * syn_szo;
914  amrex::Real const sxo_syn_szo = sx_old[i] * syn_szo;
915  amrex::Real const sxn_syo_szo = sx_new[i] * syo_szo;
916  amrex::Real const sxo_syo_szo = sx_old[i] * syo_szo;
917 
918  // Jx
919  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + j_new + j, lo.z + k_new + k),
920  wq * invvol * invdt * onethird * sxn_syn_szn);
921 
922  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + j_new + j, lo.z + k_new + k),
923  - wq * invvol * invdt * onethird * sxo_syn_szn);
924 
925  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + j_old + j, lo.z + k_new + k),
926  wq * invvol * invdt * onesixth * sxn_syo_szn);
927 
928  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + j_old + j,lo.z + k_new + k),
929  - wq * invvol * invdt * onesixth * sxo_syo_szn);
930 
931  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + j_new + j, lo.z + k_old + k),
932  wq * invvol * invdt * onesixth * sxn_syn_szo);
933 
934  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + j_new + j, lo.z + k_old + k),
935  - wq * invvol * invdt * onesixth * sxo_syn_szo);
936 
937  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_new + i, lo.y + j_old + j, lo.z + k_old + k),
938  wq * invvol * invdt * onethird * sxn_syo_szo);
939 
940  amrex::Gpu::Atomic::AddNoRet(&jx_arr(lo.x + i_old + i, lo.y + j_old + j, lo.z + k_old + k),
941  - wq * invvol * invdt * onethird * sxo_syo_szo);
942 
943  // Jy
944  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + j_new + j, lo.z + k_new + k),
945  wq * invvol * invdt * onethird * sxn_syn_szn);
946 
947  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + j_old + j, lo.z + k_new + k),
948  - wq * invvol * invdt * onethird * sxn_syo_szn);
949 
950  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + j_new + j, lo.z + k_new + k),
951  wq * invvol * invdt * onesixth * sxo_syn_szn);
952 
953  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + j_old + j, lo.z + k_new + k),
954  - wq * invvol * invdt * onesixth * sxo_syo_szn);
955 
956  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + j_new + j, lo.z + k_old + k),
957  wq * invvol * invdt * onesixth * sxn_syn_szo);
958 
959  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_new + i, lo.y + j_old + j, lo.z + k_old + k),
960  - wq * invvol * invdt * onesixth * sxn_syo_szo);
961 
962  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + j_new + j, lo.z + k_old + k),
963  wq * invvol * invdt * onethird * sxo_syn_szo);
964 
965  amrex::Gpu::Atomic::AddNoRet(&jy_arr(lo.x + i_old + i, lo.y + j_old + j, lo.z + k_old + k),
966  - wq * invvol * invdt * onethird * sxo_syo_szo);
967 
968  // Jz
969  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_new + i, lo.y + j_new + j, lo.z + k_new + k),
970  wq * invvol * invdt * onethird * sxn_syn_szn);
971 
972  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_new + i, lo.y + j_new + j, lo.z + k_old + k),
973  - wq * invvol * invdt * onethird * sxn_syn_szo);
974 
975  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_old + i, lo.y + j_new + j, lo.z + k_new + k),
976  wq * invvol * invdt * onesixth * sxo_syn_szn);
977 
978  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_old + i, lo.y + j_new + j, lo.z + k_old + k),
979  - wq * invvol * invdt * onesixth * sxo_syn_szo);
980 
981  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_new + i, lo.y + j_old + j, lo.z + k_new + k),
982  wq * invvol * invdt * onesixth * sxn_syo_szn);
983 
984  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_new + i, lo.y + j_old + j, lo.z + k_old + k),
985  - wq * invvol * invdt * onesixth * sxn_syo_szo);
986 
987  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_old + i, lo.y + j_old + j, lo.z + k_new + k),
988  wq * invvol * invdt * onethird * sxo_syo_szn);
989 
990  amrex::Gpu::Atomic::AddNoRet(&jz_arr( lo.x + i_old + i, lo.y + j_old + j, lo.z + k_old + k),
991  - wq * invvol * invdt * onethird * sxo_syo_szo);
992  }
993  }
994  }
995 #endif
996  } );
997 # if defined(WARPX_USE_GPUCLOCK)
998  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
999  amrex::Gpu::streamSynchronize();
1000  *cost += *cost_real;
1001  amrex::The_Managed_Arena()->free(cost_real);
1002  }
1003 # endif
1004 #endif // #if !(defined WARPX_DIM_RZ)
1005 }
1006 #endif // CURRENTDEPOSITION_H_
amrex::GpuComplex< amrex::Real > Complex
Definition: WarpX_Complex.H:22
void doDepositionShapeN(const GetParticlePosition &GetPosition, const amrex::ParticleReal *const wp, const amrex::ParticleReal *const uxp, const amrex::ParticleReal *const uyp, const amrex::ParticleReal *const uzp, const int *const ion_lev, amrex::FArrayBox &jx_fab, amrex::FArrayBox &jy_fab, amrex::FArrayBox &jz_fab, const long np_to_depose, const amrex::Real relative_t, const std::array< amrex::Real, 3 > &dx, const std::array< amrex::Real, 3 > &xyzmin, const amrex::Dim3 lo, const amrex::Real q, const int n_rz_azimuthal_modes, amrex::Real *cost, const long load_balance_costs_update_algo)
Current Deposition for thread thread_num.
Definition: CurrentDeposition.H:53
int dx
Definition: compute_domain.py:35
Definition: ShapeFactors.H:118
Definition: ShapeFactors.H:22
void doEsirkepovDepositionShapeN(const GetParticlePosition &GetPosition, const amrex::ParticleReal *const wp, const amrex::ParticleReal *const uxp, const amrex::ParticleReal *const uyp, const amrex::ParticleReal *const uzp, const int *const ion_lev, const amrex::Array4< amrex::Real > &Jx_arr, const amrex::Array4< amrex::Real > &Jy_arr, const amrex::Array4< amrex::Real > &Jz_arr, const long np_to_depose, const amrex::Real dt, const std::array< amrex::Real, 3 > &dx, const std::array< amrex::Real, 3 > xyzmin, const amrex::Dim3 lo, const amrex::Real q, const int n_rz_azimuthal_modes, amrex::Real *const cost, const long load_balance_costs_update_algo)
Esirkepov Current Deposition for thread thread_num.
Definition: CurrentDeposition.H:341
i
Definition: check_interp_points_and_weights.py:171
void doVayDepositionShapeN(const GetParticlePosition &GetPosition, const amrex::ParticleReal *const wp, const amrex::ParticleReal *const uxp, const amrex::ParticleReal *const uyp, const amrex::ParticleReal *const uzp, const int *const ion_lev, amrex::FArrayBox &jx_fab, amrex::FArrayBox &jy_fab, amrex::FArrayBox &jz_fab, const long np_to_depose, const amrex::Real dt, const std::array< amrex::Real, 3 > &dx, const std::array< amrex::Real, 3 > &xyzmin, const amrex::Dim3 lo, const amrex::Real q, const int n_rz_azimuthal_modes, amrex::Real *cost, const long load_balance_costs_update_algo)
Vay current deposition (Vay et al, 2013) for thread thread_num: deposit D in real space and store the...
Definition: CurrentDeposition.H:677
Definition: WarpXAlgorithmSelection.H:93
Functor that can be used to extract the positions of the macroparticles inside a ParallelFor kernel...
Definition: GetAndSetPosition.H:48
Defines a timer object to be used on GPU; measures summed thread cycles.
Definition: KernelTimer.H:19
Definition: BreitWheelerEngineWrapper.H:35