WarpX
ChargeDeposition.H
Go to the documentation of this file.
1 /* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
2  * Weiqun Zhang
3  *
4  * This file is part of WarpX.
5  *
6  * License: BSD-3-Clause-LBNL
7  */
8 #ifndef CHARGEDEPOSITION_H_
9 #define CHARGEDEPOSITION_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 
21 /* \brief Charge Deposition for thread thread_num
22  * \param GetPosition : A functor for returning the particle position.
23  * \param wp : Pointer to array of particle weights.
24  * \param ion_lev : Pointer to array of particle ionization level. This is
25  required to have the charge of each macroparticle
26  since q is a scalar. For non-ionizable species,
27  ion_lev is a null pointer.
28  * \param rho_fab : FArrayBox of charge density, either full array or tile.
29  * \param np_to_depose : Number of particles for which current is deposited.
30  * \param dx : 3D cell size
31  * \param xyzmin : Physical lower bounds of domain.
32  * \param lo : Index lower bounds of domain.
33  * \param q : species charge.
34  * \param n_rz_azimuthal_modes: Number of azimuthal modes when using RZ geometry.
35  * \param cost: Pointer to (load balancing) cost corresponding to box where present particles deposit current.
36  * \param load_balance_costs_update_algo: Selected method for updating load balance costs.
37  */
38 template <int depos_order>
40  const amrex::ParticleReal * const wp,
41  const int * const ion_lev,
42  amrex::FArrayBox& rho_fab,
43  const long np_to_depose,
44  const std::array<amrex::Real,3>& dx,
45  const std::array<amrex::Real, 3> xyzmin,
46  const amrex::Dim3 lo,
47  const amrex::Real q,
48  const int n_rz_azimuthal_modes,
49  amrex::Real* cost,
50  const long load_balance_costs_update_algo)
51 {
52  using namespace amrex;
53 
54 #if !defined(AMREX_USE_GPU)
55  amrex::ignore_unused(cost, load_balance_costs_update_algo);
56 #endif
57 
58  // Whether ion_lev is a null pointer (do_ionization=0) or a real pointer
59  // (do_ionization=1)
60  const bool do_ionization = ion_lev;
61  const amrex::Real dxi = 1.0_rt/dx[0];
62  const amrex::Real dzi = 1.0_rt/dx[2];
63 #if (AMREX_SPACEDIM == 2)
64  const amrex::Real invvol = dxi*dzi;
65 #elif (defined WARPX_DIM_3D)
66  const amrex::Real dyi = 1.0_rt/dx[1];
67  const amrex::Real invvol = dxi*dyi*dzi;
68 #endif
69 
70  const amrex::Real xmin = xyzmin[0];
71 #if (defined WARPX_DIM_3D)
72  const amrex::Real ymin = xyzmin[1];
73 #endif
74  const amrex::Real zmin = xyzmin[2];
75 
76  amrex::Array4<amrex::Real> const& rho_arr = rho_fab.array();
77  amrex::IntVect const rho_type = rho_fab.box().type();
78 
79  constexpr int zdir = (AMREX_SPACEDIM - 1);
80  constexpr int NODE = amrex::IndexType::NODE;
81  constexpr int CELL = amrex::IndexType::CELL;
82 
83  // Loop over particles and deposit into rho_fab
84 #if defined(WARPX_USE_GPUCLOCK)
85  amrex::Real* cost_real = nullptr;
86  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
87  cost_real = (amrex::Real *) amrex::The_Managed_Arena()->alloc(sizeof(amrex::Real));
88  *cost_real = 0.;
89  }
90 #endif
91  amrex::ParallelFor(
92  np_to_depose,
93  [=] AMREX_GPU_DEVICE (long ip) {
94 #if defined(WARPX_USE_GPUCLOCK)
95  KernelTimer kernelTimer(cost && load_balance_costs_update_algo
97 #endif
98  // --- Get particle quantities
99  amrex::Real wq = q*wp[ip]*invvol;
100  if (do_ionization){
101  wq *= ion_lev[ip];
102  }
103 
104  amrex::ParticleReal xp, yp, zp;
105  GetPosition(ip, xp, yp, zp);
106 
107  // --- Compute shape factors
108  // x direction
109  // Get particle position in grid coordinates
110 #if (defined WARPX_DIM_RZ)
111  const amrex::Real rp = std::sqrt(xp*xp + yp*yp);
112  amrex::Real costheta;
113  amrex::Real sintheta;
114  if (rp > 0.) {
115  costheta = xp/rp;
116  sintheta = yp/rp;
117  } else {
118  costheta = 1._rt;
119  sintheta = 0._rt;
120  }
121  const Complex xy0 = Complex{costheta, sintheta};
122  const amrex::Real x = (rp - xmin)*dxi;
123 #else
124  const amrex::Real x = (xp - xmin)*dxi;
125 #endif
126 
127  // Compute shape factor along x
128  // i: leftmost grid point that the particle touches
129  amrex::Real sx[depos_order + 1] = {0._rt};
130  int i = 0;
131  Compute_shape_factor< depos_order > const compute_shape_factor;
132  if (rho_type[0] == NODE) {
133  i = compute_shape_factor(sx, x);
134  } else if (rho_type[0] == CELL) {
135  i = compute_shape_factor(sx, x - 0.5_rt);
136  }
137 
138 #if (defined WARPX_DIM_3D)
139  // y direction
140  const amrex::Real y = (yp - ymin)*dyi;
141  amrex::Real sy[depos_order + 1] = {0._rt};
142  int j = 0;
143  if (rho_type[1] == NODE) {
144  j = compute_shape_factor(sy, y);
145  } else if (rho_type[1] == CELL) {
146  j = compute_shape_factor(sy, y - 0.5_rt);
147  }
148 #endif
149  // z direction
150  const amrex::Real z = (zp - zmin)*dzi;
151  amrex::Real sz[depos_order + 1] = {0._rt};
152  int k = 0;
153  if (rho_type[zdir] == NODE) {
154  k = compute_shape_factor(sz, z);
155  } else if (rho_type[zdir] == CELL) {
156  k = compute_shape_factor(sz, z - 0.5_rt);
157  }
158 
159  // Deposit charge into rho_arr
160 #if (defined WARPX_DIM_XZ) || (defined WARPX_DIM_RZ)
161  for (int iz=0; iz<=depos_order; iz++){
162  for (int ix=0; ix<=depos_order; ix++){
163  amrex::Gpu::Atomic::AddNoRet(
164  &rho_arr(lo.x+i+ix, lo.y+k+iz, 0, 0),
165  sx[ix]*sz[iz]*wq);
166 #if (defined WARPX_DIM_RZ)
167  Complex xy = xy0; // Throughout the following loop, xy takes the value e^{i m theta}
168  for (int imode=1 ; imode < n_rz_azimuthal_modes ; imode++) {
169  // The factor 2 on the weighting comes from the normalization of the modes
170  amrex::Gpu::Atomic::AddNoRet( &rho_arr(lo.x+i+ix, lo.y+k+iz, 0, 2*imode-1), 2._rt*sx[ix]*sz[iz]*wq*xy.real());
171  amrex::Gpu::Atomic::AddNoRet( &rho_arr(lo.x+i+ix, lo.y+k+iz, 0, 2*imode ), 2._rt*sx[ix]*sz[iz]*wq*xy.imag());
172  xy = xy*xy0;
173  }
174 #endif
175  }
176  }
177 #elif (defined WARPX_DIM_3D)
178  for (int iz=0; iz<=depos_order; iz++){
179  for (int iy=0; iy<=depos_order; iy++){
180  for (int ix=0; ix<=depos_order; ix++){
181  amrex::Gpu::Atomic::AddNoRet(
182  &rho_arr(lo.x+i+ix, lo.y+j+iy, lo.z+k+iz),
183  sx[ix]*sy[iy]*sz[iz]*wq);
184  }
185  }
186  }
187 #endif
188  }
189  );
190 #if defined(WARPX_USE_GPUCLOCK)
191  if( load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::GpuClock) {
192  amrex::Gpu::streamSynchronize();
193  *cost += *cost_real;
194  amrex::The_Managed_Arena()->free(cost_real);
195  }
196 #endif
197 
198 #ifndef WARPX_DIM_RZ
199  amrex::ignore_unused(n_rz_azimuthal_modes);
200 #endif
201 }
202 
203 #endif // CHARGEDEPOSITION_H_
amrex::GpuComplex< amrex::Real > Complex
Definition: WarpX_Complex.H:22
void doChargeDepositionShapeN(const GetParticlePosition &GetPosition, const amrex::ParticleReal *const wp, const int *const ion_lev, amrex::FArrayBox &rho_fab, const long np_to_depose, 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)
Definition: ChargeDeposition.H:39
def x
Definition: read_lab_particles.py:25
int dx
Definition: compute_domain.py:35
def z
Definition: read_lab_particles.py:26
Definition: ShapeFactors.H:22
i
Definition: check_interp_points_and_weights.py:171
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