diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Diagnostics/FieldIO.H | 5 | ||||
-rw-r--r-- | Source/Diagnostics/FieldIO.cpp | 31 | ||||
-rw-r--r-- | Source/Diagnostics/WarpXIO.cpp | 23 | ||||
-rw-r--r-- | Source/Filter/BilinearFilter.H | 26 | ||||
-rw-r--r-- | Source/Filter/BilinearFilter.cpp | 156 | ||||
-rw-r--r-- | Source/Filter/Make.package | 3 | ||||
-rw-r--r-- | Source/Filter/filter_module.F90 | 87 | ||||
-rw-r--r-- | Source/FortranInterface/WarpX_f.H | 6 | ||||
-rw-r--r-- | Source/Initialization/WarpXInitData.cpp | 15 | ||||
-rw-r--r-- | Source/Parallelization/WarpXComm.cpp | 69 | ||||
-rw-r--r-- | Source/WarpX.H | 10 | ||||
-rw-r--r-- | Source/WarpX.cpp | 153 |
12 files changed, 372 insertions, 212 deletions
diff --git a/Source/Diagnostics/FieldIO.H b/Source/Diagnostics/FieldIO.H index fc3aa9672..121fb9374 100644 --- a/Source/Diagnostics/FieldIO.H +++ b/Source/Diagnostics/FieldIO.H @@ -75,4 +75,9 @@ getInterpolatedVector( const int r_ratio, const Real* dx, const int ngrow ); +coarsenCellCenteredFields( + Vector<MultiFab>& coarse_mf, Vector<Geometry>& coarse_geom, + const Vector<MultiFab>& source_mf, const Vector<Geometry>& source_geom, + int coarse_ratio, int finest_level ); + #endif diff --git a/Source/Diagnostics/FieldIO.cpp b/Source/Diagnostics/FieldIO.cpp index 03754404b..965324d02 100644 --- a/Source/Diagnostics/FieldIO.cpp +++ b/Source/Diagnostics/FieldIO.cpp @@ -298,7 +298,36 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames, } BL_ASSERT(dcomp == ncomp); - } // end loop over levels of refinement + + } // end loop over levels of refinement + +}; + +/** \brief Reduce the size of all the fields in `source_mf` + * by `coarse_ratio` and store the results in `coarse_mf`. + * Calculate the corresponding coarse Geometry from `source_geom` + * and store the results in `coarse_geom` */ +void +coarsenCellCenteredFields( + Vector<MultiFab>& coarse_mf, Vector<Geometry>& coarse_geom, + const Vector<MultiFab>& source_mf, const Vector<Geometry>& source_geom, + int coarse_ratio, int finest_level ) +{ + // Check that the Vectors to be filled have an initial size of 0 + AMREX_ALWAYS_ASSERT( coarse_mf.size()==0 ); + AMREX_ALWAYS_ASSERT( coarse_geom.size()==0 ); + + // Fill the vectors with one element per level + int ncomp = source_mf[0].nComp(); + for (int lev=0; lev<=finest_level; lev++) { + AMREX_ALWAYS_ASSERT( source_mf[lev].is_cell_centered() ); + + coarse_geom.push_back(amrex::coarsen( source_geom[lev], IntVect(coarse_ratio))); + + BoxArray small_ba = amrex::coarsen(source_mf[lev].boxArray(), coarse_ratio); + coarse_mf.push_back( MultiFab(small_ba, source_mf[lev].DistributionMap(), ncomp, 0) ); + average_down(source_mf[lev], coarse_mf[lev], 0, ncomp, IntVect(coarse_ratio)); + } }; diff --git a/Source/Diagnostics/WarpXIO.cpp b/Source/Diagnostics/WarpXIO.cpp index 1551a7df6..ee1991c21 100644 --- a/Source/Diagnostics/WarpXIO.cpp +++ b/Source/Diagnostics/WarpXIO.cpp @@ -470,13 +470,26 @@ WarpX::WritePlotFile () const const std::string& plotfilename = amrex::Concatenate(plot_file,istep[0]); amrex::Print() << " Writing plotfile " << plotfilename << "\n"; - // Average the fields from the simulation to the cell centers + // Average the fields from the simulation grid to the cell centers const int ngrow = 0; Vector<std::string> varnames; // Name of the written fields // mf_avg will contain the averaged, cell-centered fields Vector<MultiFab> mf_avg; WarpX::AverageAndPackFields( varnames, mf_avg, ngrow ); + // Coarsen the fields, if requested by the user + Vector<const MultiFab*> output_mf; // will point to the data to be written + Vector<MultiFab> coarse_mf; // will remain empty if there is no coarsening + Vector<Geometry> output_geom; + if (plot_coarsening_ratio != 1) { + coarsenCellCenteredFields( coarse_mf, output_geom, mf_avg, Geom(), + plot_coarsening_ratio, finest_level ); + output_mf = amrex::GetVecOfConstPtrs(coarse_mf); + } else { // No averaging necessary, simply point to mf_avg + output_mf = amrex::GetVecOfConstPtrs(mf_avg); + output_geom = Geom(); + } + // Write the fields contained in `mf_avg`, and corresponding to the // names `varnames`, into a plotfile. // Prepare extra directory (filled later), for the raw fields @@ -484,11 +497,9 @@ WarpX::WritePlotFile () const VisMF::Header::Version current_version = VisMF::GetHeaderVersion(); VisMF::SetHeaderVersion(plotfile_headerversion); if (plot_raw_fields) rfs.emplace_back("raw_fields"); - amrex::WriteMultiLevelPlotfile( - plotfilename, finest_level+1, - amrex::GetVecOfConstPtrs(mf_avg), - varnames, Geom(), t_new[0], istep, - refRatio(), + amrex::WriteMultiLevelPlotfile(plotfilename, finest_level+1, + output_mf, varnames, output_geom, + t_new[0], istep, refRatio(), "HyperCLaw-V1.1", "Level_", "Cell", diff --git a/Source/Filter/BilinearFilter.H b/Source/Filter/BilinearFilter.H new file mode 100644 index 000000000..f94f4467d --- /dev/null +++ b/Source/Filter/BilinearFilter.H @@ -0,0 +1,26 @@ +#include <AMReX_MultiFab.H> +#include <AMReX_Vector.H> + +#ifndef WARPX_FILTER_H_ +#define WARPX_FILTER_H_ + +class BilinearFilter +{ +public: + BilinearFilter () = default; + + void ComputeStencils(); + void ApplyStencil(amrex::MultiFab& dstmf, const amrex::MultiFab& srcmf, int scomp=0, int dcomp=0, int ncomp=10000); + + amrex::IntVect npass_each_dir; + amrex::IntVect stencil_length_each_dir; + +private: + + void Filter(const amrex::Box& tbx, amrex::FArrayBox const& tmpfab, amrex::FArrayBox &dstfab, int scomp, int dcomp, int ncomp); + + amrex::Vector<amrex::Real> stencil_x, stencil_y, stencil_z; + + amrex::Dim3 slen; +}; +#endif diff --git a/Source/Filter/BilinearFilter.cpp b/Source/Filter/BilinearFilter.cpp new file mode 100644 index 000000000..17857a416 --- /dev/null +++ b/Source/Filter/BilinearFilter.cpp @@ -0,0 +1,156 @@ +#include <WarpX.H> +#include <BilinearFilter.H> +#include <WarpX_f.H> + +#ifdef _OPENMP +#include <omp.h> +#endif + +using namespace amrex; + +namespace { +void compute_stencil(Vector<Real> &stencil, int npass){ + Vector<Real> old_s(1+npass,0.); + Vector<Real> new_s(1+npass,0.); + + old_s[0] = 1.; + int jmax = 1; + amrex::Real loc; + // Convolve the filter with itself npass times + for(int ipass=1; ipass<npass+1; ipass++){ + // element 0 has to be treated in its own way + new_s[0] = 0.5 * old_s[0]; + if (1<jmax) new_s[0] += 0.5 * old_s[1]; + loc = 0.; + // For each element j, apply the filter to + // old_s to get new_s[j]. loc stores the tmp + // filtered value. + for(int j=1; j<jmax+1; j++){ + loc = 0.5 * old_s[j]; + loc += 0.25 * old_s[j-1]; + if (j<jmax) loc += 0.25 * old_s[j+1]; + new_s[j] = loc; + } + // copy new_s into old_s + old_s = new_s; + // extend the stencil length for next iteration + jmax += 1; + } + // we use old_s here to make sure the stencil + // is corrent even when npass = 0 + stencil = old_s; + stencil[0] *= 0.5; // because we will use it twice +} +} + +void BilinearFilter::ComputeStencils(){ + BL_PROFILE("BilinearFilter::ComputeStencils()"); + stencil_length_each_dir = npass_each_dir; + stencil_length_each_dir += 1.; +#if (AMREX_SPACEDIM == 3) + // npass_each_dir = npass_x npass_y npass_z + stencil_x.resize( 1 + npass_each_dir[0] ); + stencil_y.resize( 1 + npass_each_dir[1] ); + stencil_z.resize( 1 + npass_each_dir[2] ); + compute_stencil(stencil_x, npass_each_dir[0]); + compute_stencil(stencil_y, npass_each_dir[1]); + compute_stencil(stencil_z, npass_each_dir[2]); +#elif (AMREX_SPACEDIM == 2) + // npass_each_dir = npass_x npass_z + stencil_x.resize( 1 + npass_each_dir[0] ); + stencil_z.resize( 1 + npass_each_dir[1] ); + compute_stencil(stencil_x, npass_each_dir[0]); + compute_stencil(stencil_z, npass_each_dir[1]); +#endif + slen = stencil_length_each_dir.dim3(); +#if (AMREX_SPACEDIM == 2) + slen.z = 1; +#endif +} + + +void +BilinearFilter::ApplyStencil (MultiFab& dstmf, const MultiFab& srcmf, int scomp, int dcomp, int ncomp) +{ + BL_PROFILE("BilinearFilter::ApplyStencil()"); + ncomp = std::min(ncomp, srcmf.nComp()); +#ifdef _OPENMP +#pragma omp parallel +#endif + { + FArrayBox tmpfab; + for (MFIter mfi(dstmf,true); mfi.isValid(); ++mfi){ + const auto& srcfab = srcmf[mfi]; + auto& dstfab = dstmf[mfi]; + const Box& tbx = mfi.growntilebox(); + const Box& gbx = amrex::grow(tbx,stencil_length_each_dir-1); + // tmpfab has enough ghost cells for the stencil + tmpfab.resize(gbx,ncomp); + tmpfab.setVal(0.0, gbx, 0, ncomp); + // Copy values in srcfab into tmpfab + const Box& ibx = gbx & srcfab.box(); + tmpfab.copy(srcfab, ibx, scomp, ibx, 0, ncomp); + // Apply filter + Filter(tbx, tmpfab, dstfab, 0, dcomp, ncomp); + } + } +} + +void BilinearFilter::Filter (const Box& tbx, FArrayBox const& tmpfab, FArrayBox &dstfab, + int scomp, int dcomp, int ncomp) +{ + const auto lo = amrex::lbound(tbx); + const auto hi = amrex::ubound(tbx); + const auto tmp = tmpfab.array(); + const auto dst = dstfab.array(); + // tmp and dst are of type Array4 (Fortran ordering) + amrex::Real const* AMREX_RESTRICT sx = stencil_x.data(); + amrex::Real const* AMREX_RESTRICT sy = stencil_y.data(); + amrex::Real const* AMREX_RESTRICT sz = stencil_z.data(); + for (int n = 0; n < ncomp; ++n) { + // Set dst value to 0. + for (int k = lo.z; k <= hi.z; ++k) { + for (int j = lo.y; j <= hi.y; ++j) { + for (int i = lo.x; i <= hi.x; ++i) { + dst(i,j,k,dcomp+n) = 0.0; + } + } + } + // 3 nested loop on 3D stencil + for (int iz=0; iz < slen.z; ++iz){ + for (int iy=0; iy < slen.y; ++iy){ + for (int ix=0; ix < slen.x; ++ix){ +#if (AMREX_SPACEDIM == 3) + Real sss = sx[ix]*sy[iy]*sz[iz]; +#else + Real sss = sx[ix]*sz[iy]; +#endif + // 3 nested loop on 3D array + for (int k = lo.z; k <= hi.z; ++k) { + for (int j = lo.y; j <= hi.y; ++j) { + AMREX_PRAGMA_SIMD + for (int i = lo.x; i <= hi.x; ++i) { +#if (AMREX_SPACEDIM == 3) + dst(i,j,k,dcomp+n) += sss*(tmp(i-ix,j-iy,k-iz,scomp+n) + +tmp(i+ix,j-iy,k-iz,scomp+n) + +tmp(i-ix,j+iy,k-iz,scomp+n) + +tmp(i+ix,j+iy,k-iz,scomp+n) + +tmp(i-ix,j-iy,k+iz,scomp+n) + +tmp(i+ix,j-iy,k+iz,scomp+n) + +tmp(i-ix,j+iy,k+iz,scomp+n) + +tmp(i+ix,j+iy,k+iz,scomp+n)); +#else + dst(i,j,k,dcomp+n) += sss*(tmp(i-ix,j-iy,k,scomp+n) + +tmp(i+ix,j-iy,k,scomp+n) + +tmp(i-ix,j+iy,k,scomp+n) + +tmp(i+ix,j+iy,k,scomp+n)); +#endif + } + } + } + } + } + } + } +} + diff --git a/Source/Filter/Make.package b/Source/Filter/Make.package index 56c0e7852..36e74bfb0 100644 --- a/Source/Filter/Make.package +++ b/Source/Filter/Make.package @@ -1,4 +1,5 @@ -F90EXE_sources += filter_module.F90 +CEXE_sources += BilinearFilter.cpp +CEXE_headers += BilinearFilter.H INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Filter VPATH_LOCATIONS += $(WARPX_HOME)/Source/Filter diff --git a/Source/Filter/filter_module.F90 b/Source/Filter/filter_module.F90 deleted file mode 100644 index ea87be7ca..000000000 --- a/Source/Filter/filter_module.F90 +++ /dev/null @@ -1,87 +0,0 @@ -module warpx_filter_module - - use iso_c_binding - use amrex_fort_module, only : rt => amrex_real - use amrex_constants_module, only : fourth, eighth - - implicit none - -contains - - subroutine warpx_filter_3d(lo, hi, src, slo, shi, dst, dlo, dhi, nc) & - bind(c, name='warpx_filter_3d') - integer, intent(in), value :: nc - integer, dimension(3), intent(in) :: lo, hi, dlo, dhi, slo, shi - real(rt), intent(inout) :: dst(dlo(1):dhi(1), dlo(2):dhi(2), dlo(3):dhi(3),nc) - real(rt), intent(in ) :: src(slo(1):shi(1), slo(2):shi(2), slo(3):shi(3),nc) - - real(rt), parameter :: sixteenth = 1.d0/16.d0 - real(rt), parameter :: thirtysecond = 1.d0/32.d0 - real(rt), parameter :: sixtyfourth = 1.d0/64.d0 - integer :: i,j,k,c - - do c = 1, nc - do k = lo(3), hi(3) - do j = lo(2), hi(2) - do i = lo(1), hi(1) - dst(i,j,k,c) = sixtyfourth*(src(i-1,j-1,k-1,c) & - & +src(i+1,j-1,k-1,c) & - & +src(i-1,j+1,k-1,c) & - & +src(i+1,j+1,k-1,c) & - & +src(i-1,j-1,k+1,c) & - & +src(i+1,j-1,k+1,c) & - & +src(i-1,j+1,k+1,c) & - & +src(i+1,j+1,k+1,c)) & - + thirtysecond*(src(i-1,j-1,k ,c) & - & +src(i+1,j-1,k ,c) & - & +src(i-1,j+1,k ,c) & - & +src(i+1,j+1,k ,c) & - & +src(i-1,j ,k-1,c) & - & +src(i+1,j ,k-1,c) & - & +src(i-1,j ,k+1,c) & - & +src(i+1,j ,k+1,c) & - & +src(i ,j-1,k-1,c) & - & +src(i ,j+1,k-1,c) & - & +src(i ,j-1,k+1,c) & - & +src(i ,j+1,k+1,c)) & - + sixteenth *(src(i-1,j ,k ,c) & - & +src(i+1,j ,k ,c) & - & +src(i ,j-1,k ,c) & - & +src(i ,j+1,k ,c) & - & +src(i ,j ,k-1,c) & - & +src(i ,j ,k+1,c)) & - + eighth * src(i ,j ,k ,c) - end do - end do - end do - end do - end subroutine warpx_filter_3d - - subroutine warpx_filter_2d(lo, hi, src, slo, shi, dst, dlo, dhi, nc) & - bind(c, name='warpx_filter_2d') - integer, intent(in), value :: nc - integer, dimension(2), intent(in) :: lo, hi, dlo, dhi, slo, shi - real(rt), intent(inout) :: dst(dlo(1):dhi(1), dlo(2):dhi(2), nc) - real(rt), intent(in ) :: src(slo(1):shi(1), slo(2):shi(2), nc) - - real(rt), parameter :: sixteenth = 1.d0/16.d0 - integer :: i,j,comp - - do comp = 1, nc - do j = lo(2), hi(2) - do i = lo(1), hi(1) - dst(i, j, comp) = sixteenth*(src(i-1,j-1,comp) & - & +src(i+1,j-1,comp) & - & +src(i-1,j+1,comp) & - & +src(i+1,j+1,comp)) & - + eighth *(src(i ,j-1,comp) & - & +src(i ,j+1,comp) & - & +src(i-1,j ,comp) & - & +src(i+1,j ,comp)) & - + fourth * src(i ,j ,comp) - end do - end do - end do - end subroutine warpx_filter_2d - -end module warpx_filter_module diff --git a/Source/FortranInterface/WarpX_f.H b/Source/FortranInterface/WarpX_f.H index ba9c4b044..1ccf82f87 100644 --- a/Source/FortranInterface/WarpX_f.H +++ b/Source/FortranInterface/WarpX_f.H @@ -40,7 +40,6 @@ #define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_3d #define WRPX_LORENTZ_TRANSFORM_Z warpx_lorentz_transform_z -#define WRPX_FILTER warpx_filter_3d #define WRPX_COPY_SLICE warpx_copy_slice_3d #define WRPX_PXR_NCI_CORR_INIT init_godfrey_filter_coeffs #define WRPX_PXR_GODFREY_FILTER apply_godfrey_filter_z_3d @@ -71,7 +70,6 @@ #define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_2d #define WRPX_LORENTZ_TRANSFORM_Z warpx_lorentz_transform_z -#define WRPX_FILTER warpx_filter_2d #define WRPX_COPY_SLICE warpx_copy_slice_2d #define WRPX_PXR_NCI_CORR_INIT init_godfrey_filter_coeffs #define WRPX_PXR_GODFREY_FILTER apply_godfrey_filter_z_2d @@ -450,10 +448,6 @@ extern "C" const BL_FORT_FAB_ARG_ANYD(fine), const int* ncomp); - void WRPX_FILTER (const int* lo, const int* hi, - const amrex_real*, const int*, const int*, - amrex_real*, const int*, const int*, int); - void WRPX_PXR_NCI_CORR_INIT(amrex::Real*, amrex::Real*, const int, const amrex::Real, const int); diff --git a/Source/Initialization/WarpXInitData.cpp b/Source/Initialization/WarpXInitData.cpp index ff5442b00..9190b5a61 100644 --- a/Source/Initialization/WarpXInitData.cpp +++ b/Source/Initialization/WarpXInitData.cpp @@ -6,6 +6,7 @@ #include <WarpX.H> #include <WarpX_f.H> +#include <BilinearFilter.H> #ifdef BL_USE_SENSEI_INSITU #include <AMReX_AmrMeshInSituBridge.H> @@ -21,7 +22,7 @@ WarpX::InitData () if (restart_chkfile.empty()) { ComputeDt(); - InitFromScratch(); + InitFromScratch(); } else { @@ -38,6 +39,10 @@ WarpX::InitData () WarpX::InitNCICorrector(); } + if (WarpX::use_filter) { + WarpX::InitFilter(); + } + BuildBufferMasks(); InitDiagnostics(); @@ -178,6 +183,14 @@ WarpX::InitNCICorrector () } void +WarpX::InitFilter (){ + if (WarpX::use_filter){ + WarpX::bilinear_filter.npass_each_dir = WarpX::filter_npass_each_dir; + WarpX::bilinear_filter.ComputeStencils(); + } +} + +void WarpX::PostRestart () { #ifdef WARPX_USE_PSATD diff --git a/Source/Parallelization/WarpXComm.cpp b/Source/Parallelization/WarpXComm.cpp index 09767c265..28971eb0c 100644 --- a/Source/Parallelization/WarpXComm.cpp +++ b/Source/Parallelization/WarpXComm.cpp @@ -1,4 +1,3 @@ - #include <WarpX.H> #include <WarpX_f.H> @@ -381,35 +380,42 @@ WarpX::SyncCurrent () if (WarpX::use_filter) { for (int lev = 0; lev <= finest_level; ++lev) { IntVect ng = current_fp[lev][0]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; for (int idim = 0; idim < 3; ++idim) { + // Create new MultiFab j_jp with enough guard cells for the + // (potentially large) stencil of the multi-pass bilinear filter. j_fp[lev][idim].reset(new MultiFab(current_fp[lev][idim]->boxArray(), current_fp[lev][idim]->DistributionMap(), 1, ng)); - applyFilter(*j_fp[lev][idim], *current_fp[lev][idim]); + // Apply the filter to current_fp, store the result in j_fp. + bilinear_filter.ApplyStencil(*j_fp[lev][idim], *current_fp[lev][idim]); + // Then swap j_fp and current_fp std::swap(j_fp[lev][idim], current_fp[lev][idim]); + // At this point, current_fp may have false values close to the + // edges of each FAB. This will be solved with a SumBoundary later. + // j_fp contains the exact MultiFab current_fp before this step. } } for (int lev = 1; lev <= finest_level; ++lev) { IntVect ng = current_cp[lev][0]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; for (int idim = 0; idim < 3; ++idim) { j_cp[lev][idim].reset(new MultiFab(current_cp[lev][idim]->boxArray(), current_cp[lev][idim]->DistributionMap(), 1, ng)); - applyFilter(*j_cp[lev][idim], *current_cp[lev][idim]); + bilinear_filter.ApplyStencil(*j_cp[lev][idim], *current_cp[lev][idim]); std::swap(j_cp[lev][idim], current_cp[lev][idim]); } } for (int lev = 1; lev <= finest_level; ++lev) { if (current_buf[lev][0]) { IntVect ng = current_buf[lev][0]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; for (int idim = 0; idim < 3; ++idim) { j_buf[lev][idim].reset(new MultiFab(current_buf[lev][idim]->boxArray(), current_buf[lev][idim]->DistributionMap(), 1, ng)); - applyFilter(*j_buf[lev][idim], *current_buf[lev][idim]); + bilinear_filter.ApplyStencil(*j_buf[lev][idim], *current_buf[lev][idim]); std::swap(*j_buf[lev][idim], *current_buf[lev][idim]); } } @@ -420,6 +426,9 @@ WarpX::SyncCurrent () for (int lev = 0; lev <= finest_level; ++lev) { const auto& period = Geom(lev).periodicity(); + // When using a bilinear filter with many passes, current_fp has + // temporarily more ghost cells here, so that its value inside + // the domain is correct at the end of this stage. current_fp[lev][0]->SumBoundary(period); current_fp[lev][1]->SumBoundary(period); current_fp[lev][2]->SumBoundary(period); @@ -461,8 +470,14 @@ WarpX::SyncCurrent () for (int lev = 0; lev <= finest_level; ++lev) { for (int idim = 0; idim < 3; ++idim) { + // swap j_fp and current_fp so that j_fp has correct values inside + // the domain and wrong number of ghost cells. + // current_fp has right number of ghost cells. std::swap(j_fp[lev][idim], current_fp[lev][idim]); + // Then copy the interior of j_fp to current_fp. MultiFab::Copy(*current_fp[lev][idim], *j_fp[lev][idim], 0, 0, 1, 0); + // current_fp has right number of ghost cells and + // correct filtered values here. } } for (int lev = 1; lev <= finest_level; ++lev) @@ -557,32 +572,32 @@ WarpX::SyncRho (amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rhof, for (int lev = 0; lev <= finest_level; ++lev) { const int ncomp = rhof[lev]->nComp(); IntVect ng = rhof[lev]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; rho_f_g[lev].reset(new MultiFab(rhof[lev]->boxArray(), rhof[lev]->DistributionMap(), ncomp, ng)); - applyFilter(*rho_f_g[lev], *rhof[lev]); + bilinear_filter.ApplyStencil(*rho_f_g[lev], *rhof[lev]); std::swap(rho_f_g[lev], rhof[lev]); } for (int lev = 1; lev <= finest_level; ++lev) { const int ncomp = rhoc[lev]->nComp(); IntVect ng = rhoc[lev]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; rho_c_g[lev].reset(new MultiFab(rhoc[lev]->boxArray(), rhoc[lev]->DistributionMap(), ncomp, ng)); - applyFilter(*rho_c_g[lev], *rhoc[lev]); + bilinear_filter.ApplyStencil(*rho_c_g[lev], *rhoc[lev]); std::swap(rho_c_g[lev], rhoc[lev]); } for (int lev = 1; lev <= finest_level; ++lev) { if (charge_buf[lev]) { const int ncomp = charge_buf[lev]->nComp(); IntVect ng = charge_buf[lev]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; rho_buf_g[lev].reset(new MultiFab(charge_buf[lev]->boxArray(), charge_buf[lev]->DistributionMap(), ncomp, ng)); - applyFilter(*rho_buf_g[lev], *charge_buf[lev]); + bilinear_filter.ApplyStencil(*rho_buf_g[lev], *charge_buf[lev]); std::swap(*rho_buf_g[lev], *charge_buf[lev]); } } @@ -711,9 +726,9 @@ WarpX::ApplyFilterandSumBoundaryJ (int lev, PatchType patch_type) for (int idim = 0; idim < 3; ++idim) { if (use_filter) { IntVect ng = j[idim]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab jf(j[idim]->boxArray(), j[idim]->DistributionMap(), 1, ng); - applyFilter(jf, *j[idim]); + bilinear_filter.ApplyStencil(jf, *j[idim]); jf.SumBoundary(period); MultiFab::Copy(*j[idim], jf, 0, 0, 1, 0); } else { @@ -752,15 +767,15 @@ WarpX::AddCurrentFromFineLevelandSumBoundary (int lev) { // coarse patch of fine level IntVect ng = current_cp[lev+1][idim]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab jfc(current_cp[lev+1][idim]->boxArray(), current_cp[lev+1][idim]->DistributionMap(), 1, ng); - applyFilter(jfc, *current_cp[lev+1][idim]); + bilinear_filter.ApplyStencil(jfc, *current_cp[lev+1][idim]); // buffer patch of fine level MultiFab jfb(current_buf[lev+1][idim]->boxArray(), current_buf[lev+1][idim]->DistributionMap(), 1, ng); - applyFilter(jfb, *current_buf[lev+1][idim]); + bilinear_filter.ApplyStencil(jfb, *current_buf[lev+1][idim]); MultiFab::Add(jfb, jfc, 0, 0, 1, ng); mf.ParallelAdd(jfb, 0, 0, 1, ng, IntVect::TheZeroVector(), period); @@ -772,10 +787,10 @@ WarpX::AddCurrentFromFineLevelandSumBoundary (int lev) { // coarse patch of fine level IntVect ng = current_cp[lev+1][idim]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab jf(current_cp[lev+1][idim]->boxArray(), current_cp[lev+1][idim]->DistributionMap(), 1, ng); - applyFilter(jf, *current_cp[lev+1][idim]); + bilinear_filter.ApplyStencil(jf, *current_cp[lev+1][idim]); mf.ParallelAdd(jf, 0, 0, 1, ng, IntVect::TheZeroVector(), period); jf.SumBoundary(period); MultiFab::Copy(*current_cp[lev+1][idim], jf, 0, 0, 1, 0); @@ -822,9 +837,9 @@ WarpX::ApplyFilterandSumBoundaryRho (int lev, PatchType patch_type, int icomp, i if (r == nullptr) return; if (use_filter) { IntVect ng = r->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab rf(r->boxArray(), r->DistributionMap(), ncomp, ng); - applyFilter(rf, *r, icomp, 0, ncomp); + bilinear_filter.ApplyStencil(rf, *r, icomp, 0, ncomp); rf.SumBoundary(period); MultiFab::Copy(*r, rf, 0, icomp, ncomp, 0); } else { @@ -858,15 +873,15 @@ WarpX::AddRhoFromFineLevelandSumBoundary(int lev, int icomp, int ncomp) { // coarse patch of fine level IntVect ng = rho_cp[lev+1]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab rhofc(rho_cp[lev+1]->boxArray(), rho_cp[lev+1]->DistributionMap(), ncomp, ng); - applyFilter(rhofc, *rho_cp[lev+1], icomp, 0, ncomp); + bilinear_filter.ApplyStencil(rhofc, *rho_cp[lev+1], icomp, 0, ncomp); // buffer patch of fine level MultiFab rhofb(charge_buf[lev+1]->boxArray(), charge_buf[lev+1]->DistributionMap(), ncomp, ng); - applyFilter(rhofb, *charge_buf[lev+1], icomp, 0, ncomp); + bilinear_filter.ApplyStencil(rhofb, *charge_buf[lev+1], icomp, 0, ncomp); MultiFab::Add(rhofb, rhofc, 0, 0, ncomp, ng); mf.ParallelAdd(rhofb, 0, 0, ncomp, ng, IntVect::TheZeroVector(), period); @@ -877,9 +892,9 @@ WarpX::AddRhoFromFineLevelandSumBoundary(int lev, int icomp, int ncomp) else if (use_filter) // but no buffer { IntVect ng = rho_cp[lev+1]->nGrowVect(); - ng += 1; + ng += bilinear_filter.stencil_length_each_dir-1; MultiFab rf(rho_cp[lev+1]->boxArray(), rho_cp[lev+1]->DistributionMap(), ncomp, ng); - applyFilter(rf, *rho_cp[lev+1], icomp, 0, ncomp); + bilinear_filter.ApplyStencil(rf, *rho_cp[lev+1], icomp, 0, ncomp); mf.ParallelAdd(rf, 0, 0, ncomp, ng, IntVect::TheZeroVector(), period); rf.SumBoundary(0, ncomp, period); MultiFab::Copy(*rho_cp[lev+1], rf, 0, icomp, ncomp, 0); diff --git a/Source/WarpX.H b/Source/WarpX.H index 5ee2b518c..79488661b 100644 --- a/Source/WarpX.H +++ b/Source/WarpX.H @@ -22,6 +22,7 @@ #include <MultiParticleContainer.H> #include <PML.H> #include <BoostedFrameDiagnostic.H> +#include <BilinearFilter.H> #ifdef WARPX_USE_PSATD #include <fftw3.h> @@ -140,6 +141,9 @@ public: } } + static amrex::IntVect filter_npass_each_dir; + BilinearFilter bilinear_filter; + void ComputeDt (); int MoveWindow (bool move_j); void UpdatePlasmaInjectionPosition (amrex::Real dt); @@ -342,6 +346,8 @@ private: void InitPML (); void ComputePMLFactors (); + void InitFilter (); + void InitDiagnostics (); void InitNCICorrector (); @@ -383,9 +389,6 @@ private: void LoadBalance (); - static void applyFilter (amrex::MultiFab& dstmf, const amrex::MultiFab& srcmf, - int scomp = 0, int dcomp = 0, int ncomp = 10000); - void BuildBufferMasks (); const amrex::iMultiFab* getCurrentBufferMasks (int lev) const { return current_buffer_masks[lev].get(); @@ -510,6 +513,7 @@ private: bool plot_crsepatch = false; bool plot_raw_fields = false; bool plot_raw_fields_guards = false; + int plot_coarsening_ratio = 1; amrex::VisMF::Header::Version checkpoint_headerversion = amrex::VisMF::Header::NoFabHeader_v1; // amrex::VisMF::Header::Version plotfile_headerversion = amrex::VisMF::Header::NoFabHeader_v1; diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp index cc721ea03..dd6c94945 100644 --- a/Source/WarpX.cpp +++ b/Source/WarpX.cpp @@ -91,6 +91,8 @@ IntVect WarpX::jy_nodal_flag(1,1); // y is the missing dimension to 2D AMReX IntVect WarpX::jz_nodal_flag(1,0); // z is the second dimension to 2D AMReX #endif +IntVect WarpX::filter_npass_each_dir(1); + int WarpX::n_field_gather_buffer = 0; int WarpX::n_current_deposition_buffer = -1; @@ -98,8 +100,6 @@ int WarpX::do_nodal = false; WarpX* WarpX::m_instance = nullptr; - - WarpX& WarpX::GetInstance () { @@ -260,14 +260,14 @@ WarpX::ReadParameters () pp.query("cfl", cfl); pp.query("verbose", verbose); pp.query("regrid_int", regrid_int); - pp.query("do_subcycling", do_subcycling); - - AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_subcycling != 1 || max_level <= 1, - "Subcycling method 1 only works for 2 levels."); - - ReadBoostedFrameParameters(gamma_boost, beta_boost, boost_direction); - - pp.queryarr("B_external", B_external); + pp.query("do_subcycling", do_subcycling); + + AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_subcycling != 1 || max_level <= 1, + "Subcycling method 1 only works for 2 levels."); + + ReadBoostedFrameParameters(gamma_boost, beta_boost, boost_direction); + + pp.queryarr("B_external", B_external); pp.query("do_moving_window", do_moving_window); if (do_moving_window) @@ -298,57 +298,67 @@ WarpX::ReadParameters () pp.query("do_plasma_injection", do_plasma_injection); if (do_plasma_injection) { - pp.get("num_injected_species", num_injected_species); - injected_plasma_species.resize(num_injected_species); - pp.getarr("injected_plasma_species", injected_plasma_species, - 0, num_injected_species); - if (moving_window_v >= 0){ - // Inject particles continuously from the right end of the box - current_injection_position = geom[0].ProbHi(moving_window_dir); - } else { - // Inject particles continuously from the left end of the box - current_injection_position = geom[0].ProbLo(moving_window_dir); - } + pp.get("num_injected_species", num_injected_species); + injected_plasma_species.resize(num_injected_species); + pp.getarr("injected_plasma_species", injected_plasma_species, + 0, num_injected_species); + if (moving_window_v >= 0){ + // Inject particles continuously from the right end of the box + current_injection_position = geom[0].ProbHi(moving_window_dir); + } else { + // Inject particles continuously from the left end of the box + current_injection_position = geom[0].ProbLo(moving_window_dir); + } } - pp.query("do_boosted_frame_diagnostic", do_boosted_frame_diagnostic); - if (do_boosted_frame_diagnostic) { - - AMREX_ALWAYS_ASSERT_WITH_MESSAGE(gamma_boost > 1.0, - "gamma_boost must be > 1 to use the boosted frame diagnostic."); - - std::string s; - pp.get("boost_direction", s); - AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"), - "The boosted frame diagnostic currently only works if the boost is in the z direction."); - - pp.get("num_snapshots_lab", num_snapshots_lab); - pp.get("dt_snapshots_lab", dt_snapshots_lab); - pp.get("gamma_boost", gamma_boost); - - pp.query("do_boosted_frame_fields", do_boosted_frame_fields); - pp.query("do_boosted_frame_particles", do_boosted_frame_particles); - - - AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_moving_window, - "The moving window should be on if using the boosted frame diagnostic."); - - pp.get("moving_window_dir", s); - AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"), - "The boosted frame diagnostic currently only works if the moving window is in the z direction."); - } + pp.query("do_boosted_frame_diagnostic", do_boosted_frame_diagnostic); + if (do_boosted_frame_diagnostic) { + + AMREX_ALWAYS_ASSERT_WITH_MESSAGE(gamma_boost > 1.0, + "gamma_boost must be > 1 to use the boosted frame diagnostic."); + + std::string s; + pp.get("boost_direction", s); + AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"), + "The boosted frame diagnostic currently only works if the boost is in the z direction."); + + pp.get("num_snapshots_lab", num_snapshots_lab); + pp.get("dt_snapshots_lab", dt_snapshots_lab); + pp.get("gamma_boost", gamma_boost); + + pp.query("do_boosted_frame_fields", do_boosted_frame_fields); + pp.query("do_boosted_frame_particles", do_boosted_frame_particles); + + + AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_moving_window, + "The moving window should be on if using the boosted frame diagnostic."); + + pp.get("moving_window_dir", s); + AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"), + "The boosted frame diagnostic currently only works if the moving window is in the z direction."); + } - pp.query("do_electrostatic", do_electrostatic); - pp.query("n_buffer", n_buffer); - pp.query("const_dt", const_dt); + pp.query("do_electrostatic", do_electrostatic); + pp.query("n_buffer", n_buffer); + pp.query("const_dt", const_dt); pp.query("use_laser", use_laser); + // Read filter and fill IntVect filter_npass_each_dir with + // proper size for AMREX_SPACEDIM pp.query("use_filter", use_filter); + Vector<int> parse_filter_npass_each_dir(AMREX_SPACEDIM,1); + pp.queryarr("filter_npass_each_dir", parse_filter_npass_each_dir); + filter_npass_each_dir[0] = parse_filter_npass_each_dir[0]; + filter_npass_each_dir[1] = parse_filter_npass_each_dir[1]; +#if (AMREX_SPACEDIM == 3) + filter_npass_each_dir[2] = parse_filter_npass_each_dir[2]; +#endif + pp.query("serialize_ics", serialize_ics); pp.query("refine_plasma", refine_plasma); - pp.query("do_dive_cleaning", do_dive_cleaning); - pp.query("n_field_gather_buffer", n_field_gather_buffer); - pp.query("n_current_deposition_buffer", n_current_deposition_buffer); + pp.query("do_dive_cleaning", do_dive_cleaning); + pp.query("n_field_gather_buffer", n_field_gather_buffer); + pp.query("n_current_deposition_buffer", n_current_deposition_buffer); pp.query("sort_int", sort_int); pp.query("do_pml", do_pml); @@ -368,6 +378,16 @@ WarpX::ReadParameters () pp.query("plot_divb" , plot_divb); pp.query("plot_rho" , plot_rho); pp.query("plot_F" , plot_F); + pp.query("plot_coarsening_ratio", plot_coarsening_ratio); + // Check that the coarsening_ratio can divide the blocking factor + for (int lev=0; lev<maxLevel(); lev++){ + for (int comp=0; comp<AMREX_SPACEDIM; comp++){ + if ( blockingFactor(lev)[comp] % plot_coarsening_ratio != 0 ){ + amrex::Abort("plot_coarsening_ratio should be an integer divisor of the blocking factor."); + } + } + } + if (plot_F){ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_dive_cleaning, "plot_F only works if warpx.do_dive_cleaning = 1"); @@ -946,33 +966,6 @@ WarpX::ComputeDivE (MultiFab& divE, int dcomp, } void -WarpX::applyFilter (MultiFab& dstmf, const MultiFab& srcmf, int scomp, int dcomp, int ncomp) -{ - ncomp = std::min(ncomp, srcmf.nComp()); -#ifdef _OPENMP -#pragma omp parallel -#endif - { - FArrayBox tmpfab; - for (MFIter mfi(dstmf,true); mfi.isValid(); ++mfi) - { - const auto& srcfab = srcmf[mfi]; - auto& dstfab = dstmf[mfi]; - const Box& tbx = mfi.growntilebox(); - const Box& gbx = amrex::grow(tbx,1); - tmpfab.resize(gbx,ncomp); - tmpfab.setVal(0.0, gbx, 0, ncomp); - const Box& ibx = gbx & srcfab.box(); - tmpfab.copy(srcfab, ibx, scomp, ibx, 0, ncomp); - WRPX_FILTER(BL_TO_FORTRAN_BOX(tbx), - BL_TO_FORTRAN_ANYD(tmpfab), - BL_TO_FORTRAN_N_ANYD(dstfab,dcomp), - ncomp); - } - } -} - -void WarpX::BuildBufferMasks () { int ngbuffer = std::max(n_field_gather_buffer, n_current_deposition_buffer); |