diff options
Diffstat (limited to 'Source/Particles')
-rw-r--r-- | Source/Particles/WarpXParticleContainer.cpp | 88 |
1 files changed, 56 insertions, 32 deletions
diff --git a/Source/Particles/WarpXParticleContainer.cpp b/Source/Particles/WarpXParticleContainer.cpp index a50345f4b..d3427b148 100644 --- a/Source/Particles/WarpXParticleContainer.cpp +++ b/Source/Particles/WarpXParticleContainer.cpp @@ -228,13 +228,29 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, AMREX_ALWAYS_ASSERT_WITH_MESSAGE((depos_lev==(lev-1)) || (depos_lev==(lev )), "Deposition buffers only work for lev-1"); + // If no particles, do not do anything if (np_to_depose == 0) return; // If user decides not to deposit if (do_not_deposit) return; - const long ngJ = jx->nGrow(); + // Number of guard cells for local deposition of J + WarpX& warpx = WarpX::GetInstance(); + const int ng_J = warpx.get_ng_depos_J().max(); + + // Extract deposition order (same order along all directions) and check that + // particles shape fits within the guard cells. + // NOTE: In specific situations where the staggering of J and the current + // deposition algorithm are not trivial, this check might be too relaxed + // and we might include a particle that should deposit part of its current + // in a neighboring box. However, this should catch particles traveling many + // cells away, for example with algorithms that allow for large time steps. + const int shape_extent = static_cast<int>(WarpX::nox / 2); + AMREX_ALWAYS_ASSERT_WITH_MESSAGE( + amrex::numParticlesOutOfRange(pti, ng_J - shape_extent) == 0, + "Particles shape does not fit within guard cells used for local current deposition"); + const std::array<Real,3>& dx = WarpX::CellSize(std::max(depos_lev,0)); Real q = this->charge; @@ -256,11 +272,11 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, Box tbx = convert( tilebox, jx->ixType().toIntVect() ); Box tby = convert( tilebox, jy->ixType().toIntVect() ); Box tbz = convert( tilebox, jz->ixType().toIntVect() ); - tilebox.grow(ngJ); + + tilebox.grow(ng_J); #ifdef AMREX_USE_GPU - // No tiling on GPU: jx_ptr points to the full - // jx array (same for jy_ptr and jz_ptr). + // GPU, no tiling: j<xyz>_arr point to the full j<xyz> arrays auto & jx_fab = jx->get(pti); auto & jy_fab = jy->get(pti); auto & jz_fab = jz->get(pti); @@ -268,12 +284,11 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, Array4<Real> const& jy_arr = jy->array(pti); Array4<Real> const& jz_arr = jz->array(pti); #else - // Tiling is on: jx_ptr points to local_jx[thread_num] - // (same for jy_ptr and jz_ptr) - tbx.grow(ngJ); - tby.grow(ngJ); - tbz.grow(ngJ); + tbx.grow(ng_J); + tby.grow(ng_J); + tbz.grow(ng_J); + // CPU, tiling: j<xyz>_arr point to the local_j<xyz>[thread_num] arrays local_jx[thread_num].resize(tbx, jx->nComp()); local_jy[thread_num].resize(tby, jy->nComp()); local_jz[thread_num].resize(tbz, jz->nComp()); @@ -290,9 +305,6 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, Array4<Real> const& jy_arr = local_jy[thread_num].array(); Array4<Real> const& jz_arr = local_jz[thread_num].array(); #endif - // GPU, no tiling: deposit directly in jx - // CPU, tiling: deposit into local_jx - // (same for jx and jz) const auto GetPosition = GetParticlePosition(pti, offset); @@ -300,9 +312,8 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, // Note that this includes guard cells since it is after tilebox.ngrow const Dim3 lo = lbound(tilebox); // Take into account Galilean shift - auto& warpx_instance = WarpX::GetInstance(); - Real cur_time = warpx_instance.gett_new(lev); - const auto& time_of_last_gal_shift = warpx_instance.time_of_last_gal_shift; + Real cur_time = warpx.gett_new(lev); + const auto& time_of_last_gal_shift = warpx.time_of_last_gal_shift; Real time_shift = (cur_time + 0.5*dt - time_of_last_gal_shift); amrex::Array<amrex::Real,3> galilean_shift = { m_v_galilean[0]* time_shift, @@ -384,9 +395,8 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, WARPX_PROFILE_VAR_STOP(blp_deposit); #ifndef AMREX_USE_GPU + // CPU, tiling: atomicAdd local_j<xyz> into j<xyz> WARPX_PROFILE_VAR_START(blp_accumulate); - // CPU, tiling: atomicAdd local_jx into jx - // (same for jx and jz) (*jx)[pti].atomicAdd(local_jx[thread_num], tbx, tbx, 0, 0, jx->nComp()); (*jy)[pti].atomicAdd(local_jy[thread_num], tby, tby, 0, 0, jy->nComp()); (*jz)[pti].atomicAdd(local_jz[thread_num], tbz, tbz, 0, 0, jz->nComp()); @@ -429,7 +439,20 @@ WarpXParticleContainer::DepositCharge (WarpXParIter& pti, RealVector& wp, // If user decides not to deposit if (do_not_deposit) return; - const long ngRho = rho->nGrow(); + // Number of guard cells for local deposition of rho + WarpX& warpx = WarpX::GetInstance(); + const int ng_rho = warpx.get_ng_depos_rho().max(); + + // Extract deposition order (same order along all directions) and check that + // particles shape fits within the guard cells. + // NOTE: In specific situations where the staggering of rho and the charge + // deposition algorithm are not trivial, this check might be too strict and + // we might need to relax it, as currently done for the current deposition. + const int shape_extent = static_cast<int>(WarpX::nox / 2 + 1); + AMREX_ALWAYS_ASSERT_WITH_MESSAGE( + amrex::numParticlesOutOfRange(pti, ng_rho - shape_extent) == 0, + "Particles shape does not fit within guard cells used for local charge deposition"); + const std::array<Real,3>& dx = WarpX::CellSize(std::max(depos_lev,0)); const Real q = this->charge; @@ -447,18 +470,21 @@ WarpXParticleContainer::DepositCharge (WarpXParIter& pti, RealVector& wp, tilebox = amrex::coarsen(pti.tilebox(),ref_ratio); } - tilebox.grow(ngRho); - const Box tb = amrex::convert( tilebox, rho->ixType().toIntVect() ); + // Staggered tile box + Box tb = amrex::convert( tilebox, rho->ixType().toIntVect() ); + + tilebox.grow(ng_rho); const int nc = WarpX::ncomps; #ifdef AMREX_USE_GPU - // No tiling on GPU: rho_fab points to the full rho array. + // GPU, no tiling: rho_fab points to the full rho array MultiFab rhoi(*rho, amrex::make_alias, icomp*nc, nc); auto & rho_fab = rhoi.get(pti); #else - // Tiling is on: rho_fab points to local_rho[thread_num] + tb.grow(ng_rho); + // CPU, tiling: rho_fab points to local_rho[thread_num] local_rho[thread_num].resize(tb, nc); // local_rho[thread_num] is set to zero @@ -466,17 +492,14 @@ WarpXParticleContainer::DepositCharge (WarpXParIter& pti, RealVector& wp, auto & rho_fab = local_rho[thread_num]; #endif - // GPU, no tiling: deposit directly in rho - // CPU, tiling: deposit into local_rho const auto GetPosition = GetParticlePosition(pti, offset); // Lower corner of tile box physical domain // Note that this includes guard cells since it is after tilebox.ngrow - const auto& warpx_instance = WarpX::GetInstance(); - Real cur_time = warpx_instance.gett_new(lev); - Real dt = warpx_instance.getdt(lev); - const auto& time_of_last_gal_shift = warpx_instance.time_of_last_gal_shift; + Real cur_time = warpx.gett_new(lev); + Real dt = warpx.getdt(lev); + const auto& time_of_last_gal_shift = warpx.time_of_last_gal_shift; // Take into account Galilean shift Real time_shift_rho_old = (cur_time - time_of_last_gal_shift); Real time_shift_rho_new = (cur_time + dt - time_of_last_gal_shift); @@ -514,10 +537,9 @@ WarpXParticleContainer::DepositCharge (WarpXParIter& pti, RealVector& wp, WARPX_PROFILE_VAR_STOP(blp_ppc_chd); #ifndef AMREX_USE_GPU + // CPU, tiling: atomicAdd local_rho into rho WARPX_PROFILE_VAR_START(blp_accumulate); - (*rho)[pti].atomicAdd(local_rho[thread_num], tb, tb, 0, icomp*nc, nc); - WARPX_PROFILE_VAR_STOP(blp_accumulate); #endif } @@ -602,9 +624,11 @@ WarpXParticleContainer::GetChargeDensity (int lev, bool local) nba.surroundingNodes(); #endif - const int ng = WarpX::nox; + // Number of guard cells for local deposition of rho + WarpX& warpx = WarpX::GetInstance(); + const int ng_rho = warpx.get_ng_depos_rho().max(); - auto rho = std::unique_ptr<MultiFab>(new MultiFab(nba,dm,WarpX::ncomps,ng)); + auto rho = std::unique_ptr<MultiFab>(new MultiFab(nba,dm,WarpX::ncomps,ng_rho)); rho->setVal(0.0); #ifdef _OPENMP |