diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Evolve/WarpXEvolveEM.cpp | 16 | ||||
-rw-r--r-- | Source/Particles/Deposition/CurrentDeposition.H | 139 | ||||
-rw-r--r-- | Source/Particles/Gather/FieldGather.H | 171 | ||||
-rw-r--r-- | Source/Particles/Gather/Make.package | 3 | ||||
-rw-r--r-- | Source/Particles/Make.package | 2 | ||||
-rw-r--r-- | Source/Particles/MultiParticleContainer.H | 6 | ||||
-rw-r--r-- | Source/Particles/MultiParticleContainer.cpp | 8 | ||||
-rw-r--r-- | Source/Particles/PhysicalParticleContainer.H | 34 | ||||
-rw-r--r-- | Source/Particles/PhysicalParticleContainer.cpp | 178 | ||||
-rw-r--r-- | Source/Particles/ShapeFactors.H | 60 | ||||
-rw-r--r-- | Source/Particles/WarpXParticleContainer.H | 6 | ||||
-rw-r--r-- | Source/Particles/WarpXParticleContainer.cpp | 6 |
12 files changed, 493 insertions, 136 deletions
diff --git a/Source/Evolve/WarpXEvolveEM.cpp b/Source/Evolve/WarpXEvolveEM.cpp index 32a4747db..f1f7c698c 100644 --- a/Source/Evolve/WarpXEvolveEM.cpp +++ b/Source/Evolve/WarpXEvolveEM.cpp @@ -189,9 +189,9 @@ WarpX::EvolveEM (int numsteps) UpdateAuxilaryData(); for (int lev = 0; lev <= finest_level; ++lev) { - mypc->FieldGather(lev, - *Efield_aux[lev][0],*Efield_aux[lev][1],*Efield_aux[lev][2], - *Bfield_aux[lev][0],*Bfield_aux[lev][1],*Bfield_aux[lev][2]); + mypc->FieldGatherFortran(lev, + *Efield_aux[lev][0],*Efield_aux[lev][1],*Efield_aux[lev][2], + *Bfield_aux[lev][0],*Bfield_aux[lev][1],*Bfield_aux[lev][2]); } last_plot_file_step = step+1; @@ -241,11 +241,11 @@ WarpX::EvolveEM (int numsteps) UpdateAuxilaryData(); for (int lev = 0; lev <= finest_level; ++lev) { - mypc->FieldGather(lev, - *Efield_aux[lev][0],*Efield_aux[lev][1], - *Efield_aux[lev][2], - *Bfield_aux[lev][0],*Bfield_aux[lev][1], - *Bfield_aux[lev][2]); + mypc->FieldGatherFortran(lev, + *Efield_aux[lev][0],*Efield_aux[lev][1], + *Efield_aux[lev][2], + *Bfield_aux[lev][0],*Bfield_aux[lev][1], + *Bfield_aux[lev][2]); } if (write_plot_file) diff --git a/Source/Particles/Deposition/CurrentDeposition.H b/Source/Particles/Deposition/CurrentDeposition.H index 1db477b1d..b4531d3b3 100644 --- a/Source/Particles/Deposition/CurrentDeposition.H +++ b/Source/Particles/Deposition/CurrentDeposition.H @@ -1,52 +1,7 @@ #ifndef CURRENTDEPOSITION_H_ #define CURRENTDEPOSITION_H_ -using namespace amrex; - -// Compute shape factor and return index of leftmost cell where -// particle writes. -// Specialized templates are defined below for orders 1, 2 and 3. -template <int depos_order> -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -int compute_shape_factor(Real* const sx, Real xint); - -// Compute shape factor for order 1. -template <> -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -int compute_shape_factor <1> (Real* const sx, Real xmid){ - int j = (int) xmid; - Real xint = xmid-j; - sx[0] = 1.0 - xint; - sx[1] = xint; - return j; -} - -// Compute shape factor for order 2. -template <> -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -int compute_shape_factor <2> (Real* const sx, Real xmid){ - int j = (int) (xmid+0.5); - Real xint = xmid-j; - sx[0] = 0.5*(0.5-xint)*(0.5-xint); - sx[1] = 0.75-xint*xint; - sx[2] = 0.5*(0.5+xint)*(0.5+xint); - // index of the leftmost cell where particle deposits - return j-1; -} - -// Compute shape factor for order 3. -template <> -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -int compute_shape_factor <3> (Real* const sx, Real xmid){ - int j = (int) xmid; - Real xint = xmid-j; - sx[0] = 1.0/6.0*(1.0-xint)*(1.0-xint)*(1.0-xint); - sx[1] = 2.0/3.0-xint*xint*(1-xint/2.0); - sx[2] = 2.0/3.0-(1-xint)*(1-xint)*(1.0-0.5*(1-xint)); - sx[3] = 1.0/6.0*xint*xint*xint; - // index of the leftmost cell where particle deposits - return j-1; -} +#include "ShapeFactors.H" /* \brief Current Deposition for thread thread_num * /param xp, yp, zp : Pointer to arrays of particle positions. @@ -55,9 +10,7 @@ int compute_shape_factor <3> (Real* const sx, Real xmid){ * \param jx_arr : Array4 of current density, either full array or tile. * \param jy_arr : Array4 of current density, either full array or tile. * \param jz_arr : Array4 of current density, either full array or tile. - * \param offset : Index of first particle for which current is deposited * \param np_to_depose : Number of particles for which current is deposited. - Particles [offset,offset+np_tp_depose] deposit current. * \param dt : Time step for particle level * \param dx : 3D cell size * \param xyzmin : Physical lower bounds of domain. @@ -66,79 +19,83 @@ int compute_shape_factor <3> (Real* const sx, Real xmid){ * /param q : species charge. */ template <int depos_order> -void doDepositionShapeN(const Real * const xp, const Real * const yp, const Real * const zp, - const Real * const wp, const Real * const uxp, - const Real * const uyp, const Real * const uzp, - const amrex::Array4<amrex::Real>& jx_arr, - const amrex::Array4<amrex::Real>& jy_arr, +void doDepositionShapeN(const amrex::Real * const xp, + const amrex::Real * const yp, + const amrex::Real * const zp, + const amrex::Real * const wp, + const amrex::Real * const uxp, + const amrex::Real * const uyp, + const amrex::Real * const uzp, + const amrex::Array4<amrex::Real>& jx_arr, + const amrex::Array4<amrex::Real>& jy_arr, const amrex::Array4<amrex::Real>& jz_arr, - const long offset, const long np_to_depose, - const amrex::Real dt, const std::array<amrex::Real,3>& dx, + const long np_to_depose, const amrex::Real dt, + const std::array<amrex::Real,3>& dx, const std::array<Real, 3> xyzmin, - const Dim3 lo, + const amrex::Dim3 lo, const amrex::Real stagger_shift, const amrex::Real q) { - const Real dxi = 1.0/dx[0]; - const Real dzi = 1.0/dx[2]; - const Real dts2dx = 0.5*dt*dxi; - const Real dts2dz = 0.5*dt*dzi; + const amrex::Real dxi = 1.0/dx[0]; + const amrex::Real dzi = 1.0/dx[2]; + const amrex::Real dts2dx = 0.5*dt*dxi; + const amrex::Real dts2dz = 0.5*dt*dzi; #if (AMREX_SPACEDIM == 2) - const Real invvol = dxi*dzi; + const amrex::Real invvol = dxi*dzi; #else // (AMREX_SPACEDIM == 3) - const Real dyi = 1.0/dx[1]; - const Real dts2dy = 0.5*dt*dyi; - const Real invvol = dxi*dyi*dzi; + const amrex::Real dyi = 1.0/dx[1]; + const amrex::Real dts2dy = 0.5*dt*dyi; + const amrex::Real invvol = dxi*dyi*dzi; #endif - const Real xmin = xyzmin[0]; - const Real ymin = xyzmin[1]; - const Real zmin = xyzmin[2]; - const Real clightsq = 1.0/PhysConst::c/PhysConst::c; + const amrex::Real xmin = xyzmin[0]; + const amrex::Real ymin = xyzmin[1]; + const amrex::Real zmin = xyzmin[2]; + const amrex::Real clightsq = 1.0/PhysConst::c/PhysConst::c; // Loop over particles and deposit into jx_arr, jy_arr and jz_arr ParallelFor( np_to_depose, [=] AMREX_GPU_DEVICE (long ip) { // --- Get particle quantities - const Real gaminv = 1.0/std::sqrt(1.0 + uxp[ip]*uxp[ip]*clightsq - + uyp[ip]*uyp[ip]*clightsq - + uzp[ip]*uzp[ip]*clightsq); - const Real wq = q*wp[ip]; - const Real vx = uxp[ip]*gaminv; - const Real vy = uyp[ip]*gaminv; - const Real vz = uzp[ip]*gaminv; + const amrex::Real gaminv = 1.0/std::sqrt(1.0 + uxp[ip]*uxp[ip]*clightsq + + uyp[ip]*uyp[ip]*clightsq + + uzp[ip]*uzp[ip]*clightsq); + const amrex::Real wq = q*wp[ip]; + const amrex::Real vx = uxp[ip]*gaminv; + const amrex::Real vy = uyp[ip]*gaminv; + const amrex::Real vz = uzp[ip]*gaminv; // wqx, wqy wqz are particle current in each direction - const Real wqx = wq*invvol*vx; - const Real wqy = wq*invvol*vy; - const Real wqz = wq*invvol*vz; + const amrex::Real wqx = wq*invvol*vx; + const amrex::Real wqy = wq*invvol*vy; + const amrex::Real wqz = wq*invvol*vz; // --- Compute shape factors // x direction // Get particle position after 1/2 push back in position - const Real xmid = (xp[ip]-xmin)*dxi-dts2dx*vx; + const amrex::Real xmid = (xp[ip]-xmin)*dxi-dts2dx*vx; // Compute shape factors for node-centered quantities - Real AMREX_RESTRICT sx [depos_order + 1]; + amrex::Real AMREX_RESTRICT sx [depos_order + 1]; // j: leftmost grid point (node-centered) that the particle touches const int j = compute_shape_factor<depos_order>(sx, xmid); // Compute shape factors for cell-centered quantities - Real AMREX_RESTRICT sx0[depos_order + 1]; + amrex::Real AMREX_RESTRICT sx0[depos_order + 1]; // j0: leftmost grid point (cell-centered) that the particle touches const int j0 = compute_shape_factor<depos_order>(sx0, xmid-stagger_shift); #if (AMREX_SPACEDIM == 3) // y direction - const Real ymid= (yp[ip]-ymin)*dyi-dts2dy*vy; - Real AMREX_RESTRICT sy [depos_order + 1]; - const int k = compute_shape_factor<depos_order>(sy, ymid); - Real AMREX_RESTRICT sy0[depos_order + 1]; - const int k0 = compute_shape_factor<depos_order>(sy0, ymid-stagger_shift); + const amrex::Real ymid= (yp[ip]-ymin)*dyi-dts2dy*vy; + amrex::Real AMREX_RESTRICT sy [depos_order + 1]; + const int k = compute_shape_factor<depos_order>(sy, ymid); + amrex::Real AMREX_RESTRICT sy0[depos_order + 1]; + const int k0 = compute_shape_factor<depos_order>(sy0, ymid-stagger_shift); #endif // z direction - const Real zmid= (zp[ip]-zmin)*dzi-dts2dz*vz; - Real AMREX_RESTRICT sz [depos_order + 1]; - const int l = compute_shape_factor<depos_order>(sz, zmid); - Real AMREX_RESTRICT sz0[depos_order + 1]; - const int l0 = compute_shape_factor<depos_order>(sz0, zmid-stagger_shift); + const amrex::Real zmid= (zp[ip]-zmin)*dzi-dts2dz*vz; + amrex::Real AMREX_RESTRICT sz [depos_order + 1]; + const int l = compute_shape_factor<depos_order>(sz, zmid); + amrex::Real AMREX_RESTRICT sz0[depos_order + 1]; + const int l0 = compute_shape_factor<depos_order>(sz0, zmid-stagger_shift); // Deposit current into jx_arr, jy_arr and jz_arr #if (AMREX_SPACEDIM == 2) diff --git a/Source/Particles/Gather/FieldGather.H b/Source/Particles/Gather/FieldGather.H new file mode 100644 index 000000000..789c7f775 --- /dev/null +++ b/Source/Particles/Gather/FieldGather.H @@ -0,0 +1,171 @@ +#ifndef FIELDGATHER_H_ +#define FIELDGATHER_H_ + +#include "ShapeFactors.H" + +using namespace amrex; + +/* \brief Field gather for particles handled by thread thread_num + * /param xp, yp, zp : Pointer to arrays of particle positions. + * \param Exp, Eyp, Ezp: Pointer to array of electric field on particles. + * \param Bxp, Byp, Bzp: Pointer to array of magnetic field on particles. + * \param ex_arr ey_arr: Array4 of current density, either full array or tile. + * \param ez_arr bx_arr: Array4 of current density, either full array or tile. + * \param by_arr bz_arr: Array4 of current density, either full array or tile. + * \param np_to_gather : Number of particles for which current is deposited. + * \param dx : 3D cell size + * \param xyzmin : Physical lower bounds of domain. + * \param lo : Index lower bounds of domain. + * \param stagger_shift: 0 if nodal, 0.5 if staggered. + */ +template <int depos_order, int lower_in_v> +void doGatherShapeN(const Real * const xp, + const Real * const yp, + const Real * const zp, + Real * const Exp, Real * const Eyp, Real * const Ezp, + Real * const Bxp, Real * const Byp, Real * const Bzp, + const amrex::Array4<const amrex::Real>& ex_arr, + const amrex::Array4<const amrex::Real>& ey_arr, + const amrex::Array4<const amrex::Real>& ez_arr, + const amrex::Array4<const amrex::Real>& bx_arr, + const amrex::Array4<const amrex::Real>& by_arr, + const amrex::Array4<const amrex::Real>& bz_arr, + const long np_to_gather, + const std::array<amrex::Real,3>& dx, + const std::array<Real, 3> xyzmin, + const Dim3 lo, + const amrex::Real stagger_shift) +{ + const Real dxi = 1.0/dx[0]; + const Real dzi = 1.0/dx[2]; +#if (AMREX_SPACEDIM == 3) + const Real dyi = 1.0/dx[1]; +#endif + + const Real xmin = xyzmin[0]; + const Real ymin = xyzmin[1]; + const Real zmin = xyzmin[2]; + + // Loop over particles and gather fields from {e,b}{x,y,z}_arr to {E,B}{xyz}p. + ParallelFor( np_to_gather, + [=] AMREX_GPU_DEVICE (long ip) { + // --- Compute shape factors + // x direction + // Get particle position after 1/2 push back in position + const Real xmid = (xp[ip]-xmin)*dxi; + // Compute shape factors for node-centered quantities + Real AMREX_RESTRICT sx [depos_order + 1]; + // j: leftmost grid point (node-centered) that the particle touches + const int j = compute_shape_factor<depos_order>(sx, xmid); + // Compute shape factors for cell-centered quantities + Real AMREX_RESTRICT sx0[depos_order + 1 - lower_in_v]; + // j0: leftmost grid point (cell-centered) that the particle touches + const int j0 = compute_shape_factor<depos_order - lower_in_v>(sx0, xmid-stagger_shift); + +#if (AMREX_SPACEDIM == 3) + // y direction + const Real ymid= (yp[ip]-ymin)*dyi; + Real AMREX_RESTRICT sy [depos_order + 1]; + const int k = compute_shape_factor<depos_order>(sy, ymid); + Real AMREX_RESTRICT sy0[depos_order + 1 - lower_in_v]; + const int k0 = compute_shape_factor<depos_order-lower_in_v>(sy0, ymid-stagger_shift); +#endif + // z direction + const Real zmid= (zp[ip]-zmin)*dzi; + Real AMREX_RESTRICT sz [depos_order + 1]; + const int l = compute_shape_factor<depos_order>(sz, zmid); + Real AMREX_RESTRICT sz0[depos_order + 1 - lower_in_v]; + const int l0 = compute_shape_factor<depos_order - lower_in_v>(sz0, zmid-stagger_shift); + + // Deposit current into jx_arr, jy_arr and jz_arr + Exp[ip] = 0; + Eyp[ip] = 0; + Ezp[ip] = 0; + Bxp[ip] = 0; + Byp[ip] = 0; + Bzp[ip] = 0; +#if (AMREX_SPACEDIM == 2) + for (int iz=0; iz<=depos_order; iz++){ + for (int ix=0; ix<=depos_order; ix++){ + Eyp[ip] += sx[ix]*sz[iz]* + ey_arr(lo.x+j+ix, lo.y+l+iz, 0); + } + } + for (int iz=0; iz<=depos_order; iz++){ + for (int ix=0; ix<=depos_order-lower_in_v; ix++){ + Exp[ip] += sx0[ix]*sz[iz]* + ex_arr(lo.x+j0+ix, lo.y+l +iz, 0); + Bzp[ip] += sx0[ix]*sz[iz]* + bz_arr(lo.x+j0+ix, lo.y+l +iz, 0); + } + } + for (int iz=0; iz<=depos_order-lower_in_v; iz++){ + for (int ix=0; ix<=depos_order; ix++){ + Ezp[ip] += sx[ix]*sz0[iz]* + ez_arr(lo.x+j+ix, lo.y+l0 +iz, 0); + Bxp[ip] += sx[ix]*sz0[iz]* + bx_arr(lo.x+j+ix, lo.y+l0 +iz, 0); + } + } + for (int iz=0; iz<=depos_order-lower_in_v; iz++){ + for (int ix=0; ix<=depos_order-lower_in_v; ix++){ + Byp[ip] += sx0[ix]*sz0[iz]* + by_arr(lo.x+j0+ix, lo.y+l0+iz, 0); + } + } +#else // (AMREX_SPACEDIM == 3) + for (int iz=0; iz<=depos_order; iz++){ + for (int iy=0; iy<=depos_order; iy++){ + for (int ix=0; ix<=depos_order-lower_in_v; ix++){ + Exp[ip] += sx0[ix]*sy[iy]*sz[iz]* + ex_arr(lo.x+j0+ix, lo.y+k+iy, lo.z+l+iz); + } + } + } + for (int iz=0; iz<=depos_order; iz++){ + for (int iy=0; iy<=depos_order-lower_in_v; iy++){ + for (int ix=0; ix<=depos_order; ix++){ + Eyp[ip] += sx[ix]*sy0[iy]*sz[iz]* + ey_arr(lo.x+j+ix, lo.y+k0+iy, lo.z+l+iz); + } + } + } + for (int iz=0; iz<=depos_order-lower_in_v; iz++){ + for (int iy=0; iy<=depos_order; iy++){ + for (int ix=0; ix<=depos_order; ix++){ + Ezp[ip] += sx[ix]*sy[iy]*sz0[iz]* + ez_arr(lo.x+j+ix, lo.y+k+iy, lo.z+l0+iz); + } + } + } + + for (int iz=0; iz<=depos_order; iz++){ + for (int iy=0; iy<=depos_order-lower_in_v; iy++){ + for (int ix=0; ix<=depos_order-lower_in_v; ix++){ + Bzp[ip] += sx0[ix]*sy0[iy]*sz[iz]* + bz_arr(lo.x+j0+ix, lo.y+k0+iy, lo.z+l+iz); + } + } + } + for (int iz=0; iz<=depos_order-lower_in_v; iz++){ + for (int iy=0; iy<=depos_order; iy++){ + for (int ix=0; ix<=depos_order-lower_in_v; ix++){ + Byp[ip] += sx0[ix]*sy[iy]*sz0[iz]* + by_arr(lo.x+j0+ix, lo.y+k+iy, lo.z+l0+iz); + } + } + } + for (int iz=0; iz<=depos_order-lower_in_v; iz++){ + for (int iy=0; iy<=depos_order-lower_in_v; iy++){ + for (int ix=0; ix<=depos_order; ix++){ + Bxp[ip] += sx[ix]*sy0[iy]*sz0[iz]* + bx_arr(lo.x+j+ix, lo.y+k0+iy, lo.z+l0+iz); + } + } + } +#endif + } + ); +} + +#endif // FIELDGATHER_H_ diff --git a/Source/Particles/Gather/Make.package b/Source/Particles/Gather/Make.package new file mode 100644 index 000000000..10abfcaaf --- /dev/null +++ b/Source/Particles/Gather/Make.package @@ -0,0 +1,3 @@ +CEXE_headers += FieldGather.H +INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Particles/Gather +VPATH_LOCATIONS += $(WARPX_HOME)/Source/Particles/Gather diff --git a/Source/Particles/Make.package b/Source/Particles/Make.package index 2038472a1..db90de1dc 100644 --- a/Source/Particles/Make.package +++ b/Source/Particles/Make.package @@ -9,9 +9,11 @@ CEXE_headers += MultiParticleContainer.H CEXE_headers += WarpXParticleContainer.H CEXE_headers += RigidInjectedParticleContainer.H CEXE_headers += PhysicalParticleContainer.H +CEXE_headers += ShapeFactors.H include $(WARPX_HOME)/Source/Particles/Pusher/Make.package include $(WARPX_HOME)/Source/Particles/Deposition/Make.package +include $(WARPX_HOME)/Source/Particles/Gather/Make.package INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Particles VPATH_LOCATIONS += $(WARPX_HOME)/Source/Particles diff --git a/Source/Particles/MultiParticleContainer.H b/Source/Particles/MultiParticleContainer.H index 869126fef..76e3c44bc 100644 --- a/Source/Particles/MultiParticleContainer.H +++ b/Source/Particles/MultiParticleContainer.H @@ -84,9 +84,9 @@ public: /// Performs the field gather operation using the input fields E and B, for all the species /// in the MultiParticleContainer. This is the electromagnetic version of the field gather. /// - void 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); + void FieldGatherFortran (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); /// /// This evolves all the particles by one PIC time step, including current deposition, the diff --git a/Source/Particles/MultiParticleContainer.cpp b/Source/Particles/MultiParticleContainer.cpp index 9d39ec2f9..ab4400dad 100644 --- a/Source/Particles/MultiParticleContainer.cpp +++ b/Source/Particles/MultiParticleContainer.cpp @@ -239,12 +239,12 @@ MultiParticleContainer::sumParticleCharge (bool local) #endif // WARPX_DO_ELECTROSTATIC void -MultiParticleContainer::FieldGather (int lev, - const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, - const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) +MultiParticleContainer::FieldGatherFortran (int lev, + const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, + const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) { for (auto& pc : allcontainers) { - pc->FieldGather(lev, Ex, Ey, Ez, Bx, By, Bz); + pc->FieldGatherFortran(lev, Ex, Ey, Ez, Bx, By, Bz); } } diff --git a/Source/Particles/PhysicalParticleContainer.H b/Source/Particles/PhysicalParticleContainer.H index d55764682..ec9d7f98b 100644 --- a/Source/Particles/PhysicalParticleContainer.H +++ b/Source/Particles/PhysicalParticleContainer.H @@ -31,13 +31,33 @@ public: amrex::Real t, amrex::Real dt) override; #endif // WARPX_DO_ELECTROSTATIC - virtual void 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) final; + virtual void FieldGatherFortran(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) final; + + void 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 thread_num, + int lev, + int depos_lev); virtual void Evolve (int lev, const amrex::MultiFab& Ex, diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp index d47a7b220..357a187fd 100644 --- a/Source/Particles/PhysicalParticleContainer.cpp +++ b/Source/Particles/PhysicalParticleContainer.cpp @@ -6,7 +6,7 @@ #include <WarpX.H> #include <WarpXConst.H> #include <WarpXWrappers.h> - +#include <FieldGather.H> using namespace amrex; @@ -1055,9 +1055,9 @@ PhysicalParticleContainer::EvolveES (const Vector<std::array<std::unique_ptr<Mul #endif // WARPX_DO_ELECTROSTATIC void -PhysicalParticleContainer::FieldGather (int lev, - const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, - const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) +PhysicalParticleContainer::FieldGatherFortran (int lev, + const MultiFab& Ex, const MultiFab& Ey, const MultiFab& Ez, + const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz) { const std::array<Real,3>& dx = WarpX::CellSize(lev); @@ -1395,19 +1395,19 @@ PhysicalParticleContainer::Evolve (int lev, if (! do_not_push) { + const long np_gather = (cEx) ? nfine_gather : np; + + 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) // + BL_PROFILE_VAR_START(blp_pxr_fg); +#ifdef WARPX_RZ const int ll4symtry = false; long lvect_fieldgathe = 64; - const std::array<Real,3>& xyzmin_grid = WarpX::LowerCorner(box, lev); const int* ixyzmin_grid = box.loVect(); - - const long np_gather = (cEx) ? nfine_gather : np; - - BL_PROFILE_VAR_START(blp_pxr_fg); - warpx_geteb_energy_conserving( &np_gather, m_xp[thread_num].dataPtr(), @@ -1427,6 +1427,11 @@ PhysicalParticleContainer::Evolve (int lev, BL_TO_FORTRAN_ANYD(*bzfab), &ll4symtry, &WarpX::l_lower_order_in_v, &WarpX::do_nodal, &lvect_fieldgathe, &WarpX::field_gathering_algo); +#else + FieldGather(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp, + exfab, eyfab, ezfab, bxfab, byfab, bzfab, + Ex.nGrow(), e_is_nodal, 0, np_gather, thread_num, lev, lev); +#endif if (np_gather < np) { @@ -1435,13 +1440,14 @@ PhysicalParticleContainer::Evolve (int lev, const std::array<Real,3>& cxyzmin_grid = WarpX::LowerCorner(cbox, lev-1); const int* cixyzmin_grid = cbox.loVect(); - const FArrayBox* cexfab = &(*cEx)[pti]; - const FArrayBox* ceyfab = &(*cEy)[pti]; - const FArrayBox* cezfab = &(*cEz)[pti]; - const FArrayBox* cbxfab = &(*cBx)[pti]; - const FArrayBox* cbyfab = &(*cBy)[pti]; - const FArrayBox* cbzfab = &(*cBz)[pti]; - + // Data on the grid + FArrayBox const* cexfab = &(*cEx)[pti]; + FArrayBox const* ceyfab = &(*cEy)[pti]; + FArrayBox const* cezfab = &(*cEz)[pti]; + FArrayBox const* cbxfab = &(*cBx)[pti]; + FArrayBox const* cbyfab = &(*cBy)[pti]; + FArrayBox const* cbzfab = &(*cBz)[pti]; + if (WarpX::use_fdtd_nci_corr) { #if (AMREX_SPACEDIM == 2) @@ -1494,6 +1500,9 @@ PhysicalParticleContainer::Evolve (int lev, #endif } + // Field gather for particles in gather buffers +#ifdef WARPX_RZ + long ncrse = np - nfine_gather; warpx_geteb_energy_conserving( &ncrse, @@ -1514,6 +1523,15 @@ PhysicalParticleContainer::Evolve (int lev, BL_TO_FORTRAN_ANYD(*cbzfab), &ll4symtry, &WarpX::l_lower_order_in_v, &WarpX::do_nodal, &lvect_fieldgathe, &WarpX::field_gathering_algo); +#else + 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, + thread_num, lev, lev-1); +#endif } BL_PROFILE_VAR_STOP(blp_pxr_fg); @@ -2112,3 +2130,129 @@ PhysicalParticleContainer::ContinuousInjection(const RealBox& injection_box) const int lev=0; 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 thread_num: if using OpenMP, thread number + * \param lev: level on which particles are located + * \param gather_lev: level from which particles gather fields (lev-1) for + particles in buffers. + */ +void +PhysicalParticleContainer::FieldGather(WarpXParIter& pti, + RealVector& Exp, + RealVector& Eyp, + RealVector& Ezp, + RealVector& Bxp, + RealVector& Byp, + RealVector& Bzp, + FArrayBox const * exfab, + FArrayBox const * eyfab, + FArrayBox const * ezfab, + FArrayBox const * bxfab, + FArrayBox const * byfab, + FArrayBox const * bzfab, + const int ngE, const int e_is_nodal, + const long offset, + const long np_to_gather, + int thread_num, + int lev, + int gather_lev) +{ + 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 (np_to_gather == 0) return; + + const std::array<Real,3>& dx = WarpX::CellSize(std::max(gather_lev,0)); + const Real stagger_shift = e_is_nodal ? 0.0 : 0.5; + + // Get box =from which field is gathered. + Box box; + if (lev == gather_lev) { + box = pti.tilebox(); + } else { + const IntVect& ref_ratio = WarpX::RefRatio(gather_lev); + box = amrex::coarsen(pti.tilebox(),ref_ratio); + } + + box.grow(ngE); + + const Array4<const Real>& ex_arr = exfab->array(); + const Array4<const Real>& ey_arr = eyfab->array(); + const Array4<const Real>& ez_arr = ezfab->array(); + const Array4<const Real>& bx_arr = bxfab->array(); + const Array4<const Real>& by_arr = byfab->array(); + const Array4<const Real>& bz_arr = bzfab->array(); + + const Real * const AMREX_RESTRICT xp = m_xp[thread_num].dataPtr() + offset; + const Real * const AMREX_RESTRICT zp = m_zp[thread_num].dataPtr() + offset; + const Real * const AMREX_RESTRICT yp = m_yp[thread_num].dataPtr() + offset; + + // Lower corner of tile box physical domain + const std::array<Real, 3>& xyzmin = WarpX::LowerCorner(box, gather_lev); + + const Dim3 lo = lbound(box); + + if (WarpX::l_lower_order_in_v){ + if (WarpX::nox == 1){ + doGatherShapeN<1,1>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } else if (WarpX::nox == 2){ + doGatherShapeN<2,1>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } else if (WarpX::nox == 3){ + doGatherShapeN<3,1>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } + } else { + if (WarpX::nox == 1){ + doGatherShapeN<1,0>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } else if (WarpX::nox == 2){ + doGatherShapeN<2,0>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } else if (WarpX::nox == 3){ + doGatherShapeN<3,0>(xp, yp, zp, + Exp.dataPtr() + offset, Eyp.dataPtr() + offset, + Ezp.dataPtr() + offset, Bxp.dataPtr() + offset, + Byp.dataPtr() + offset, Bzp.dataPtr() + offset, + ex_arr, ey_arr, ez_arr, bx_arr, by_arr, bz_arr, + np_to_gather, dx, + xyzmin, lo, stagger_shift); + } + } +} diff --git a/Source/Particles/ShapeFactors.H b/Source/Particles/ShapeFactors.H new file mode 100644 index 000000000..6258f05af --- /dev/null +++ b/Source/Particles/ShapeFactors.H @@ -0,0 +1,60 @@ +#ifndef SHAPEFACTORS_H_ +#define SHAPEFACTORS_H_ + +using namespace amrex; + +// Compute shape factor and return index of leftmost cell where +// particle writes. +// Specialized templates are defined below for orders 1, 2 and 3. +template <int depos_order> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shape_factor(Real* const sx, Real xint) {return 0;}; + +// Compute shape factor for order 0. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shape_factor <0> (Real* const sx, Real xmid){ + int j = (int) (xmid+0.5); + sx[0] = 1.0; + return j; +} + +// Compute shape factor for order 1. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shape_factor <1> (Real* const sx, Real xmid){ + int j = (int) xmid; + Real xint = xmid-j; + sx[0] = 1.0 - xint; + sx[1] = xint; + return j; +} + +// Compute shape factor for order 2. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shape_factor <2> (Real* const sx, Real xmid){ + int j = (int) (xmid+0.5); + Real xint = xmid-j; + sx[0] = 0.5*(0.5-xint)*(0.5-xint); + sx[1] = 0.75-xint*xint; + sx[2] = 0.5*(0.5+xint)*(0.5+xint); + // index of the leftmost cell where particle deposits + return j-1; +} + +// Compute shape factor for order 3. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shape_factor <3> (Real* const sx, Real xmid){ + int j = (int) xmid; + Real xint = xmid-j; + sx[0] = 1.0/6.0*(1.0-xint)*(1.0-xint)*(1.0-xint); + sx[1] = 2.0/3.0-xint*xint*(1-xint/2.0); + sx[2] = 2.0/3.0-(1-xint)*(1-xint)*(1.0-0.5*(1-xint)); + sx[3] = 1.0/6.0*xint*xint*xint; + // index of the leftmost cell where particle deposits + return j-1; +} + +#endif // SHAPEFACTORS_H_ diff --git a/Source/Particles/WarpXParticleContainer.H b/Source/Particles/WarpXParticleContainer.H index 662b2e1b8..1b2a06171 100644 --- a/Source/Particles/WarpXParticleContainer.H +++ b/Source/Particles/WarpXParticleContainer.H @@ -103,9 +103,9 @@ public: virtual void FieldGatherES (const amrex::Vector<std::array<std::unique_ptr<amrex::MultiFab>, 3> >& E, const amrex::Vector<std::unique_ptr<amrex::FabArray<amrex::BaseFab<int> > > >& masks) {} - virtual void 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) {} + virtual void FieldGatherFortran (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) {} #ifdef WARPX_DO_ELECTROSTATIC virtual void EvolveES (const amrex::Vector<std::array<std::unique_ptr<amrex::MultiFab>, 3> >& E, diff --git a/Source/Particles/WarpXParticleContainer.cpp b/Source/Particles/WarpXParticleContainer.cpp index a20f0035e..89f233b2c 100644 --- a/Source/Particles/WarpXParticleContainer.cpp +++ b/Source/Particles/WarpXParticleContainer.cpp @@ -532,17 +532,17 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, if (WarpX::nox == 1){ doDepositionShapeN<1>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, - jz_arr, offset, np_to_depose, dt, dx, + jz_arr, np_to_depose, dt, dx, xyzmin, lo, stagger_shift, q); } else if (WarpX::nox == 2){ doDepositionShapeN<2>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, - jz_arr, offset, np_to_depose, dt, dx, + jz_arr, np_to_depose, dt, dx, xyzmin, lo, stagger_shift, q); } else if (WarpX::nox == 3){ doDepositionShapeN<3>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, - jz_arr, offset, np_to_depose, dt, dx, + jz_arr, np_to_depose, dt, dx, xyzmin, lo, stagger_shift, q); } } |