WarpX
DepositCharge.H
Go to the documentation of this file.
1 /* Copyright 2019-2021 Axel Huebl, Andrew Myers
2  *
3  * This file is part of WarpX.
4  *
5  * License: BSD-3-Clause-LBNL
6  */
7 #ifndef ABLASTR_DEPOSIT_CHARGE_H_
8 #define ABLASTR_DEPOSIT_CHARGE_H_
9 
13 #include "Particles/ShapeFactors.H"
15 #include "ablastr/utils/TextMsg.H"
16 #ifdef WARPX_DIM_RZ
17 # include "Utils/WarpX_Complex.H"
18 #endif
19 
20 #include <AMReX.H>
21 
22 #include <optional>
23 
24 
26 {
27 
57 template< typename T_PC >
58 static void
59 deposit_charge (typename T_PC::ParIterType& pti,
60  typename T_PC::RealVector const& wp,
61  amrex::Real const charge,
62  int const * const ion_lev,
63  amrex::MultiFab* rho,
64  amrex::FArrayBox& local_rho,
65  int const particle_shape,
66  std::array<amrex::Real, 3> const & dx,
67  std::array<amrex::Real, 3> const & xyzmin,
68  int const n_rz_azimuthal_modes = 0,
69  std::optional<amrex::IntVect> num_rho_deposition_guards = std::nullopt,
70  std::optional<int> depos_lev = std::nullopt,
71  std::optional<amrex::IntVect> rel_ref_ratio = std::nullopt,
72  long const offset = 0,
73  std::optional<long> np_to_depose = std::nullopt,
74  int const icomp = 0, int const nc = 1,
75  amrex::Real * const AMREX_RESTRICT cost = nullptr,
76  long const load_balance_costs_update_algo = 0,
77  bool const do_device_synchronize = true)
78 {
79  // deposition guards
80  amrex::IntVect ng_rho = rho->nGrowVect();
81  if (num_rho_deposition_guards.has_value())
82  ng_rho = num_rho_deposition_guards.value();
83  ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(ng_rho <= rho->nGrowVect(),
84  "num_rho_deposition_guards are larger than allocated!");
85  // particle shape
86  auto const[nox, noy, noz] = std::array<int, 3>{particle_shape, particle_shape, particle_shape};
87 
88  // used for MR when we want to deposit for a subset of the particles on the level in the
89  // current box; with offset, we start at a later particle index
90  if (!np_to_depose.has_value())
91  np_to_depose = pti.numParticles();
92  ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(np_to_depose.value() + offset <= pti.numParticles(),
93  "np_to_depose + offset are out-of-bounds for particle iterator");
94 
95  int const lev = pti.GetLevel();
96  if (!depos_lev.has_value())
97  depos_lev = lev;
98  ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE((depos_lev.value() == (lev-1)) ||
99  (depos_lev.value() == (lev )),
100  "Deposition buffers only work for lev or lev-1");
101  if (!rel_ref_ratio.has_value()) {
102  ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(lev == depos_lev,
103  "rel_ref_ratio must be set if lev != depos_lev");
104  rel_ref_ratio = amrex::IntVect(AMREX_D_DECL(1, 1, 1));
105  }
106 
107  // If no particles, do not do anything
108  if (np_to_depose == 0) return;
109 
110  // Extract deposition order and check that particles shape fits within the guard cells.
111  // NOTE: In specific situations where the staggering of rho and the charge deposition algorithm
112  // are not trivial, this check might be too strict and we might need to relax it, as currently
113  // done for the current deposition.
114 
115 #if defined(WARPX_DIM_1D_Z)
118  const amrex::IntVect shape_extent = amrex::IntVect(static_cast<int>(noz/2+1));
119 #elif defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
121  const amrex::IntVect shape_extent = amrex::IntVect(static_cast<int>(nox/2+1),
122  static_cast<int>(noz/2+1));
123 #elif defined(WARPX_DIM_3D)
124  const amrex::IntVect shape_extent = amrex::IntVect(static_cast<int>(nox/2+1),
125  static_cast<int>(noy/2+1),
126  static_cast<int>(noz/2+1));
127 #endif
128 
129  // On CPU: particles deposit on tile arrays, which have a small number of guard cells ng_rho
130  // On GPU: particles deposit directly on the rho array, which usually have a larger number of guard cells
131 #ifndef AMREX_USE_GPU
132  const amrex::IntVect range = ng_rho - shape_extent;
133 #else
134  const amrex::IntVect range = rho->nGrowVect() - shape_extent;
135 #endif
136  amrex::ignore_unused(range); // for release builds
138  amrex::numParticlesOutOfRange(pti, range) == 0,
139  "Particles shape does not fit within tile (CPU) or guard cells (GPU) used for charge deposition");
140 
141  ABLASTR_PROFILE_VAR_NS("ablastr::particles::deposit_charge::ChargeDeposition", blp_ppc_chd, do_device_synchronize);
142  ABLASTR_PROFILE_VAR_NS("ablastr::particles::deposit_charge::Accumulate", blp_accumulate, do_device_synchronize);
143 
144  // Get tile box where charge is deposited.
145  // The tile box is different when depositing in the buffers (depos_lev<lev)
146  // or when depositing inside the level (depos_lev=lev)
147  amrex::Box tilebox;
148  if (lev == depos_lev) {
149  tilebox = pti.tilebox();
150  } else {
151  tilebox = amrex::coarsen(pti.tilebox(), rel_ref_ratio.value());
152  }
153 
154 #ifndef AMREX_USE_GPU
155  // Staggered tile box
156  amrex::Box tb = amrex::convert( tilebox, rho->ixType().toIntVect() );
157 #endif
158 
159  tilebox.grow(ng_rho);
160 
161 #ifdef AMREX_USE_GPU
162  amrex::ignore_unused(local_rho);
163  // GPU, no tiling: rho_fab points to the full rho array
164  amrex::MultiFab rhoi(*rho, amrex::make_alias, icomp*nc, nc);
165  auto & rho_fab = rhoi.get(pti);
166 #else
167  tb.grow(ng_rho);
168 
169  // CPU, tiling: rho_fab points to local_rho
170  local_rho.resize(tb, nc);
171 
172  // local_rho is set to zero
173  local_rho.setVal(0.0);
174 
175  auto & rho_fab = local_rho;
176 #endif
177 
178  const auto GetPosition = GetParticlePosition(pti, offset);
179 
180  // Indices of the lower bound
181  const amrex::Dim3 lo = lbound(tilebox);
182 
183  ABLASTR_PROFILE_VAR_START(blp_ppc_chd, do_device_synchronize);
184 
185  if (nox == 1){
186  doChargeDepositionShapeN<1>(GetPosition, wp.dataPtr()+offset, ion_lev,
187  rho_fab, np_to_depose.value(), dx, xyzmin, lo, charge,
188  n_rz_azimuthal_modes, cost,
189  load_balance_costs_update_algo);
190  } else if (nox == 2){
191  doChargeDepositionShapeN<2>(GetPosition, wp.dataPtr()+offset, ion_lev,
192  rho_fab, np_to_depose.value(), dx, xyzmin, lo, charge,
193  n_rz_azimuthal_modes, cost,
194  load_balance_costs_update_algo);
195  } else if (nox == 3){
196  doChargeDepositionShapeN<3>(GetPosition, wp.dataPtr()+offset, ion_lev,
197  rho_fab, np_to_depose.value(), dx, xyzmin, lo, charge,
198  n_rz_azimuthal_modes, cost,
199  load_balance_costs_update_algo);
200  }
201  ABLASTR_PROFILE_VAR_STOP(blp_ppc_chd, do_device_synchronize);
202 
203 #ifndef AMREX_USE_GPU
204  // CPU, tiling: atomicAdd local_rho into rho
205  ABLASTR_PROFILE_VAR_START(blp_accumulate, do_device_synchronize);
206  (*rho)[pti].atomicAdd(local_rho, tb, tb, 0, icomp*nc, nc);
207  ABLASTR_PROFILE_VAR_STOP(blp_accumulate, do_device_synchronize);
208 #endif
209 }
210 
211 } // namespace ablastr::particles
212 
213 #endif // ABLASTR_DEPOSIT_CHARGE_H_
IntVect nGrowVect() const noexcept
#define AMREX_D_DECL(a, b, c)
int noz
Definition: Stencil.py:472
int nc
Definition: check_interp_points_and_weights.py:130
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE IntVect toIntVect() const noexcept
int noy
Definition: Stencil.py:471
int nox
Definition: Stencil.py:470
int dx
Definition: compute_domain.py:35
IndexType ixType() const noexcept
static void deposit_charge(typename T_PC::ParIterType &pti, typename T_PC::RealVector const &wp, amrex::Real const charge, int const *const ion_lev, amrex::MultiFab *rho, amrex::FArrayBox &local_rho, int const particle_shape, std::array< amrex::Real, 3 > const &dx, std::array< amrex::Real, 3 > const &xyzmin, int const n_rz_azimuthal_modes=0, std::optional< amrex::IntVect > num_rho_deposition_guards=std::nullopt, std::optional< int > depos_lev=std::nullopt, std::optional< amrex::IntVect > rel_ref_ratio=std::nullopt, long const offset=0, std::optional< long > np_to_depose=std::nullopt, int const icomp=0, int const nc=1, amrex::Real *const AMREX_RESTRICT cost=nullptr, long const load_balance_costs_update_algo=0, bool const do_device_synchronize=true)
Definition: DepositCharge.H:59
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void ignore_unused(const Ts &...)
Definition: DepositCharge.H:25
const FArrayBox & get(const MFIter &mfi) const noexcept
#define ABLASTR_PROFILE_VAR_NS(fname, vname, sync)
Definition: ProfilerWrapper.H:51
int numParticlesOutOfRange(Iterator const &pti, int nGrow)
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Box coarsen(const Box &b, int ref_ratio) noexcept
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Dim3 lbound(Array4< T > const &a) noexcept
#define ABLASTR_PROFILE_VAR_START(vname, sync)
Definition: ProfilerWrapper.H:52
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Box convert(const Box &b, const IntVect &typ) noexcept
AMREX_GPU_HOST_DEVICE Box & grow(int i) noexcept
void resize(const Box &b, int N=1, Arena *ar=nullptr)
#define ABLASTR_PROFILE_VAR_STOP(vname, sync)
Definition: ProfilerWrapper.H:53
#define ABLASTR_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition: TextMsg.H:73
Functor that can be used to extract the positions of the macroparticles inside a ParallelFor kernel...
Definition: GetAndSetPosition.H:52
void setVal(Real const &x, const Box &bx, int dcomp, int ncomp) noexcept