diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Particles/Deposition/CurrentDeposition.H | 187 | ||||
-rw-r--r-- | Source/Particles/WarpXParticleContainer.cpp | 50 | ||||
-rw-r--r-- | Source/WarpX.cpp | 4 |
3 files changed, 222 insertions, 19 deletions
diff --git a/Source/Particles/Deposition/CurrentDeposition.H b/Source/Particles/Deposition/CurrentDeposition.H index efda97892..20493d8c6 100644 --- a/Source/Particles/Deposition/CurrentDeposition.H +++ b/Source/Particles/Deposition/CurrentDeposition.H @@ -176,4 +176,191 @@ void doDepositionShapeN(const Real * const xp, const Real * const yp, const Real ); } +// 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_shifted_shape_factor(Real* const sx, Real x_old, int j_now) {return 0;}; + +// Compute shape factor for order 1. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shifted_shape_factor <1> (Real* const sx, Real x_old, int j_now){ + int j = (int) x_old; + int i_shift = j - j_now; + Real xint = x_old - j; + sx[1+i_shift] = 1.0 - xint; + sx[2+i_shift] = xint; + return j; +} + +// Compute shape factor for order 2. +template <> +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int compute_shifted_shape_factor <2> (Real* const sx, Real x_old, int j_now){ + int j = (int) (x_old+0.5); + int i_shift = j - (j_now + 1); + Real xint = x_old - j; + sx[1+i_shift] = 0.5*(0.5-xint)*(0.5-xint); + sx[2+i_shift] = 0.75-xint*xint; + sx[3+i_shift] = 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_shifted_shape_factor <3> (Real* const sx, Real x_old, int j_now){ + int j = (int) x_old; + int i_shift = j - (j_now + 1); + Real xint = x_old - j; + sx[1+i_shift] = 1.0/6.0*(1.0-xint)*(1.0-xint)*(1.0-xint); + sx[2+i_shift] = 2.0/3.0-xint*xint*(1-xint/2.0); + sx[3+i_shift] = 2.0/3.0-(1-xint)*(1-xint)*(1.0-0.5*(1-xint)); + sx[4+i_shift] = 1.0/6.0*xint*xint*xint; + // index of the leftmost cell where particle deposits + return j-1; +} + +/* \brief Esirkepov Current Deposition for thread thread_num + * /param xp, yp, zp : Pointer to arrays of particle positions. + * \param wp : Pointer to array of particle weights. + * \param uxp uyp uzp : Pointer to arrays of particle momentum. + * \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. + * \param lo : Index lower bounds of domain. + * /param q : species charge. + */ +template <int depos_order> +void doEsirkepovDepositionShapeN(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, + 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 std::array<Real, 3> xyzmin, + const Dim3 lo, + const amrex::Real q) +{ + const Real dxi = 1.0/dx[0]; + const Real dyi = 1.0/dx[1]; + const Real dzi = 1.0/dx[2]; + const Real dtsdx0 = dt*dxi; + const Real dtsdy0 = dt*dyi; + const Real dtsdz0 = dt*dzi; + const Real invdtdx = 1.0/(dt*dx[1]*dx[2]); + const Real invdtdy = 1.0/(dt*dx[0]*dx[2]); + const Real invdtdz = 1.0/(dt*dx[0]*dx[1]); + + const Real xmin = xyzmin[0]; + const Real ymin = xyzmin[1]; + const Real zmin = xyzmin[2]; + const 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); + + // wqx, wqy wqz are particle current in each direction + const Real wq = q*wp[ip]; + const Real wqx = wq*invdtdx; + const Real wqy = wq*invdtdy; + const Real wqz = wq*invdtdz; + + // computes current position in grid units + const Real x_now = (xp[ip] - xmin)*dxi; + const Real y_now = (yp[ip] - ymin)*dyi; + const Real z_now = (zp[ip] - zmin)*dzi; + + // computes old position in grid units + const Real x_old = x_now - dtsdx0*uxp[ip]*gaminv; + const Real y_old = y_now - dtsdy0*uyp[ip]*gaminv; + const Real z_old = z_now - dtsdz0*uzp[ip]*gaminv; + + // Shape factor arrays + // Note that there are extra values above and below + // to possibly hold the factor for the old particle + // which can be at a different grid location. + Real AMREX_RESTRICT sx_now[depos_order + 3]; + Real AMREX_RESTRICT sy_now[depos_order + 3]; + Real AMREX_RESTRICT sz_now[depos_order + 3]; + Real AMREX_RESTRICT sx_old[depos_order + 3]; + Real AMREX_RESTRICT sy_old[depos_order + 3]; + Real AMREX_RESTRICT sz_old[depos_order + 3]; + + // --- Compute shape factors + // Compute shape factors for position as they are now and at old positions + // [jkl]_now: leftmost grid point that the particle touches + const int j_now = compute_shape_factor<depos_order>(sx_now+1, x_now); + const int k_now = compute_shape_factor<depos_order>(sy_now+1, y_now); + const int l_now = compute_shape_factor<depos_order>(sz_now+1, z_now); + + const int j_old = compute_shifted_shape_factor<depos_order>(sx_old, x_old, j_now); + const int k_old = compute_shifted_shape_factor<depos_order>(sy_old, y_old, k_now); + const int l_old = compute_shifted_shape_factor<depos_order>(sz_old, z_old, l_now); + + // computes min/max positions of current contributions + int djs = 1, dje = 1; + if (j_old < j_now) djs = 0; + if (j_old > j_now) dje = 0; + int dks = 1, dke = 1; + if (k_old < k_now) dks = 0; + if (k_old > k_now) dke = 0; + int dls = 1, dle = 1; + if (l_old < l_now) dls = 0; + if (l_old > l_now) dle = 0; + + std::cout << "JJJ " << depos_order << " " << lo.z << " " << l_now-1 << " " << zp[ip] << " " << zmin << " " << dx[2] << "\n"; + for (int l=dls; l<=depos_order+2-dle; l++){ + for (int k=dks; k<=depos_order+2-dke; k++){ + Real sdxi = 0.; + for (int j=djs; j<=depos_order+1-dje; j++){ + sdxi += wqx*(sx_old[j] - sx_now[j])*((sy_now[k] + 0.5*(sy_old[k] - sy_now[k]))*sz_now[l] + + (0.5*sy_now[k] + 1./3.*(sy_old[k] - sy_now[k]))*(sz_old[l] - sz_now[l])); + amrex::Gpu::Atomic::Add( &jx_arr(lo.x+j_now-1+j, lo.y+k_now-1+k, lo.z+l_now-1+l), sdxi); + } + } + } + + for (int l=dls; l<=depos_order+2-dle; l++){ + for (int j=djs; j<=depos_order+2-dje; j++){ + Real sdyj = 0.; + for (int k=dks; k<=depos_order+1-dke; k++){ + sdyj += wqy*(sy_old[k] - sy_now[k])*((sz_now[l] + 0.5*(sz_old[l] - sz_now[l]))*sx_now[l] + + (0.5*sz_now[l] + 1./3.*(sz_old[l] - sz_now[l]))*(sx_old[l] - sx_now[l])); + amrex::Gpu::Atomic::Add( &jy_arr(lo.x+j_now-1+j, lo.y+k_now-1+k, lo.z+l_now-1+l), sdyj); + } + } + } + + for (int k=dks; k<=depos_order+2-dke; k++){ + for (int j=djs; j<=depos_order+2-dje; j++){ + Real sdzk = 0.; + for (int l=dls; l<=depos_order+1-dle; l++){ + sdzk += wqz*(sz_old[l] - sz_now[l])*((sx_now[l] + 0.5*(sx_old[l] - sx_now[l]))*sy_now[k] + + (0.5*sx_now[l] + 1./3.*(sx_old[l] - sx_now[l]))*(sy_old[k] - sy_now[k])); + amrex::Gpu::Atomic::Add( &jz_arr(lo.x+j_now-1+j, lo.y+k_now-1+k, lo.z+l_now-1+l), sdzk); + } + } + } + } + ); + +} + #endif // CURRENTDEPOSITION_H_ diff --git a/Source/Particles/WarpXParticleContainer.cpp b/Source/Particles/WarpXParticleContainer.cpp index 7316dcc95..5a3f9242f 100644 --- a/Source/Particles/WarpXParticleContainer.cpp +++ b/Source/Particles/WarpXParticleContainer.cpp @@ -6,6 +6,7 @@ #include <AMReX_AmrParGDB.H> #include <WarpX_f.H> #include <WarpX.H> +#include <WarpXAlgorithmSelection.H> // Import low-level single-particle kernels #include <GetAndSetPosition.H> @@ -510,21 +511,40 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti, // Better for memory? worth trying? const Dim3 lo = lbound(tilebox); - 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, - 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, - 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, - xyzmin, lo, stagger_shift, q); + if (WarpX::current_deposition_algo == CurrentDepositionAlgo::Esirkepov) { + if (WarpX::nox == 1){ + doEsirkepovDepositionShapeN<1>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), + uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, + jz_arr, offset, np_to_depose, dt, dx, + xyzmin, lo, q); + } else if (WarpX::nox == 2){ + doEsirkepovDepositionShapeN<2>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), + uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, + jz_arr, offset, np_to_depose, dt, dx, + xyzmin, lo, q); + } else if (WarpX::nox == 3){ + doEsirkepovDepositionShapeN<3>(xp, yp, zp, wp.dataPtr(), uxp.dataPtr(), + uyp.dataPtr(), uzp.dataPtr(), jx_arr, jy_arr, + jz_arr, offset, np_to_depose, dt, dx, + xyzmin, lo, q); + } + } else { + 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, + 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, + 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, + xyzmin, lo, stagger_shift, q); + } } #ifndef AMREX_USE_GPU diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp index 08948227c..18d76c07e 100644 --- a/Source/WarpX.cpp +++ b/Source/WarpX.cpp @@ -492,10 +492,6 @@ WarpX::ReadParameters () pp.query("use_picsar_deposition", use_picsar_deposition); #endif current_deposition_algo = GetAlgorithmInteger(pp, "current_deposition"); - if (!use_picsar_deposition){ - AMREX_ALWAYS_ASSERT_WITH_MESSAGE( current_deposition_algo >= 2, - "if not use_picsar_deposition, cannot use Esirkepov deposition."); - } charge_deposition_algo = GetAlgorithmInteger(pp, "charge_deposition"); field_gathering_algo = GetAlgorithmInteger(pp, "field_gathering"); particle_pusher_algo = GetAlgorithmInteger(pp, "particle_pusher"); |