diff options
Diffstat (limited to 'Source/Particles/PhysicalParticleContainer.cpp')
-rw-r--r-- | Source/Particles/PhysicalParticleContainer.cpp | 602 |
1 files changed, 232 insertions, 370 deletions
diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp index a0016d436..07c307c83 100644 --- a/Source/Particles/PhysicalParticleContainer.cpp +++ b/Source/Particles/PhysicalParticleContainer.cpp @@ -899,69 +899,6 @@ PhysicalParticleContainer::AddPlasma (int lev, RealBox part_realbox) } void -PhysicalParticleContainer::FieldGather (int lev, - const amrex::MultiFab& Ex, - const amrex::MultiFab& Ey, - const amrex::MultiFab& Ez, - const amrex::MultiFab& Bx, - const amrex::MultiFab& By, - const amrex::MultiFab& Bz) -{ - BL_ASSERT(OnSameGrids(lev,Ex)); - - amrex::LayoutData<amrex::Real>* cost = WarpX::getCosts(lev); - -#ifdef _OPENMP -#pragma omp parallel -#endif - { - for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti) - { - if (cost && WarpX::load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::Timers) - { - amrex::Gpu::synchronize(); - } - Real wt = amrex::second(); - - auto& attribs = pti.GetAttribs(); - - auto& Exp = attribs[PIdx::Ex]; - auto& Eyp = attribs[PIdx::Ey]; - auto& Ezp = attribs[PIdx::Ez]; - auto& Bxp = attribs[PIdx::Bx]; - auto& Byp = attribs[PIdx::By]; - auto& Bzp = attribs[PIdx::Bz]; - - const long np = pti.numParticles(); - - // Data on the grid - const FArrayBox& exfab = Ex[pti]; - const FArrayBox& eyfab = Ey[pti]; - const FArrayBox& ezfab = Ez[pti]; - const FArrayBox& bxfab = Bx[pti]; - const FArrayBox& byfab = By[pti]; - const FArrayBox& bzfab = Bz[pti]; - - // - // Field Gather - // - int e_is_nodal = Ex.is_nodal() and Ey.is_nodal() and Ez.is_nodal(); - FieldGather(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp, - &exfab, &eyfab, &ezfab, &bxfab, &byfab, &bzfab, - Ex.nGrow(), e_is_nodal, - 0, np, lev, lev); - - if (cost && WarpX::load_balance_costs_update_algo == LoadBalanceCostsUpdateAlgo::Timers) - { - amrex::Gpu::synchronize(); - wt = amrex::second() - wt; - amrex::HostDevice::Atomic::Add( &(*cost)[pti.index()], wt); - } - } - } -} - -void PhysicalParticleContainer::Evolve (int lev, const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz, @@ -973,10 +910,7 @@ PhysicalParticleContainer::Evolve (int lev, Real /*t*/, Real dt, DtType a_dt_type) { WARPX_PROFILE("PPC::Evolve()"); - WARPX_PROFILE_VAR_NS("PPC::Evolve::Copy", blp_copy); - WARPX_PROFILE_VAR_NS("PPC::FieldGather", blp_fg); - WARPX_PROFILE_VAR_NS("PPC::EvolveOpticalDepth", blp_ppc_qed_ev); - WARPX_PROFILE_VAR_NS("PPC::ParticlePush", blp_ppc_pp); + WARPX_PROFILE_VAR_NS("PPC::GatherAndPush", blp_fg); BL_ASSERT(OnSameGrids(lev,jx)); @@ -1029,12 +963,6 @@ PhysicalParticleContainer::Evolve (int lev, auto& uxp = attribs[PIdx::ux]; auto& uyp = attribs[PIdx::uy]; auto& uzp = attribs[PIdx::uz]; - auto& Exp = attribs[PIdx::Ex]; - auto& Eyp = attribs[PIdx::Ey]; - auto& Ezp = attribs[PIdx::Ez]; - auto& Bxp = attribs[PIdx::Bx]; - auto& Byp = attribs[PIdx::By]; - auto& Bzp = attribs[PIdx::Bz]; const long np = pti.numParticles(); @@ -1103,13 +1031,13 @@ PhysicalParticleContainer::Evolve (int lev, int e_is_nodal = Ex.is_nodal() and Ey.is_nodal() and Ez.is_nodal(); // - // Field Gather of Aux Data (i.e., the full solution) + // Gather and push for particles not in the buffer // WARPX_PROFILE_VAR_START(blp_fg); - FieldGather(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - Ex.nGrow(), e_is_nodal, - 0, np_gather, lev, lev); + PushPX(pti, exfab, eyfab, ezfab, + bxfab, byfab, bzfab, + Ex.nGrow(), e_is_nodal, + 0, np_gather, lev, lev, dt, ScaleFields(false), a_dt_type); if (np_gather < np) { @@ -1138,34 +1066,17 @@ PhysicalParticleContainer::Evolve (int lev, cexfab, ceyfab, cezfab, cbxfab, cbyfab, cbzfab); } - // Field gather for particles in gather buffers + // Field gather and push for particles in gather buffers e_is_nodal = cEx->is_nodal() and cEy->is_nodal() and cEz->is_nodal(); - FieldGather(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp, - cexfab, ceyfab, cezfab, - cbxfab, cbyfab, cbzfab, - cEx->nGrow(), e_is_nodal, - nfine_gather, np-nfine_gather, - lev, lev-1); + PushPX(pti, cexfab, ceyfab, cezfab, + cbxfab, cbyfab, cbzfab, + cEx->nGrow(), e_is_nodal, + nfine_gather, np-nfine_gather, + lev, lev-1, dt, ScaleFields(false), a_dt_type); } WARPX_PROFILE_VAR_STOP(blp_fg); -#ifdef WARPX_QED - // - //Evolve Optical Depth - // - WARPX_PROFILE_VAR_START(blp_ppc_qed_ev); - EvolveOpticalDepth(pti, dt); - WARPX_PROFILE_VAR_STOP(blp_ppc_qed_ev); -#endif - - // - // Particle Push - // - WARPX_PROFILE_VAR_START(blp_ppc_pp); - PushPX(pti, dt, a_dt_type); - WARPX_PROFILE_VAR_STOP(blp_ppc_pp); - // // Current Deposition (only needed for electromagnetic solver) // @@ -1466,131 +1377,24 @@ PhysicalParticleContainer::SplitParticles (int lev) } void -PhysicalParticleContainer::PushPX (WarpXParIter& pti, Real dt, DtType a_dt_type) -{ - - // This wraps the momentum and position advance so that inheritors can modify the call. - auto& attribs = pti.GetAttribs(); - // Extract pointers to the different particle quantities - - const auto GetPosition = GetParticlePosition(pti); - auto SetPosition = SetParticlePosition(pti); - - ParticleReal* const AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr(); - ParticleReal* const AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr(); - ParticleReal* const AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ex = attribs[PIdx::Ex].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ey = attribs[PIdx::Ey].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ez = attribs[PIdx::Ez].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bx = attribs[PIdx::Bx].dataPtr(); - const ParticleReal* const AMREX_RESTRICT By = attribs[PIdx::By].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bz = attribs[PIdx::Bz].dataPtr(); - - auto copyAttribs = CopyParticleAttribs(pti, tmp_particle_data); - int do_copy = (WarpX::do_back_transformed_diagnostics && - do_back_transformed_diagnostics && - (a_dt_type!=DtType::SecondHalf)); - - int* AMREX_RESTRICT ion_lev = nullptr; - if (do_field_ionization){ - ion_lev = pti.GetiAttribs(particle_icomps["ionization_level"]).dataPtr(); - } - - // Loop over the particles and update their momentum - const Real q = this->charge; - const Real m = this-> mass; - - const auto pusher_algo = WarpX::particle_pusher_algo; - const auto do_crr = do_classical_radiation_reaction; -#ifdef WARPX_QED - const auto do_sync = m_do_qed_quantum_sync; - amrex::Real t_chi_max = 0.0; - if (do_sync) t_chi_max = m_shr_p_qs_engine->get_ref_ctrl().chi_part_min; -#endif - - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i) { - doParticlePush(GetPosition, SetPosition, copyAttribs, i, - ux[i], uy[i], uz[i], - Ex[i], Ey[i], Ez[i], - Bx[i], By[i], Bz[i], - ion_lev ? ion_lev[i] : 0, - m, q, pusher_algo, do_crr, do_copy, -#ifdef WARPX_QED - do_sync, - t_chi_max, -#endif - dt); - }); -} - -#ifdef WARPX_QED -void PhysicalParticleContainer::EvolveOpticalDepth( - WarpXParIter& pti, amrex::Real dt) -{ - if(!has_quantum_sync()) - return; - - QuantumSynchrotronEvolveOpticalDepth evolve_opt = - m_shr_p_qs_engine->build_evolve_functor(); - - auto& attribs = pti.GetAttribs(); - const ParticleReal* const AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr(); - const ParticleReal* const AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr(); - const ParticleReal* const AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ex = attribs[PIdx::Ex].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ey = attribs[PIdx::Ey].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ez = attribs[PIdx::Ez].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bx = attribs[PIdx::Bx].dataPtr(); - const ParticleReal* const AMREX_RESTRICT By = attribs[PIdx::By].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bz = attribs[PIdx::Bz].dataPtr(); - - ParticleReal* const AMREX_RESTRICT p_optical_depth_QSR = - pti.GetAttribs(particle_comps["optical_depth_QSR"]).dataPtr(); - - const ParticleReal m = this->mass; - - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i) { - const ParticleReal px = m * ux[i]; - const ParticleReal py = m * uy[i]; - const ParticleReal pz = m * uz[i]; - - bool has_event_happened = evolve_opt( - px, py, pz, - Ex[i], Ey[i], Ez[i], - Bx[i], By[i], Bz[i], - dt, p_optical_depth_QSR[i]); - } - ); - -} -#endif - -void -PhysicalParticleContainer::PushP ( - int lev, Real dt, - const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, - const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) +PhysicalParticleContainer::PushP (int lev, Real dt, + const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, + const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) { WARPX_PROFILE("PhysicalParticleContainer::PushP"); if (do_not_push) return; + const std::array<amrex::Real,3>& dx = WarpX::CellSize(std::max(lev,0)); + #ifdef _OPENMP #pragma omp parallel #endif { for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti) { - auto& attribs = pti.GetAttribs(); - - auto& Exp = attribs[PIdx::Ex]; - auto& Eyp = attribs[PIdx::Ey]; - auto& Ezp = attribs[PIdx::Ez]; - auto& Bxp = attribs[PIdx::Bx]; - auto& Byp = attribs[PIdx::By]; - auto& Bzp = attribs[PIdx::Bz]; + amrex::Box box = pti.tilebox(); + box.grow(Ex.nGrow()); const long np = pti.numParticles(); @@ -1602,83 +1406,100 @@ PhysicalParticleContainer::PushP ( const FArrayBox& byfab = By[pti]; const FArrayBox& bzfab = Bz[pti]; - int e_is_nodal = Ex.is_nodal() and Ey.is_nodal() and Ez.is_nodal(); - FieldGather(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp, - &exfab, &eyfab, &ezfab, &bxfab, &byfab, &bzfab, - Ex.nGrow(), e_is_nodal, - 0, np, lev, lev); + const auto getPosition = GetParticlePosition(pti); + auto setPosition = SetParticlePosition(pti); + + const auto getExternalE = GetExternalEField(pti); + const auto getExternalB = GetExternalBField(pti); + + const auto& xyzmin = WarpX::GetInstance().LowerCornerWithGalilean(box,v_galilean,lev); + + const Dim3 lo = lbound(box); - // This wraps the momentum advance so that inheritors can modify the call. - // Extract pointers to the different particle quantities + int l_lower_order_in_v = WarpX::l_lower_order_in_v; + int nox = WarpX::nox; + int n_rz_azimuthal_modes = WarpX::n_rz_azimuthal_modes; + + amrex::GpuArray<amrex::Real, 3> dx_arr = {dx[0], dx[1], dx[2]}; + amrex::GpuArray<amrex::Real, 3> xyzmin_arr = {xyzmin[0], xyzmin[1], xyzmin[2]}; + + amrex::Array4<const amrex::Real> const& ex_arr = exfab.array(); + amrex::Array4<const amrex::Real> const& ey_arr = eyfab.array(); + amrex::Array4<const amrex::Real> const& ez_arr = ezfab.array(); + amrex::Array4<const amrex::Real> const& bx_arr = bxfab.array(); + amrex::Array4<const amrex::Real> const& by_arr = byfab.array(); + amrex::Array4<const amrex::Real> const& bz_arr = bzfab.array(); + + amrex::IndexType const ex_type = exfab.box().ixType(); + amrex::IndexType const ey_type = eyfab.box().ixType(); + amrex::IndexType const ez_type = ezfab.box().ixType(); + amrex::IndexType const bx_type = bxfab.box().ixType(); + amrex::IndexType const by_type = byfab.box().ixType(); + amrex::IndexType const bz_type = bzfab.box().ixType(); + + auto& attribs = pti.GetAttribs(); ParticleReal* const AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr(); ParticleReal* const AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr(); ParticleReal* const AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr(); - const ParticleReal* const AMREX_RESTRICT Expp = Exp.dataPtr(); - const ParticleReal* const AMREX_RESTRICT Eypp = Eyp.dataPtr(); - const ParticleReal* const AMREX_RESTRICT Ezpp = Ezp.dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bxpp = Bxp.dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bypp = Byp.dataPtr(); - const ParticleReal* const AMREX_RESTRICT Bzpp = Bzp.dataPtr(); - - // Loop over the particles and update their momentum - const Real q = this->charge; - const Real m = this-> mass; int* AMREX_RESTRICT ion_lev = nullptr; - if (do_field_ionization){ + if (do_field_ionization) { ion_lev = pti.GetiAttribs(particle_icomps["ionization_level"]).dataPtr(); } - //Assumes that all consistency checks have been done at initialization - if(do_classical_radiation_reaction){ - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i){ - Real qp = q; - if (ion_lev){ qp *= ion_lev[i]; } - UpdateMomentumBorisWithRadiationReaction( - ux[i], uy[i], uz[i], - Expp[i], Eypp[i], Ezpp[i], - Bxpp[i], Bypp[i], Bzpp[i], - qp, m, dt); - } - ); - } else if (WarpX::particle_pusher_algo == ParticlePusherAlgo::Boris){ - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i) { - Real qp = q; - if (ion_lev){ qp *= ion_lev[i]; } - UpdateMomentumBoris( - ux[i], uy[i], uz[i], - Expp[i], Eypp[i], Ezpp[i], - Bxpp[i], Bypp[i], Bzpp[i], - qp, m, dt); - } - ); - } else if (WarpX::particle_pusher_algo == ParticlePusherAlgo::Vay){ - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i) { - Real qp = q; - if (ion_lev){ qp *= ion_lev[i]; } - UpdateMomentumVay( - ux[i], uy[i], uz[i], - Expp[i], Eypp[i], Ezpp[i], - Bxpp[i], Bypp[i], Bzpp[i], - qp, m, dt); - } - ); - } else if (WarpX::particle_pusher_algo == ParticlePusherAlgo::HigueraCary){ - amrex::ParallelFor(pti.numParticles(), - [=] AMREX_GPU_DEVICE (long i) { - UpdateMomentumHigueraCary( ux[i], uy[i], uz[i], - Expp[i], Eypp[i], Ezpp[i], - Bxpp[i], Bypp[i], Bzpp[i], - q, m, dt); - } - ); - } else { - amrex::Abort("Unknown particle pusher"); - } + // Loop over the particles and update their momentum + const amrex::Real q = this->charge; + const amrex::Real m = this-> mass; + + const auto pusher_algo = WarpX::particle_pusher_algo; + const auto do_crr = do_classical_radiation_reaction; + amrex::ParallelFor( np, [=] AMREX_GPU_DEVICE (long ip) + { + amrex::ParticleReal xp, yp, zp; + getPosition(ip, xp, yp, zp); + + amrex::ParticleReal Exp = 0._rt, Eyp = 0._rt, Ezp = 0._rt; + getExternalE(ip, Exp, Eyp, Ezp); + + amrex::ParticleReal Bxp = 0._rt, Byp = 0._rt, Bzp = 0._rt; + getExternalB(ip, Bxp, Byp, Bzp); + + // first gather E and B to the particle positions + doGatherShapeN(xp, yp, zp, Exp, Eyp, Ezp, Bxp, Byp, Bzp, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + ex_type, ey_type, ez_type, bx_type, by_type, bz_type, + dx_arr, xyzmin_arr, lo, n_rz_azimuthal_modes, + nox, l_lower_order_in_v); + + if (do_crr) { + amrex::Real qp = q; + if (ion_lev) { qp *= ion_lev[ip]; } + UpdateMomentumBorisWithRadiationReaction(ux[ip], uy[ip], uz[ip], + Exp, Eyp, Ezp, Bxp, + Byp, Bzp, qp, m, dt); + } else if (pusher_algo == ParticlePusherAlgo::Boris) { + amrex::Real qp = q; + if (ion_lev) { qp *= ion_lev[ip]; } + UpdateMomentumBoris( ux[ip], uy[ip], uz[ip], + Exp, Eyp, Ezp, Bxp, + Byp, Bzp, qp, m, dt); + } else if (pusher_algo == ParticlePusherAlgo::Vay) { + amrex::Real qp = q; + if (ion_lev){ qp *= ion_lev[ip]; } + UpdateMomentumVay( ux[ip], uy[ip], uz[ip], + Exp, Eyp, Ezp, Bxp, + Byp, Bzp, qp, m, dt); + } else if (pusher_algo == ParticlePusherAlgo::HigueraCary) { + amrex::Real qp = q; + if (ion_lev){ qp *= ion_lev[ip]; } + UpdateMomentumHigueraCary( ux[ip], uy[ip], uz[ip], + Exp, Eyp, Ezp, Bxp, + Byp, Bzp, qp, m, dt); + } else { + amrex::Abort("Unknown particle pusher"); + } + }); } } } @@ -1897,44 +1718,30 @@ PhysicalParticleContainer::ContinuousInjection (const RealBox& injection_box) AddPlasma(lev, injection_box); } -/* \brief Gather fields from FArrayBox exfab, eyfab, ezfab, bxfab, byfab, - * bzfab into arrays of fields on particles Exp, Eyp, Ezp, Bxp, Byp, Bzp. - * \param Exp-Bzp: fields on particles. - * \param exfab-bzfab: FAB of electric and magnetic fields for particles in pti - * \param ngE: number of guard cells for E - * \param e_is_nodal: 0 if E is staggered, 1 if E is nodal - * \param offset: index of first particle for which fields are gathered - * \param np_to_gather: number of particles onto which fields are gathered - * \param lev: level on which particles are located - * \param gather_lev: level from which particles gather fields (lev-1) for - particles in buffers. +/* \brief Perform the field gather and particle push operations in one fused kernel + * */ void -PhysicalParticleContainer::FieldGather (WarpXParIter& pti, - RealVector& Exp, - RealVector& Eyp, - RealVector& Ezp, - RealVector& Bxp, - RealVector& Byp, - RealVector& Bzp, - amrex::FArrayBox const * exfab, - amrex::FArrayBox const * eyfab, - amrex::FArrayBox const * ezfab, - amrex::FArrayBox const * bxfab, - amrex::FArrayBox const * byfab, - amrex::FArrayBox const * bzfab, - const int ngE, const int /*e_is_nodal*/, - const long offset, - const long np_to_gather, - int lev, - int gather_lev) +PhysicalParticleContainer::PushPX (WarpXParIter& pti, + amrex::FArrayBox const * exfab, + amrex::FArrayBox const * eyfab, + amrex::FArrayBox const * ezfab, + amrex::FArrayBox const * bxfab, + amrex::FArrayBox const * byfab, + amrex::FArrayBox const * bzfab, + const int ngE, const int /*e_is_nodal*/, + const long offset, + const long np_to_push, + int lev, int gather_lev, + amrex::Real dt, ScaleFields scaleFields, + DtType a_dt_type) { AMREX_ALWAYS_ASSERT_WITH_MESSAGE((gather_lev==(lev-1)) || (gather_lev==(lev )), "Gather buffers only work for lev-1"); // If no particles, do not do anything // If do_not_gather = 1 by user, do not do anything - if (np_to_gather == 0 || do_not_gather) return; + if (np_to_push == 0 || do_not_gather) return; // Get cell size on gather_lev const std::array<Real,3>& dx = WarpX::CellSize(std::max(gather_lev,0)); @@ -1953,6 +1760,7 @@ PhysicalParticleContainer::FieldGather (WarpXParIter& pti, box.grow(ngE); const auto getPosition = GetParticlePosition(pti, offset); + auto setPosition = SetParticlePosition(pti, offset); const auto getExternalE = GetExternalEField(pti, offset); const auto getExternalB = GetExternalBField(pti, offset); @@ -1966,63 +1774,107 @@ PhysicalParticleContainer::FieldGather (WarpXParIter& pti, const Dim3 lo = lbound(box); - // Depending on l_lower_in_v and WarpX::nox, call - // different versions of template function doGatherShapeN - if (WarpX::l_lower_order_in_v){ - if (WarpX::nox == 1){ - doGatherShapeN<1,1>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } else if (WarpX::nox == 2){ - doGatherShapeN<2,1>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } else if (WarpX::nox == 3){ - doGatherShapeN<3,1>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } - } else { - if (WarpX::nox == 1){ - doGatherShapeN<1,0>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } else if (WarpX::nox == 2){ - doGatherShapeN<2,0>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } else if (WarpX::nox == 3){ - doGatherShapeN<3,0>(getPosition, getExternalE, getExternalB, - Exp.dataPtr() + offset, Eyp.dataPtr() + offset, - Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, - Byp.dataPtr() + offset, Bzp.dataPtr() + offset, - exfab, eyfab, ezfab, bxfab, byfab, bzfab, - np_to_gather, dx, - xyzmin, lo, WarpX::n_rz_azimuthal_modes); - } + int l_lower_order_in_v = WarpX::l_lower_order_in_v; + int nox = WarpX::nox; + int n_rz_azimuthal_modes = WarpX::n_rz_azimuthal_modes; + + amrex::GpuArray<amrex::Real, 3> dx_arr = {dx[0], dx[1], dx[2]}; + amrex::GpuArray<amrex::Real, 3> xyzmin_arr = {xyzmin[0], xyzmin[1], xyzmin[2]}; + + amrex::Array4<const amrex::Real> const& ex_arr = exfab->array(); + amrex::Array4<const amrex::Real> const& ey_arr = eyfab->array(); + amrex::Array4<const amrex::Real> const& ez_arr = ezfab->array(); + amrex::Array4<const amrex::Real> const& bx_arr = bxfab->array(); + amrex::Array4<const amrex::Real> const& by_arr = byfab->array(); + amrex::Array4<const amrex::Real> const& bz_arr = bzfab->array(); + + amrex::IndexType const ex_type = exfab->box().ixType(); + amrex::IndexType const ey_type = eyfab->box().ixType(); + amrex::IndexType const ez_type = ezfab->box().ixType(); + amrex::IndexType const bx_type = bxfab->box().ixType(); + amrex::IndexType const by_type = byfab->box().ixType(); + amrex::IndexType const bz_type = bzfab->box().ixType(); + + auto& attribs = pti.GetAttribs(); + ParticleReal* const AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr(); + ParticleReal* const AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr(); + ParticleReal* const AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr(); + + auto copyAttribs = CopyParticleAttribs(pti, tmp_particle_data, offset); + int do_copy = (WarpX::do_back_transformed_diagnostics && + do_back_transformed_diagnostics && + (a_dt_type!=DtType::SecondHalf)); + + int* AMREX_RESTRICT ion_lev = nullptr; + if (do_field_ionization) { + ion_lev = pti.GetiAttribs(particle_icomps["ionization_level"]).dataPtr(); } -} + // Loop over the particles and update their momentum + const amrex::Real q = this->charge; + const amrex::Real m = this-> mass; + + const auto pusher_algo = WarpX::particle_pusher_algo; + const auto do_crr = do_classical_radiation_reaction; +#ifdef WARPX_QED + const auto do_sync = m_do_qed_quantum_sync; + amrex::Real t_chi_max = 0.0; + if (do_sync) t_chi_max = m_shr_p_qs_engine->get_ref_ctrl().chi_part_min; + + QuantumSynchrotronEvolveOpticalDepth evolve_opt; + amrex::ParticleReal* AMREX_RESTRICT p_optical_depth_QSR = nullptr; + const bool local_has_quantum_sync = has_quantum_sync(); + if (local_has_quantum_sync) { + evolve_opt = m_shr_p_qs_engine->build_evolve_functor(); + p_optical_depth_QSR = pti.GetAttribs(particle_comps["optical_depth_QSR"]).dataPtr(); + } +#endif + + amrex::ParallelFor( np_to_push, [=] AMREX_GPU_DEVICE (long ip) + { + amrex::ParticleReal xp, yp, zp; + getPosition(ip, xp, yp, zp); + + amrex::ParticleReal Exp = 0._rt, Eyp = 0._rt, Ezp = 0._rt; + getExternalE(ip, Exp, Eyp, Ezp); + + amrex::ParticleReal Bxp = 0._rt, Byp = 0._rt, Bzp = 0._rt; + getExternalB(ip, Bxp, Byp, Bzp); + + // first gather E and B to the particle positions + doGatherShapeN(xp, yp, zp, Exp, Eyp, Ezp, Bxp, Byp, Bzp, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + ex_type, ey_type, ez_type, bx_type, by_type, bz_type, + dx_arr, xyzmin_arr, lo, n_rz_azimuthal_modes, + nox, l_lower_order_in_v); + + scaleFields(xp, yp, zp, Exp, Eyp, Ezp, Bxp, Byp, Bzp); + +#ifdef WARPX_WED + if (local_has_quantum_sync) { + const ParticleReal px = m * ux[ip]; + const ParticleReal py = m * uy[ip]; + const ParticleReal pz = m * uz[ip]; + + bool has_event_happened = evolve_opt(px, py, pz, + Exp, Eyp, Ezp, + Bxp, Byp, Bzp, + dt, p_optical_depth_QSR[ip]); + } +#endif + + doParticlePush(getPosition, setPosition, copyAttribs, ip, + ux[ip+offset], uy[ip+offset], uz[ip+offset], + Exp, Eyp, Ezp, Bxp, Byp, Bzp, + ion_lev ? ion_lev[ip] : 0, + m, q, pusher_algo, do_crr, do_copy, +#ifdef WARPX_QED + do_sync, + t_chi_max, +#endif + dt); + }); +} void PhysicalParticleContainer::InitIonizationModule () @@ -2074,16 +1926,26 @@ PhysicalParticleContainer::InitIonizationModule () } IonizationFilterFunc -PhysicalParticleContainer::getIonizationFunc () +PhysicalParticleContainer::getIonizationFunc (const WarpXParIter& pti, + int lev, + int ngE, + const amrex::FArrayBox& Ex, + const amrex::FArrayBox& Ey, + const amrex::FArrayBox& Ez, + const amrex::FArrayBox& Bx, + const amrex::FArrayBox& By, + const amrex::FArrayBox& Bz) { WARPX_PROFILE("PPC::getIonizationFunc"); - return IonizationFilterFunc{ionization_energies.dataPtr(), + return IonizationFilterFunc(pti, lev, ngE, Ex, Ey, Ez, Bx, By, Bz, + v_galilean, + ionization_energies.dataPtr(), adk_prefactor.dataPtr(), adk_exp_prefactor.dataPtr(), adk_power.dataPtr(), particle_icomps["ionization_level"], - ion_atomic_number}; + ion_atomic_number); } #ifdef WARPX_QED |