aboutsummaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/BoundaryConditions/PML.cpp2
-rw-r--r--Source/Diagnostics/BoostedFrameDiagnostic.H56
-rw-r--r--Source/Diagnostics/BoostedFrameDiagnostic.cpp297
-rw-r--r--Source/Diagnostics/BoostedFrame_module.F90106
-rw-r--r--Source/Diagnostics/FieldIO.cpp32
-rw-r--r--Source/Diagnostics/Make.package3
-rw-r--r--Source/Diagnostics/ParticleIO.cpp139
-rw-r--r--Source/Diagnostics/SliceDiagnostic.H42
-rw-r--r--Source/Diagnostics/SliceDiagnostic.cpp475
-rw-r--r--Source/Diagnostics/WarpXIO.cpp134
-rw-r--r--Source/Evolve/WarpXEvolveEM.cpp243
-rw-r--r--Source/FieldSolver/SpectralSolver/Make.package5
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H (renamed from Source/FieldSolver/SpectralSolver/PsatdAlgorithm.H)20
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp (renamed from Source/FieldSolver/SpectralSolver/PsatdAlgorithm.cpp)182
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H51
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.H18
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp171
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralKSpace.H4
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp72
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.H34
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.cpp35
-rw-r--r--Source/FieldSolver/WarpXFFT.cpp19
-rw-r--r--Source/FieldSolver/WarpXPushFieldsEM.cpp64
-rw-r--r--Source/Filter/BilinearFilter.H27
-rw-r--r--Source/Filter/BilinearFilter.cpp170
-rw-r--r--Source/Filter/Filter.H43
-rw-r--r--Source/Filter/Filter.cpp257
-rw-r--r--Source/Filter/Make.package4
-rw-r--r--Source/Filter/NCIGodfreyFilter.H30
-rw-r--r--Source/Filter/NCIGodfreyFilter.cpp78
-rw-r--r--Source/FortranInterface/WarpX_f.F9035
-rw-r--r--Source/FortranInterface/WarpX_f.H58
-rw-r--r--Source/FortranInterface/WarpX_picsar.F90109
-rw-r--r--Source/Initialization/Make.package1
-rw-r--r--Source/Initialization/PlasmaInjector.H21
-rw-r--r--Source/Initialization/PlasmaInjector.cpp14
-rw-r--r--Source/Initialization/PlasmaProfiles.cpp41
-rw-r--r--Source/Initialization/WarpXInitData.cpp18
-rw-r--r--Source/Laser/LaserParticleContainer.H26
-rw-r--r--Source/Laser/LaserParticleContainer.cpp465
-rw-r--r--Source/Make.WarpX26
-rw-r--r--Source/Parallelization/Make.package1
-rw-r--r--Source/Parallelization/WarpXComm.cpp117
-rw-r--r--Source/Parallelization/WarpXSumGuardCells.H61
-rw-r--r--Source/Parser/WarpXParser.cpp3
-rw-r--r--Source/Particles/Make.package2
-rw-r--r--Source/Particles/MultiParticleContainer.H37
-rw-r--r--Source/Particles/MultiParticleContainer.cpp191
-rw-r--r--Source/Particles/PhysicalParticleContainer.H12
-rw-r--r--Source/Particles/PhysicalParticleContainer.cpp348
-rw-r--r--Source/Particles/Pusher/GetAndSetPosition.H76
-rw-r--r--Source/Particles/Pusher/Make.package4
-rw-r--r--Source/Particles/Pusher/UpdatePosition.H30
-rw-r--r--Source/Particles/RigidInjectedParticleContainer.H4
-rw-r--r--Source/Particles/RigidInjectedParticleContainer.cpp29
-rw-r--r--Source/Particles/WarpXParticleContainer.H78
-rw-r--r--Source/Particles/WarpXParticleContainer.cpp373
-rw-r--r--Source/Python/Make.package8
-rw-r--r--Source/Python/WarpXWrappers.cpp2
-rw-r--r--Source/Utils/Make.package3
-rw-r--r--Source/Utils/NCIGodfreyTables.H224
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.H57
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.cpp95
-rw-r--r--Source/Utils/WarpXMovingWindow.cpp66
-rw-r--r--Source/Utils/WarpXTagging.cpp2
-rw-r--r--Source/Utils/WarpXUtil.H4
-rw-r--r--Source/Utils/WarpXUtil.cpp41
-rw-r--r--Source/WarpX.H43
-rw-r--r--Source/WarpX.cpp180
70 files changed, 4063 insertions, 1661 deletions
diff --git a/Source/BoundaryConditions/PML.cpp b/Source/BoundaryConditions/PML.cpp
index c3449cecd..f780f335c 100644
--- a/Source/BoundaryConditions/PML.cpp
+++ b/Source/BoundaryConditions/PML.cpp
@@ -412,7 +412,7 @@ PML::MakeBoxArray (const amrex::Geometry& geom, const amrex::BoxArray& grid_ba,
{
Box domain = geom.Domain();
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
- if ( ! Geometry::isPeriodic(idim) ) {
+ if ( ! geom.isPeriodic(idim) ) {
domain.grow(idim, ncell);
}
}
diff --git a/Source/Diagnostics/BoostedFrameDiagnostic.H b/Source/Diagnostics/BoostedFrameDiagnostic.H
index e35d307a6..3a09259b0 100644
--- a/Source/Diagnostics/BoostedFrameDiagnostic.H
+++ b/Source/Diagnostics/BoostedFrameDiagnostic.H
@@ -2,11 +2,13 @@
#define WARPX_BoostedFrameDiagnostic_H_
#include <vector>
+#include <map>
#include <AMReX_VisMF.H>
#include <AMReX_PlotFileUtil.H>
#include <AMReX_ParallelDescriptor.H>
#include <AMReX_Geometry.H>
+#include <AMReX_CudaContainers.H>
#include "MultiParticleContainer.H"
#include "WarpXConst.H"
@@ -32,17 +34,25 @@ class BoostedFrameDiagnostic {
std::string file_name;
amrex::Real t_lab;
- amrex::Real zmin_lab;
- amrex::Real zmax_lab;
+ amrex::RealBox prob_domain_lab_;
+ amrex::IntVect prob_ncells_lab_;
+
amrex::Real current_z_lab;
amrex::Real current_z_boost;
+
+ int ncomp_to_dump_;
+ std::vector<std::string> mesh_field_names_;
+
int file_num;
int initial_i;
const BoostedFrameDiagnostic& my_bfd;
LabSnapShot(amrex::Real t_lab_in, amrex::Real t_boost,
- amrex::Real zmin_lab_in,
- amrex::Real zmax_lab_in, int file_num_in,
+ const amrex::RealBox prob_domain_lab,
+ const amrex::IntVect prob_ncells_lab,
+ const int ncomp_to_dump,
+ const std::vector<std::string> mesh_field_names,
+ int file_num_in,
const BoostedFrameDiagnostic& bfd);
///
@@ -69,15 +79,21 @@ class BoostedFrameDiagnostic {
amrex::Real dt_snapshots_lab_;
amrex::Real dt_boost_;
int N_snapshots_;
- unsigned Nx_lab_;
- unsigned Ny_lab_;
- unsigned Nz_lab_;
int boost_direction_;
+ // For back-transformed diagnostics of grid fields, data_buffer_[i]
+ // stores a buffer of the fields in the lab frame (in a MultiFab, i.e.
+ // with all box data etc.). When the buffer if full, dump to file.
amrex::Vector<std::unique_ptr<amrex::MultiFab> > data_buffer_;
+ // particles_buffer_ is currently blind to refinement level.
+ // particles_buffer_[i][j] is a WarpXParticleContainer::DiagnosticParticleData where
+ // - i is the back-transformed snapshot number
+ // - j is the species number
amrex::Vector<amrex::Vector<WarpXParticleContainer::DiagnosticParticleData> > particles_buffer_;
int num_buffer_ = 256;
int max_box_size_ = 256;
+ // buff_counter_[i] is the number of z slices in data_buffer_[i]
+ // for snapshot number i.
amrex::Vector<int> buff_counter_;
amrex::Vector<LabSnapShot> snapshots_;
@@ -105,6 +121,32 @@ public:
const amrex::Real t_boost, const amrex::Real dt);
void writeMetaData();
+
+private:
+ // Map field names and component number in cell_centered_data
+ std::map<std::string, int> possible_fields_to_dump = {
+ {"Ex" , 0},
+ {"Ey" , 1},
+ {"Ez" , 2},
+ {"Bx" , 3},
+ {"By" , 4},
+ {"Bz" , 5},
+ {"jx" , 6},
+ {"jy" , 7},
+ {"jz" , 8},
+ {"rho", 9} };
+
+ // maps field index in data_buffer_[i] -> cell_centered_data for
+ // snapshots i. By default, all fields in cell_centered_data are dumped.
+ // Needs to be amrex::Vector because used in a ParallelFor kernel.
+ amrex::Gpu::ManagedDeviceVector<int> map_actual_fields_to_dump;
+ // Name of fields to dump. By default, all fields in cell_centered_data.
+ // Needed for file headers only.
+ std::vector<std::string> mesh_field_names = {"Ex", "Ey", "Ez",
+ "Bx", "By", "Bz",
+ "jx", "jy", "jz", "rho"};
+ int ncomp_to_dump = 10;
+
};
#endif
diff --git a/Source/Diagnostics/BoostedFrameDiagnostic.cpp b/Source/Diagnostics/BoostedFrameDiagnostic.cpp
index 13972075d..5e7d4e0ad 100644
--- a/Source/Diagnostics/BoostedFrameDiagnostic.cpp
+++ b/Source/Diagnostics/BoostedFrameDiagnostic.cpp
@@ -17,8 +17,6 @@ using namespace amrex;
namespace
{
const std::vector<std::string> particle_field_names = {"w", "x", "y", "z", "ux", "uy", "uz"};
- const std::vector<std::string> mesh_field_names =
- {"Ex", "Ey", "Ez", "Bx", "By", "Bz", "jx", "jy", "jz", "rho"};
/*
Creates the HDF5 file in truncate mode and closes it.
@@ -446,6 +444,83 @@ namespace
}
#endif
+namespace
+{
+ void
+ CopySlice(MultiFab& tmp, MultiFab& buf, int k_lab,
+ const Gpu::ManagedDeviceVector<int>& map_actual_fields_to_dump)
+ {
+ const int ncomp_to_dump = map_actual_fields_to_dump.size();
+ // Copy data from MultiFab tmp to MultiFab data_buffer[i].
+#ifdef _OPENMP
+#pragma omp parallel if (Gpu::notInLaunchRegion())
+#endif
+ for (MFIter mfi(tmp, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
+ Array4< Real> tmp_arr = tmp[mfi].array();
+ Array4< Real> buf_arr = buf[mfi].array();
+ // For 3D runs, tmp is a 2D (x,y) multifab, that contains only
+ // slice to write to file.
+ const Box& bx = mfi.tilebox();
+
+ const auto field_map_ptr = map_actual_fields_to_dump.dataPtr();
+ ParallelFor(bx, ncomp_to_dump,
+ [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
+ {
+ const int icomp = field_map_ptr[n];
+#if (AMREX_SPACEDIM == 3)
+ buf_arr(i,j,k_lab,n) += tmp_arr(i,j,k,icomp);
+#else
+ buf_arr(i,k_lab,k,n) += tmp_arr(i,j,k,icomp);
+#endif
+ }
+ );
+ }
+ }
+
+void
+LorentzTransformZ(MultiFab& data, Real gamma_boost, Real beta_boost, int ncomp)
+{
+ // Loop over tiles/boxes and in-place convert each slice from boosted
+ // frame to lab frame.
+#ifdef _OPENMP
+#pragma omp parallel if (Gpu::notInLaunchRegion())
+#endif
+ for (MFIter mfi(data, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
+ const Box& tile_box = mfi.tilebox();
+ Array4< Real > arr = data[mfi].array();
+ // arr(x,y,z,comp) where 0->9 comps are
+ // Ex Ey Ez Bx By Bz jx jy jz rho
+ Real clight = PhysConst::c;
+ ParallelFor(tile_box,
+ [=] AMREX_GPU_DEVICE (int i, int j, int k)
+ {
+ // Transform the transverse E and B fields. Note that ez and bz are not
+ // changed by the tranform.
+ Real e_lab, b_lab, j_lab, r_lab;
+ e_lab = gamma_boost * (arr(i, j, k, 0) + beta_boost*clight*arr(i, j, k, 4));
+ b_lab = gamma_boost * (arr(i, j, k, 4) + beta_boost*arr(i, j, k, 0)/clight);
+
+ arr(i, j, k, 0) = e_lab;
+ arr(i, j, k, 4) = b_lab;
+
+ e_lab = gamma_boost * (arr(i, j, k, 1) - beta_boost*clight*arr(i, j, k, 3));
+ b_lab = gamma_boost * (arr(i, j, k, 3) - beta_boost*arr(i, j, k, 1)/clight);
+
+ arr(i, j, k, 1) = e_lab;
+ arr(i, j, k, 3) = b_lab;
+
+ // Transform the charge and current density. Only the z component of j is affected.
+ j_lab = gamma_boost*(arr(i, j, k, 8) + beta_boost*clight*arr(i, j, k, 9));
+ r_lab = gamma_boost*(arr(i, j, k, 9) + beta_boost*arr(i, j, k, 8)/clight);
+
+ arr(i, j, k, 8) = j_lab;
+ arr(i, j, k, 9) = r_lab;
+ }
+ );
+ }
+}
+}
+
BoostedFrameDiagnostic::
BoostedFrameDiagnostic(Real zmin_lab, Real zmax_lab, Real v_window_lab,
Real dt_snapshots_lab, int N_snapshots,
@@ -469,23 +544,53 @@ BoostedFrameDiagnostic(Real zmin_lab, Real zmax_lab, Real v_window_lab,
dz_lab_ = PhysConst::c * dt_boost_ * inv_beta_boost_ * inv_gamma_boost_;
inv_dz_lab_ = 1.0 / dz_lab_;
- Nx_lab_ = geom.Domain().length(0);
+ int Nz_lab = static_cast<unsigned>((zmax_lab - zmin_lab) * inv_dz_lab_);
+ int Nx_lab = geom.Domain().length(0);
#if (AMREX_SPACEDIM == 3)
- Ny_lab_ = geom.Domain().length(1);
+ int Ny_lab = geom.Domain().length(1);
+ IntVect prob_ncells_lab = {Nx_lab, Ny_lab, Nz_lab};
#else
- Ny_lab_ = 1;
+ // Ny_lab = 1;
+ IntVect prob_ncells_lab = {Nx_lab, Nz_lab};
#endif
- Nz_lab_ = static_cast<unsigned>((zmax_lab - zmin_lab) * inv_dz_lab_);
-
+
writeMetaData();
if (WarpX::do_boosted_frame_fields) data_buffer_.resize(N_snapshots);
if (WarpX::do_boosted_frame_particles) particles_buffer_.resize(N_snapshots);
+
+ // Query fields to dump
+ std::vector<std::string> user_fields_to_dump;
+ ParmParse pp("warpx");
+ bool do_user_fields;
+ do_user_fields = pp.queryarr("boosted_frame_diag_fields",
+ user_fields_to_dump);
+ // If user specifies fields to dump, overwrite ncomp_to_dump,
+ // map_actual_fields_to_dump and mesh_field_names.
+ for (int i = 0; i < 10; ++i) map_actual_fields_to_dump.push_back(i);
+ if (do_user_fields){
+ ncomp_to_dump = user_fields_to_dump.size();
+ map_actual_fields_to_dump.resize(ncomp_to_dump);
+ mesh_field_names.resize(ncomp_to_dump);
+ for (int i=0; i<ncomp_to_dump; i++){
+ std::string fieldstr = user_fields_to_dump[i];
+ mesh_field_names[i] = fieldstr;
+ map_actual_fields_to_dump[i] = possible_fields_to_dump[fieldstr];
+ }
+ }
+
for (int i = 0; i < N_snapshots; ++i) {
Real t_lab = i * dt_snapshots_lab_;
- LabSnapShot snapshot(t_lab, t_boost,
- zmin_lab + v_window_lab * t_lab,
- zmax_lab + v_window_lab * t_lab, i, *this);
+ // Get simulation domain physical coordinates (in boosted frame).
+ RealBox prob_domain_lab = geom.ProbDomain();
+ // Replace z bounds by lab-frame coordinates
+ // x and y bounds are the same for lab frame and boosted frame
+ prob_domain_lab.setLo(AMREX_SPACEDIM-1, zmin_lab + v_window_lab * t_lab);
+ prob_domain_lab.setHi(AMREX_SPACEDIM-1, zmax_lab + v_window_lab * t_lab);
+ // Construct LabSnapShot
+ LabSnapShot snapshot(t_lab, t_boost, prob_domain_lab,
+ prob_ncells_lab, ncomp_to_dump,
+ mesh_field_names, i, *this);
snapshots_.push_back(snapshot);
buff_counter_.push_back(0);
if (WarpX::do_boosted_frame_fields) data_buffer_[i].reset( nullptr );
@@ -504,9 +609,11 @@ void BoostedFrameDiagnostic::Flush(const Geometry& geom)
auto & mypc = WarpX::GetInstance().GetPartContainer();
const std::vector<std::string> species_names = mypc.GetSpeciesNames();
+ // Loop over BFD snapshots
for (int i = 0; i < N_snapshots_; ++i) {
- int i_lab = (snapshots_[i].current_z_lab - snapshots_[i].zmin_lab) / dz_lab_;
+ Real zmin_lab = snapshots_[i].prob_domain_lab_.lo(AMREX_SPACEDIM-1);
+ int i_lab = (snapshots_[i].current_z_lab - zmin_lab) / dz_lab_;
if (buff_counter_[i] != 0) {
if (WarpX::do_boosted_frame_fields) {
@@ -539,14 +646,20 @@ void BoostedFrameDiagnostic::Flush(const Geometry& geom)
}
if (WarpX::do_boosted_frame_particles) {
- for (int j = 0; j < mypc.nSpecies(); ++j) {
+ // Loop over species to be dumped to BFD
+ for (int j = 0; j < mypc.nSpeciesBoostedFrameDiags(); ++j) {
+ // Get species name
+ std::string species_name =
+ species_names[mypc.mapSpeciesBoostedFrameDiags(j)];
#ifdef WARPX_USE_HDF5
+ // Dump species data
writeParticleDataHDF5(particles_buffer_[i][j],
snapshots_[i].file_name,
- species_names[j]);
+ species_name);
#else
std::stringstream part_ss;
- part_ss << snapshots_[i].file_name + "/" + species_names[j] + "/";
+ part_ss << snapshots_[i].file_name + "/" + species_name + "/";
+ // Dump species data
writeParticleData(particles_buffer_[i][j], part_ss.str(), i_lab);
#endif
}
@@ -575,73 +688,76 @@ writeLabFrameData(const MultiFab* cell_centered_data,
const Real zhi_boost = domain_z_boost.hi(boost_direction_);
const std::vector<std::string> species_names = mypc.GetSpeciesNames();
-
+
+ // Loop over snapshots
for (int i = 0; i < N_snapshots_; ++i) {
+
+ // Get updated z position of snapshot
const Real old_z_boost = snapshots_[i].current_z_boost;
snapshots_[i].updateCurrentZPositions(t_boost,
inv_gamma_boost_,
inv_beta_boost_);
+
+ Real zmin_lab = snapshots_[i].prob_domain_lab_.lo(AMREX_SPACEDIM-1);
+ Real zmax_lab = snapshots_[i].prob_domain_lab_.hi(AMREX_SPACEDIM-1);
+ // If snapshot out of the domain, nothing to do
if ( (snapshots_[i].current_z_boost < zlo_boost) or
(snapshots_[i].current_z_boost > zhi_boost) or
- (snapshots_[i].current_z_lab < snapshots_[i].zmin_lab) or
- (snapshots_[i].current_z_lab > snapshots_[i].zmax_lab) ) continue;
+ (snapshots_[i].current_z_lab < zmin_lab) or
+ (snapshots_[i].current_z_lab > zmax_lab) ) continue;
- int i_lab = (snapshots_[i].current_z_lab - snapshots_[i].zmin_lab) / dz_lab_;
+ // Get z index of data_buffer_ (i.e. in the lab frame) where
+ // simulation domain (t', [zmin',zmax']), back-transformed to lab
+ // frame, intersects with snapshot.
+ int i_lab = (snapshots_[i].current_z_lab - zmin_lab) / dz_lab_;
+ // If buffer of snapshot i is empty...
if (buff_counter_[i] == 0) {
+ // ... reset fields buffer data_buffer_[i]
if (WarpX::do_boosted_frame_fields) {
- const int ncomp = cell_centered_data->nComp();
Box buff_box = geom.Domain();
buff_box.setSmall(boost_direction_, i_lab - num_buffer_ + 1);
buff_box.setBig(boost_direction_, i_lab);
BoxArray buff_ba(buff_box);
buff_ba.maxSize(max_box_size_);
DistributionMapping buff_dm(buff_ba);
- data_buffer_[i].reset( new MultiFab(buff_ba, buff_dm, ncomp, 0) );
+ data_buffer_[i].reset( new MultiFab(buff_ba, buff_dm, ncomp_to_dump, 0) );
}
- if (WarpX::do_boosted_frame_particles) particles_buffer_[i].resize(mypc.nSpecies());
+ // ... reset particle buffer particles_buffer_[i]
+ if (WarpX::do_boosted_frame_particles)
+ particles_buffer_[i].resize(mypc.nSpeciesBoostedFrameDiags());
}
if (WarpX::do_boosted_frame_fields) {
const int ncomp = cell_centered_data->nComp();
const int start_comp = 0;
const bool interpolate = true;
+ // Get slice in the boosted frame
std::unique_ptr<MultiFab> slice = amrex::get_slice_data(boost_direction_,
snapshots_[i].current_z_boost,
*cell_centered_data, geom,
start_comp, ncomp, interpolate);
// transform it to the lab frame
- for (MFIter mfi(*slice); mfi.isValid(); ++mfi) {
- const Box& tile_box = mfi.tilebox();
- WRPX_LORENTZ_TRANSFORM_Z(BL_TO_FORTRAN_ANYD((*slice)[mfi]),
- BL_TO_FORTRAN_BOX(tile_box),
- &gamma_boost_, &beta_boost_);
- }
-
+ LorentzTransformZ(*slice, gamma_boost_, beta_boost_, ncomp);
+ // Create a 2D box for the slice in the boosted frame
Real dx = geom.CellSize(boost_direction_);
int i_boost = (snapshots_[i].current_z_boost - geom.ProbLo(boost_direction_))/dx;
Box slice_box = geom.Domain();
slice_box.setSmall(boost_direction_, i_boost);
slice_box.setBig(boost_direction_, i_boost);
+ // Make it a BoxArray slice_ba
BoxArray slice_ba(slice_box);
slice_ba.maxSize(max_box_size_);
+ // Create MultiFab tmp on slice_ba with data from slice
MultiFab tmp(slice_ba, data_buffer_[i]->DistributionMap(), ncomp, 0);
tmp.copy(*slice, 0, 0, ncomp);
-#ifdef _OPENMP
-#pragma omp parallel
-#endif
- for (MFIter mfi(tmp, true); mfi.isValid(); ++mfi) {
- const Box& tile_box = mfi.tilebox();
- WRPX_COPY_SLICE(BL_TO_FORTRAN_BOX(tile_box),
- BL_TO_FORTRAN_ANYD(tmp[mfi]),
- BL_TO_FORTRAN_ANYD((*data_buffer_[i])[mfi]),
- &ncomp, &i_boost, &i_lab);
- }
+ // Copy data from MultiFab tmp to MultiDab data_buffer[i]
+ CopySlice(tmp, *data_buffer_[i], i_lab, map_actual_fields_to_dump);
}
-
+
if (WarpX::do_boosted_frame_particles) {
mypc.GetLabFrameData(snapshots_[i].file_name, i_lab, boost_direction_,
old_z_boost, snapshots_[i].current_z_boost,
@@ -651,6 +767,7 @@ writeLabFrameData(const MultiFab* cell_centered_data,
++buff_counter_[i];
+ // If buffer full, write to disk.
if (buff_counter_[i] == num_buffer_) {
if (WarpX::do_boosted_frame_fields) {
@@ -666,14 +783,21 @@ writeLabFrameData(const MultiFab* cell_centered_data,
}
if (WarpX::do_boosted_frame_particles) {
- for (int j = 0; j < mypc.nSpecies(); ++j) {
+ // Loop over species to be dumped to BFD
+ for (int j = 0; j < mypc.nSpeciesBoostedFrameDiags(); ++j) {
+ // Get species name
+ const std::string species_name = species_names[mypc.mapSpeciesBoostedFrameDiags(j)];
#ifdef WARPX_USE_HDF5
+ // Write data to disk (HDF5)
writeParticleDataHDF5(particles_buffer_[i][j],
snapshots_[i].file_name,
- species_names[j]);
+ species_name);
#else
std::stringstream part_ss;
- part_ss << snapshots_[i].file_name + "/" + species_names[j] + "/";
+
+ part_ss << snapshots_[i].file_name + "/" + species_name + "/";
+
+ // Write data to disk (custom)
writeParticleData(particles_buffer_[i][j], part_ss.str(), i_lab);
#endif
}
@@ -791,15 +915,14 @@ writeMetaData ()
BL_PROFILE("BoostedFrameDiagnostic::writeMetaData");
if (ParallelDescriptor::IOProcessor()) {
- std::string DiagnosticDirectory = "lab_frame_data";
- if (!UtilCreateDirectory(DiagnosticDirectory, 0755))
- CreateDirectoryFailed(DiagnosticDirectory);
+ if (!UtilCreateDirectory(WarpX::lab_data_directory, 0755))
+ CreateDirectoryFailed(WarpX::lab_data_directory);
VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
std::ofstream HeaderFile;
HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
- std::string HeaderFileName(DiagnosticDirectory + "/Header");
+ std::string HeaderFileName(WarpX::lab_data_directory + "/Header");
HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
std::ofstream::trunc |
std::ofstream::binary);
@@ -812,25 +935,30 @@ writeMetaData ()
HeaderFile << dt_snapshots_lab_ << "\n";
HeaderFile << gamma_boost_ << "\n";
HeaderFile << beta_boost_ << "\n";
- HeaderFile << dz_lab_ << "\n";
- HeaderFile << Nz_lab_ << "\n";
}
}
BoostedFrameDiagnostic::LabSnapShot::
-LabSnapShot(Real t_lab_in, Real t_boost, Real zmin_lab_in,
- Real zmax_lab_in, int file_num_in, const BoostedFrameDiagnostic& bfd)
+LabSnapShot(Real t_lab_in, Real t_boost, RealBox prob_domain_lab,
+ IntVect prob_ncells_lab,
+ int ncomp_to_dump,
+ std::vector<std::string> mesh_field_names,
+ int file_num_in,
+ const BoostedFrameDiagnostic& bfd)
: t_lab(t_lab_in),
- zmin_lab(zmin_lab_in),
- zmax_lab(zmax_lab_in),
+ prob_domain_lab_(prob_domain_lab),
+ prob_ncells_lab_(prob_ncells_lab),
+ ncomp_to_dump_(ncomp_to_dump),
+ mesh_field_names_(mesh_field_names),
file_num(file_num_in),
my_bfd(bfd)
{
+ Real zmin_lab = prob_domain_lab_.lo(AMREX_SPACEDIM-1);
current_z_lab = 0.0;
current_z_boost = 0.0;
updateCurrentZPositions(t_boost, my_bfd.inv_gamma_boost_, my_bfd.inv_beta_boost_);
initial_i = (current_z_lab - zmin_lab) / my_bfd.dz_lab_;
- file_name = Concatenate("lab_frame_data/snapshot", file_num, 5);
+ file_name = Concatenate(WarpX::lab_data_directory + "/snapshot", file_num, 5);
#ifdef WARPX_USE_HDF5
if (ParallelDescriptor::IOProcessor())
@@ -844,27 +972,34 @@ LabSnapShot(Real t_lab_in, Real t_boost, Real zmin_lab_in,
{
if (WarpX::do_boosted_frame_fields)
{
- for (int comp = 0; comp < static_cast<int>(mesh_field_names.size()); ++comp) {
- output_create_field(file_name, mesh_field_names[comp],
- my_bfd.Nx_lab_,
- my_bfd.Ny_lab_,
- my_bfd.Nz_lab_+1);
+ for (int comp = 0; comp < ncomp_to_dump; ++comp) {
+ output_create_field(file_name, mesh_field_names_[comp],
+ prob_ncells_lab_[0],
+#if ( AMREX_SPACEDIM == 3 )
+ prob_ncells_lab_[1],
+#else
+ 1,
+#endif
+ prob_ncells_lab_[AMREX_SPACEDIM-1]+1);
}
}
}
ParallelDescriptor::Barrier();
- if (WarpX::do_boosted_frame_particles)
- {
+ if (WarpX::do_boosted_frame_particles){
auto & mypc = WarpX::GetInstance().GetPartContainer();
const std::vector<std::string> species_names = mypc.GetSpeciesNames();
- for (int j = 0; j < mypc.nSpecies(); ++j)
+ // Loop over species to be dumped to BFD
+ for (int j = 0; j < mypc.nSpeciesBoostedFrameDiags(); ++j)
{
- output_create_species_group(file_name, species_names[j]);
+ // Loop over species to be dumped to BFD
+ std::string species_name =
+ species_names[mypc.mapSpeciesBoostedFrameDiags(j)];
+ output_create_species_group(file_name, species_name);
for (int k = 0; k < static_cast<int>(particle_field_names.size()); ++k)
{
- std::string field_path = species_names[j] + "/" + particle_field_names[k];
+ std::string field_path = species_name + "/" + particle_field_names[k];
output_create_particle_field(file_name, field_path);
}
}
@@ -884,11 +1019,14 @@ LabSnapShot(Real t_lab_in, Real t_boost, Real zmin_lab_in,
auto & mypc = WarpX::GetInstance().GetPartContainer();
const std::vector<std::string> species_names = mypc.GetSpeciesNames();
- int nspecies = mypc.nSpecies();
const std::string particles_prefix = "particle";
- for(int i = 0; i < nspecies; ++i) {
- const std::string fullpath = file_name + "/" + species_names[i];
+ // Loop over species to be dumped to BFD
+ for(int i = 0; i < mypc.nSpeciesBoostedFrameDiags(); ++i) {
+ // Get species name
+ std::string species_name =
+ species_names[mypc.mapSpeciesBoostedFrameDiags(i)];
+ const std::string fullpath = file_name + "/" + species_name;
if (!UtilCreateDirectory(fullpath, 0755))
CreateDirectoryFailed(fullpath);
}
@@ -924,8 +1062,31 @@ writeSnapShotHeader() {
HeaderFile.precision(17);
HeaderFile << t_lab << "\n";
- HeaderFile << zmin_lab << "\n";
- HeaderFile << zmax_lab << "\n";
+ // Write domain number of cells
+ HeaderFile << prob_ncells_lab_[0] << ' '
+#if ( AMREX_SPACEDIM==3 )
+ << prob_ncells_lab_[1] << ' '
+#endif
+ << prob_ncells_lab_[AMREX_SPACEDIM-1] <<'\n';
+ // Write domain physical boundaries
+ // domain lower bound
+ HeaderFile << prob_domain_lab_.lo(0) << ' '
+#if ( AMREX_SPACEDIM==3 )
+ << prob_domain_lab_.lo(1) << ' '
+#endif
+ << prob_domain_lab_.lo(AMREX_SPACEDIM-1) <<'\n';
+ // domain higher bound
+ HeaderFile << prob_domain_lab_.hi(0) << ' '
+#if ( AMREX_SPACEDIM==3 )
+ << prob_domain_lab_.hi(1) << ' '
+#endif
+ << prob_domain_lab_.hi(AMREX_SPACEDIM-1) <<'\n';
+ // List of fields dumped to file
+ for (int i=0; i<ncomp_to_dump_; i++)
+ {
+ HeaderFile << mesh_field_names_[i] << ' ';
+ }
+ HeaderFile << "\n";
}
#endif
}
diff --git a/Source/Diagnostics/BoostedFrame_module.F90 b/Source/Diagnostics/BoostedFrame_module.F90
deleted file mode 100644
index 3bce1817e..000000000
--- a/Source/Diagnostics/BoostedFrame_module.F90
+++ /dev/null
@@ -1,106 +0,0 @@
-
-module warpx_boosted_frame_module
-
- use iso_c_binding
- use amrex_fort_module, only : amrex_real
- use constants, only : clight
-
- implicit none
-
-contains
-
-!
-! Given cell-centered data in the boosted reference frame of the simulation,
-! this transforms E and B in place so that the multifab now contains values
-! in the lab frame. This routine assumes that the simulation frame is moving
-! in the positive z direction with respect to the lab frame.
-!
- subroutine warpx_lorentz_transform_z(data, dlo, dhi, tlo, thi, gamma_boost, beta_boost) &
- bind(C, name="warpx_lorentz_transform_z")
-
- integer(c_int), intent(in) :: dlo(3), dhi(3)
- integer(c_int), intent(in) :: tlo(3), thi(3)
- real(amrex_real), intent(inout) :: data(dlo(1):dhi(1),dlo(2):dhi(2),dlo(3):dhi(3), 10)
- real(amrex_real), intent(in) :: gamma_boost, beta_boost
-
- integer i, j, k
- real(amrex_real) e_lab, b_lab, j_lab, r_lab
-
- do k = tlo(3), thi(3)
- do j = tlo(2), thi(2)
- do i = tlo(1), thi(1)
-
- ! Transform the transverse E and B fields. Note that ez and bz are not
- ! changed by the tranform.
- e_lab = gamma_boost * (data(i, j, k, 1) + beta_boost*clight*data(i, j, k, 5))
- b_lab = gamma_boost * (data(i, j, k, 5) + beta_boost*data(i, j, k, 1)/clight)
-
- data(i, j, k, 1) = e_lab
- data(i, j, k, 5) = b_lab
-
- e_lab = gamma_boost * (data(i, j, k, 2) - beta_boost*clight*data(i, j, k, 4))
- b_lab = gamma_boost * (data(i, j, k, 4) - beta_boost*data(i, j, k, 2)/clight)
-
- data(i, j, k, 2) = e_lab
- data(i, j, k, 4) = b_lab
-
- ! Transform the charge and current density. Only the z component of j is affected.
- j_lab = gamma_boost*(data(i, j, k, 9) + beta_boost*clight*data(i, j, k, 10))
- r_lab = gamma_boost*(data(i, j, k, 10) + beta_boost*data(i, j, k, 9)/clight)
-
- data(i, j, k, 9) = j_lab
- data(i, j, k, 10) = r_lab
-
- end do
- end do
- end do
-
- end subroutine warpx_lorentz_transform_z
-
- subroutine warpx_copy_slice_3d(lo, hi, tmp, tlo, thi, &
- buf, blo, bhi, ncomp, &
- i_boost, i_lab) &
- bind(C, name="warpx_copy_slice_3d")
-
- integer , intent(in) :: ncomp, i_boost, i_lab
- integer , intent(in) :: lo(3), hi(3)
- integer , intent(in) :: tlo(3), thi(3)
- integer , intent(in) :: blo(3), bhi(3)
- real(amrex_real), intent(inout) :: tmp(tlo(1):thi(1),tlo(2):thi(2),tlo(3):thi(3),ncomp)
- real(amrex_real), intent(inout) :: buf(blo(1):bhi(1),blo(2):bhi(2),blo(3):bhi(3),ncomp)
-
- integer n, i, j, k
-
- do n = 1, ncomp
- do j = lo(2), hi(2)
- do i = lo(1), hi(1)
- buf(i, j, i_lab, n) = tmp(i, j, i_boost, n)
- end do
- end do
- end do
-
- end subroutine warpx_copy_slice_3d
-
- subroutine warpx_copy_slice_2d(lo, hi, tmp, tlo, thi, &
- buf, blo, bhi, ncomp, &
- i_boost, i_lab) &
- bind(C, name="warpx_copy_slice_2d")
-
- integer , intent(in) :: ncomp, i_boost, i_lab
- integer , intent(in) :: lo(2), hi(2)
- integer , intent(in) :: tlo(2), thi(2)
- integer , intent(in) :: blo(2), bhi(2)
- real(amrex_real), intent(inout) :: tmp(tlo(1):thi(1),tlo(2):thi(2),ncomp)
- real(amrex_real), intent(inout) :: buf(blo(1):bhi(1),blo(2):bhi(2),ncomp)
-
- integer n, i, j, k
-
- do n = 1, ncomp
- do i = lo(1), hi(1)
- buf(i, i_lab, n) = tmp(i, i_boost, n)
- end do
- end do
-
- end subroutine warpx_copy_slice_2d
-
-end module warpx_boosted_frame_module
diff --git a/Source/Diagnostics/FieldIO.cpp b/Source/Diagnostics/FieldIO.cpp
index 209d8e9b4..b1181f22f 100644
--- a/Source/Diagnostics/FieldIO.cpp
+++ b/Source/Diagnostics/FieldIO.cpp
@@ -299,7 +299,10 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
amrex::Vector<MultiFab>& mf_avg, const int ngrow) const
{
// Count how many different fields should be written (ncomp)
- const int ncomp = 3*3
+ const int ncomp = 0
+ + static_cast<int>(plot_E_field)*3
+ + static_cast<int>(plot_B_field)*3
+ + static_cast<int>(plot_J_field)*3
+ static_cast<int>(plot_part_per_cell)
+ static_cast<int>(plot_part_per_grid)
+ static_cast<int>(plot_part_per_proc)
@@ -321,15 +324,21 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
// Go through the different fields, pack them into mf_avg[lev],
// add the corresponding names to `varnames` and increment dcomp
int dcomp = 0;
- AverageAndPackVectorField(mf_avg[lev], current_fp[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"jx","jy","jz"}) varnames.push_back(name);
- dcomp += 3;
- AverageAndPackVectorField(mf_avg[lev], Efield_aux[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"Ex","Ey","Ez"}) varnames.push_back(name);
- dcomp += 3;
- AverageAndPackVectorField(mf_avg[lev], Bfield_aux[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"Bx","By","Bz"}) varnames.push_back(name);
- dcomp += 3;
+ if (plot_J_field) {
+ AverageAndPackVectorField(mf_avg[lev], current_fp[lev], dcomp, ngrow);
+ if(lev==0) for(auto name:{"jx","jy","jz"}) varnames.push_back(name);
+ dcomp += 3;
+ }
+ if (plot_E_field) {
+ AverageAndPackVectorField(mf_avg[lev], Efield_aux[lev], dcomp, ngrow);
+ if(lev==0) for(auto name:{"Ex","Ey","Ez"}) varnames.push_back(name);
+ dcomp += 3;
+ }
+ if (plot_B_field) {
+ AverageAndPackVectorField(mf_avg[lev], Bfield_aux[lev], dcomp, ngrow);
+ if(lev==0) for(auto name:{"Bx","By","Bz"}) varnames.push_back(name);
+ dcomp += 3;
+ }
if (plot_part_per_cell)
{
@@ -651,7 +660,6 @@ getInterpolatedScalar(
interpolated_F->setVal(0.);
// Loop through the boxes and interpolate the values from the _cp data
- const int use_limiter = 0;
#ifdef _OPEMP
#pragma omp parallel
#endif
@@ -669,7 +677,7 @@ getInterpolatedScalar(
if ( F_fp.is_nodal() ){
IntVect refinement_vector{AMREX_D_DECL(r_ratio, r_ratio, r_ratio)};
node_bilinear_interp.interp(cfab, 0, ffab, 0, 1,
- finebx, refinement_vector, {}, {}, {}, 0, 0);
+ finebx, refinement_vector, {}, {}, {}, 0, 0, RunOn::Cpu);
} else {
amrex::Abort("Unknown field staggering.");
}
diff --git a/Source/Diagnostics/Make.package b/Source/Diagnostics/Make.package
index 1c602ee33..dfd947d53 100644
--- a/Source/Diagnostics/Make.package
+++ b/Source/Diagnostics/Make.package
@@ -5,7 +5,8 @@ CEXE_sources += FieldIO.cpp
CEXE_headers += FieldIO.H
CEXE_headers += BoostedFrameDiagnostic.H
CEXE_headers += ElectrostaticIO.cpp
-F90EXE_sources += BoostedFrame_module.F90
+CEXE_headers += SliceDiagnostic.H
+CEXE_sources += SliceDiagnostic.cpp
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Diagnostics
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Diagnostics
diff --git a/Source/Diagnostics/ParticleIO.cpp b/Source/Diagnostics/ParticleIO.cpp
index f15c084a0..f2a543ed5 100644
--- a/Source/Diagnostics/ParticleIO.cpp
+++ b/Source/Diagnostics/ParticleIO.cpp
@@ -5,6 +5,53 @@
using namespace amrex;
void
+RigidInjectedParticleContainer::ReadHeader (std::istream& is)
+{
+ is >> charge >> mass;
+ WarpX::GotoNextLine(is);
+
+ int nlevs;
+ is >> nlevs;
+ WarpX::GotoNextLine(is);
+
+ AMREX_ASSERT(zinject_plane_levels.size() == 0);
+ AMREX_ASSERT(done_injecting.size() == 0);
+
+ for (int i = 0; i < nlevs; ++i)
+ {
+ int zinject_plane_tmp;
+ is >> zinject_plane_tmp;
+ zinject_plane_levels.push_back(zinject_plane_tmp);
+ WarpX::GotoNextLine(is);
+ }
+
+ for (int i = 0; i < nlevs; ++i)
+ {
+ int done_injecting_tmp;
+ is >> done_injecting_tmp;
+ done_injecting.push_back(done_injecting_tmp);
+ WarpX::GotoNextLine(is);
+ }
+}
+
+void
+RigidInjectedParticleContainer::WriteHeader (std::ostream& os) const
+{
+ // no need to write species_id
+ os << charge << " " << mass << "\n";
+ int nlevs = zinject_plane_levels.size();
+ os << nlevs << "\n";
+ for (int i = 0; i < nlevs; ++i)
+ {
+ os << zinject_plane_levels[i] << "\n";
+ }
+ for (int i = 0; i < nlevs; ++i)
+ {
+ os << done_injecting[i] << "\n";
+ }
+}
+
+void
WarpXParticleContainer::ReadHeader (std::istream& is)
{
is >> charge >> mass;
@@ -27,17 +74,55 @@ MultiParticleContainer::Checkpoint (const std::string& dir) const
}
void
-MultiParticleContainer::WritePlotFile (const std::string& dir,
- const Vector<int>& real_flags,
- const Vector<std::string>& real_names) const
+MultiParticleContainer::WritePlotFile (const std::string& dir) const
{
Vector<std::string> int_names;
Vector<int> int_flags;
-
+
for (unsigned i = 0, n = species_names.size(); i < n; ++i) {
- allcontainers[i]->WritePlotFile(dir, species_names[i],
- real_flags, int_flags,
- real_names, int_names);
+ auto& pc = allcontainers[i];
+ if (pc->plot_species) {
+
+ Vector<std::string> real_names;
+ real_names.push_back("weight");
+
+ real_names.push_back("momentum_x");
+ real_names.push_back("momentum_y");
+ real_names.push_back("momentum_z");
+
+ real_names.push_back("Ex");
+ real_names.push_back("Ey");
+ real_names.push_back("Ez");
+
+ real_names.push_back("Bx");
+ real_names.push_back("By");
+ real_names.push_back("Bz");
+
+#ifdef WARPX_RZ
+ real_names.push_back("theta");
+#endif
+
+ if (WarpX::do_boosted_frame_diagnostic && pc->DoBoostedFrameDiags())
+ {
+ real_names.push_back("xold");
+ real_names.push_back("yold");
+ real_names.push_back("zold");
+
+ real_names.push_back("uxold");
+ real_names.push_back("uyold");
+ real_names.push_back("uzold");
+ }
+
+ // Convert momentum to SI
+ pc->ConvertUnits(ConvertDirection::WarpX_to_SI);
+ // real_names contains a list of all particle attributes.
+ // pc->plot_flags is 1 or 0, whether quantity is dumped or not.
+ pc->WritePlotFile(dir, species_names[i],
+ pc->plot_flags, int_flags,
+ real_names, int_names);
+ // Convert momentum back to WarpX units
+ pc->ConvertUnits(ConvertDirection::SI_to_WarpX);
+ }
}
}
@@ -65,3 +150,43 @@ MultiParticleContainer::WriteHeader (std::ostream& os) const
}
}
+// Particle momentum is defined as gamma*velocity, which is neither
+// SI mass*gamma*velocity nor normalized gamma*velocity/c.
+// This converts momentum to SI units (or vice-versa) to write SI data
+// to file.
+void
+PhysicalParticleContainer::ConvertUnits(ConvertDirection convert_direction)
+{
+ BL_PROFILE("PPC::ConvertUnits()");
+
+ // Compute conversion factor
+ Real factor = 1;
+ if (convert_direction == ConvertDirection::WarpX_to_SI){
+ factor = mass;
+ } else if (convert_direction == ConvertDirection::SI_to_WarpX){
+ factor = 1./mass;
+ }
+
+ for (int lev=0; lev<=finestLevel(); lev++){
+#ifdef _OPENMP
+#pragma omp parallel if (Gpu::notInLaunchRegion())
+#endif
+ for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
+ {
+ // - momenta are stored as a struct of array, in `attribs`
+ auto& attribs = pti.GetAttribs();
+ Real* AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr();
+ Real* AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr();
+ Real* AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr();
+ // Loop over the particles and convert momentum
+ const long np = pti.numParticles();
+ ParallelFor( np,
+ [=] AMREX_GPU_DEVICE (long i) {
+ ux[i] *= factor;
+ uy[i] *= factor;
+ uz[i] *= factor;
+ }
+ );
+ }
+ }
+}
diff --git a/Source/Diagnostics/SliceDiagnostic.H b/Source/Diagnostics/SliceDiagnostic.H
new file mode 100644
index 000000000..31eea83be
--- /dev/null
+++ b/Source/Diagnostics/SliceDiagnostic.H
@@ -0,0 +1,42 @@
+#ifndef WARPX_SliceDiagnostic_H_
+#define WARPX_SliceDiagnostic_H_
+
+#include <AMReX_VisMF.H>
+#include <AMReX_PlotFileUtil.H>
+#include <AMReX_ParallelDescriptor.H>
+#include <AMReX_Geometry.H>
+
+#include <WarpX.H>
+#include <AMReX_FArrayBox.H>
+#include <AMReX_IArrayBox.H>
+#include <AMReX_Vector.H>
+#include <AMReX_BLassert.H>
+#include <AMReX_MultiFabUtil.H>
+#include <AMReX_MultiFabUtil_C.H>
+
+
+
+std::unique_ptr<amrex::MultiFab> CreateSlice( const amrex::MultiFab& mf,
+ const amrex::Vector<amrex::Geometry> &dom_geom,
+ amrex::RealBox &slice_realbox,
+ amrex::IntVect &slice_cr_ratio );
+
+void CheckSliceInput( const amrex::RealBox real_box,
+ amrex::RealBox &slice_cc_nd_box, amrex::RealBox &slice_realbox,
+ amrex::IntVect &slice_cr_ratio, amrex::Vector<amrex::Geometry> dom_geom,
+ amrex::IntVect const SliceType, amrex::IntVect &slice_lo,
+ amrex::IntVect &slice_hi, amrex::IntVect &interp_lo);
+
+void InterpolateSliceValues( amrex::MultiFab& smf,
+ amrex::IntVect interp_lo, amrex::RealBox slice_realbox,
+ amrex::Vector<amrex::Geometry> geom, int ncomp, int nghost,
+ amrex::IntVect slice_lo, amrex::IntVect slice_hi,
+ amrex::IntVect SliceType, const amrex::RealBox real_box);
+
+void InterpolateLo( const amrex::Box& bx, amrex::FArrayBox &fabox,
+ amrex::IntVect slice_lo, amrex::Vector<amrex::Geometry> geom,
+ int idir, amrex::IntVect IndType, amrex::RealBox slice_realbox,
+ int srccomp, int ncomp, int nghost, const amrex::RealBox real_box);
+
+#endif
+
diff --git a/Source/Diagnostics/SliceDiagnostic.cpp b/Source/Diagnostics/SliceDiagnostic.cpp
new file mode 100644
index 000000000..994f990c6
--- /dev/null
+++ b/Source/Diagnostics/SliceDiagnostic.cpp
@@ -0,0 +1,475 @@
+#include "SliceDiagnostic.H"
+#include <AMReX_MultiFabUtil.H>
+#include <AMReX_PlotFileUtil.H>
+#include <AMReX_FillPatchUtil_F.H>
+
+#include <WarpX.H>
+
+using namespace amrex;
+
+
+/* \brief
+ * The functions creates the slice for diagnostics based on the user-input.
+ * The slice can be 1D, 2D, or 3D and it inherts the index type of the underlying data.
+ * The implementation assumes that the slice is aligned with the coordinate axes.
+ * The input parameters are modified if the user-input does not comply with requirements of coarsenability or if the slice extent is not contained within the simulation domain.
+ * First a slice multifab (smf) with cell size equal to that of the simulation grid is created such that it extends from slice.dim_lo to slice.dim_hi and shares the same index space as the source multifab (mf)
+ * The values are copied from src mf to dst smf using amrex::ParallelCopy
+ * If interpolation is required, then on the smf, using data points stored in the ghost cells, the data in interpolated.
+ * If coarsening is required, then a coarse slice multifab is generated (cs_mf) and the
+ * values of the refined slice (smf) is averaged down to obtain the coarse slice.
+ * \param mf is the source multifab containing the field data
+ * \param dom_geom is the geometry of the domain and used in the function to obtain the
+ * CellSize of the underlying grid.
+ * \param slice_realbox defines the extent of the slice
+ * \param slice_cr_ratio provides the coarsening ratio for diagnostics
+ */
+
+std::unique_ptr<MultiFab>
+CreateSlice( const MultiFab& mf, const Vector<Geometry> &dom_geom,
+ RealBox &slice_realbox, IntVect &slice_cr_ratio )
+{
+ std::unique_ptr<MultiFab> smf;
+ std::unique_ptr<MultiFab> cs_mf;
+
+ Vector<int> slice_ncells(AMREX_SPACEDIM);
+ int nghost = 1;
+ int nlevels = dom_geom.size();
+ int ncomp = (mf).nComp();
+
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE( nlevels==1,
+ "Slice diagnostics does not work with mesh refinement yet (TO DO).");
+
+ const auto conversionType = (mf).ixType();
+ IntVect SliceType(AMREX_D_DECL(0,0,0));
+ for (int idim = 0; idim < AMREX_SPACEDIM; ++idim )
+ {
+ SliceType[idim] = conversionType.nodeCentered(idim);
+ }
+
+ const RealBox& real_box = dom_geom[0].ProbDomain();
+ RealBox slice_cc_nd_box;
+ int slice_grid_size = 32;
+
+ bool interpolate = false;
+ bool coarsen = false;
+
+ // same index space as domain //
+ IntVect slice_lo(AMREX_D_DECL(0,0,0));
+ IntVect slice_hi(AMREX_D_DECL(1,1,1));
+ IntVect interp_lo(AMREX_D_DECL(0,0,0));
+
+ CheckSliceInput(real_box, slice_cc_nd_box, slice_realbox, slice_cr_ratio,
+ dom_geom, SliceType, slice_lo,
+ slice_hi, interp_lo);
+ // Determine if interpolation is required and number of cells in slice //
+ for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
+
+ // Flag for interpolation if required //
+ if ( interp_lo[idim] == 1) {
+ interpolate = 1;
+ }
+
+ // For the case when a dimension is reduced //
+ if ( ( slice_hi[idim] - slice_lo[idim]) == 1) {
+ slice_ncells[idim] = 1;
+ }
+ else {
+ slice_ncells[idim] = ( slice_hi[idim] - slice_lo[idim] + 1 )
+ / slice_cr_ratio[idim];
+
+ int refined_ncells = slice_hi[idim] - slice_lo[idim] + 1 ;
+ if ( slice_cr_ratio[idim] > 1) {
+ coarsen = true;
+
+ // modify slice_grid_size if >= refines_cells //
+ if ( slice_grid_size >= refined_ncells ) {
+ slice_grid_size = refined_ncells - 1;
+ }
+
+ }
+ }
+ }
+
+ // Slice generation with index type inheritance //
+ Box slice(slice_lo, slice_hi);
+
+ Vector<BoxArray> sba(1);
+ sba[0].define(slice);
+ sba[0].maxSize(slice_grid_size);
+
+ // Distribution mapping for slice can be different from that of domain //
+ Vector<DistributionMapping> sdmap(1);
+ sdmap[0] = DistributionMapping{sba[0]};
+
+ smf.reset(new MultiFab(amrex::convert(sba[0],SliceType), sdmap[0],
+ ncomp, nghost));
+
+ // Copy data from domain to slice that has same cell size as that of //
+ // the domain mf. src and dst have the same number of ghost cells //
+ smf->ParallelCopy(mf, 0, 0, ncomp,nghost,nghost);
+
+ // inteprolate if required on refined slice //
+ if (interpolate == 1 ) {
+ InterpolateSliceValues( *smf, interp_lo, slice_cc_nd_box, dom_geom,
+ ncomp, nghost, slice_lo, slice_hi, SliceType, real_box);
+ }
+
+
+ if (coarsen == false) {
+ return smf;
+ }
+ else if ( coarsen == true ) {
+ Vector<BoxArray> crse_ba(1);
+ crse_ba[0] = sba[0];
+ crse_ba[0].coarsen(slice_cr_ratio);
+
+ AMREX_ALWAYS_ASSERT(crse_ba[0].size() == sba[0].size());
+
+ cs_mf.reset( new MultiFab(amrex::convert(crse_ba[0],SliceType),
+ sdmap[0], ncomp,nghost));
+
+ MultiFab& mfSrc = *smf;
+ MultiFab& mfDst = *cs_mf;
+
+ MFIter mfi_dst(mfDst);
+ for (MFIter mfi(mfSrc); mfi.isValid(); ++mfi) {
+
+ FArrayBox& Src_fabox = mfSrc[mfi];
+
+ const Box& Dst_bx = mfi_dst.validbox();
+ FArrayBox& Dst_fabox = mfDst[mfi_dst];
+
+ int scomp = 0;
+ int dcomp = 0;
+
+ IntVect cctype(AMREX_D_DECL(0,0,0));
+ if( SliceType==cctype ) {
+ amrex::amrex_avgdown(Dst_bx, Dst_fabox, Src_fabox, dcomp, scomp,
+ ncomp, slice_cr_ratio);
+ }
+ IntVect ndtype(AMREX_D_DECL(1,1,1));
+ if( SliceType == ndtype ) {
+ amrex::amrex_avgdown_nodes(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio);
+ }
+ if( SliceType == WarpX::Ex_nodal_flag ) {
+ amrex::amrex_avgdown_edges(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 0);
+ }
+ if( SliceType == WarpX::Ey_nodal_flag) {
+ amrex::amrex_avgdown_edges(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 1);
+ }
+ if( SliceType == WarpX::Ez_nodal_flag ) {
+ amrex::amrex_avgdown_edges(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 2);
+ }
+ if( SliceType == WarpX::Bx_nodal_flag) {
+ amrex::amrex_avgdown_faces(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 0);
+ }
+ if( SliceType == WarpX::By_nodal_flag ) {
+ amrex::amrex_avgdown_faces(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 1);
+ }
+ if( SliceType == WarpX::Bz_nodal_flag ) {
+ amrex::amrex_avgdown_faces(Dst_bx, Dst_fabox, Src_fabox, dcomp,
+ scomp, ncomp, slice_cr_ratio, 2);
+ }
+
+ if ( mfi_dst.isValid() ) {
+ ++mfi_dst;
+ }
+
+ }
+ return cs_mf;
+
+ }
+ amrex::Abort("Should not hit this return statement.");
+ return smf;
+}
+
+
+/* \brief
+ * This function modifies the slice input parameters under certain conditions.
+ * The coarsening ratio, slice_cr_ratio is modified if the input is not an exponent of 2.
+ * for example, if the coarsening ratio is 3, 5 or 6, which is not an exponent of 2,
+ * then the value of coarsening ratio is modified to the nearest exponent of 2.
+ * The default value for coarsening ratio is 1.
+ * slice_realbox.lo and slice_realbox.hi are set equal to the simulation domain lo and hi
+ * if for the user-input for the slice lo and hi coordinates are outside the domain.
+ * If the slice_realbox.lo and slice_realbox.hi coordinates do not align with the data
+ * points and the number of cells in that dimension is greater than 1, and if the extent of
+ * the slice in that dimension is not coarsenable, then the value lo and hi coordinates are
+ * shifted to the nearest coarsenable point to include some extra data points in the slice.
+ * If slice_realbox.lo==slice_realbox.hi, then that dimension has only one cell and no
+ * modifications are made to the value. If the lo and hi do not align with a data point,
+ * then it is flagged for interpolation.
+ * \param real_box a Real box defined for the underlying domain.
+ * \param slice_realbox a Real box for defining the slice dimension.
+ * \param slice_cc_nd_box a Real box for defining the modified lo and hi of the slice
+ * such that the coordinates align with the underlying data points.
+ * If the dimension is reduced to have only one cell, the slice_realbox is not modified and * instead the values are interpolated to the coordinate from the nearest data points.
+ * \param slice_cr_ratio contains values of the coarsening ratio which may be modified
+ * if the input values do not satisfy coarsenability conditions.
+ * \param slice_lo and slice_hi are the index values of the slice
+ * \param interp_lo are set to 0 or 1 if they are flagged for interpolation.
+ * The slice shares the same index space as that of the simulation domain.
+ */
+
+
+void
+CheckSliceInput( const RealBox real_box, RealBox &slice_cc_nd_box,
+ RealBox &slice_realbox, IntVect &slice_cr_ratio,
+ Vector<Geometry> dom_geom, IntVect const SliceType,
+ IntVect &slice_lo, IntVect &slice_hi, IntVect &interp_lo)
+{
+
+ IntVect slice_lo2(AMREX_D_DECL(0,0,0));
+ for ( int idim = 0; idim < AMREX_SPACEDIM; ++idim)
+ {
+ // Modify coarsening ratio if the input value is not an exponent of 2 for AMR //
+ if ( slice_cr_ratio[idim] > 0 ) {
+ int log_cr_ratio = floor ( log2( double(slice_cr_ratio[idim])));
+ slice_cr_ratio[idim] = exp2( double(log_cr_ratio) );
+ }
+
+ //// Default coarsening ratio is 1 //
+ // Modify lo if input is out of bounds //
+ if ( slice_realbox.lo(idim) < real_box.lo(idim) ) {
+ slice_realbox.setLo( idim, real_box.lo(idim));
+ amrex::Print() << " slice lo is out of bounds. " <<
+ " Modified it in dimension " << idim <<
+ " to be aligned with the domain box\n";
+ }
+
+ // Modify hi if input in out od bounds //
+ if ( slice_realbox.hi(idim) > real_box.hi(idim) ) {
+ slice_realbox.setHi( idim, real_box.hi(idim));
+ amrex::Print() << " slice hi is out of bounds." <<
+ " Modified it in dimension " << idim <<
+ " to be aligned with the domain box\n";
+ }
+
+ // Factor to ensure index values computation depending on index type //
+ double fac = ( 1.0 - SliceType[idim] )*dom_geom[0].CellSize(idim)*0.5;
+ // if dimension is reduced to one cell length //
+ if ( slice_realbox.hi(idim) - slice_realbox.lo(idim) <= 0)
+ {
+ slice_cc_nd_box.setLo( idim, slice_realbox.lo(idim) );
+ slice_cc_nd_box.setHi( idim, slice_realbox.hi(idim) );
+
+ if ( slice_cr_ratio[idim] > 1) slice_cr_ratio[idim] = 1;
+
+ // check for interpolation -- compute index lo with floor and ceil
+ if ( slice_cc_nd_box.lo(idim) - real_box.lo(idim) >= fac ) {
+ slice_lo[idim] = floor( ( (slice_cc_nd_box.lo(idim)
+ - (real_box.lo(idim) + fac ) )
+ / dom_geom[0].CellSize(idim)) + fac * 1E-10);
+ slice_lo2[idim] = ceil( ( (slice_cc_nd_box.lo(idim)
+ - (real_box.lo(idim) + fac) )
+ / dom_geom[0].CellSize(idim)) - fac * 1E-10 );
+ }
+ else {
+ slice_lo[idim] = round( (slice_cc_nd_box.lo(idim)
+ - (real_box.lo(idim) ) )
+ / dom_geom[0].CellSize(idim));
+ slice_lo2[idim] = ceil((slice_cc_nd_box.lo(idim)
+ - (real_box.lo(idim) ) )
+ / dom_geom[0].CellSize(idim) );
+ }
+
+ // flag for interpolation -- if reduced dimension location //
+ // does not align with data point //
+ if ( slice_lo[idim] == slice_lo2[idim]) {
+ if ( slice_cc_nd_box.lo(idim) - real_box.lo(idim) < fac ) {
+ interp_lo[idim] = 1;
+ }
+ }
+ else {
+ interp_lo[idim] = 1;
+ }
+
+ // ncells = 1 if dimension is reduced //
+ slice_hi[idim] = slice_lo[idim] + 1;
+ }
+ else
+ {
+ // moving realbox.lo and reabox.hi to nearest coarsenable grid point //
+ int index_lo = floor(((slice_realbox.lo(idim) + 1E-10
+ - (real_box.lo(idim))) / dom_geom[0].CellSize(idim)));
+ int index_hi = ceil(((slice_realbox.hi(idim) - 1E-10
+ - (real_box.lo(idim))) / dom_geom[0].CellSize(idim)));
+
+ bool modify_cr = true;
+
+ while ( modify_cr == true) {
+ int lo_new = index_lo;
+ int hi_new = index_hi;
+ int mod_lo = index_lo % slice_cr_ratio[idim];
+ int mod_hi = index_hi % slice_cr_ratio[idim];
+ modify_cr = false;
+
+ // To ensure that the index.lo is coarsenable //
+ if ( mod_lo > 0) {
+ lo_new = index_lo - mod_lo;
+ }
+ // To ensure that the index.hi is coarsenable //
+ if ( mod_hi > 0) {
+ hi_new = index_hi + (slice_cr_ratio[idim] - mod_hi);
+ }
+
+ // If modified index.hi is > baselinebox.hi, move the point //
+ // to the previous coarsenable point //
+ if ( (hi_new * dom_geom[0].CellSize(idim))
+ > real_box.hi(idim) - real_box.lo(idim) + dom_geom[0].CellSize(idim)*0.01 )
+ {
+ hi_new = index_hi - mod_hi;
+ }
+
+ if ( (hi_new - lo_new) == 0 ){
+ amrex::Print() << " Diagnostic Warning :: ";
+ amrex::Print() << " Coarsening ratio ";
+ amrex::Print() << slice_cr_ratio[idim] << " in dim "<< idim;
+ amrex::Print() << "is leading to zero cells for slice.";
+ amrex::Print() << " Thus reducing cr_ratio by half.\n";
+
+ slice_cr_ratio[idim] = slice_cr_ratio[idim]/2;
+ modify_cr = true;
+ }
+
+ if ( modify_cr == false ) {
+ index_lo = lo_new;
+ index_hi = hi_new;
+ }
+ slice_lo[idim] = index_lo;
+ slice_hi[idim] = index_hi - 1; // since default is cell-centered
+ }
+ slice_realbox.setLo( idim, index_lo * dom_geom[0].CellSize(idim)
+ + real_box.lo(idim) );
+ slice_realbox.setHi( idim, index_hi * dom_geom[0].CellSize(idim)
+ + real_box.lo(idim) );
+ slice_cc_nd_box.setLo( idim, slice_realbox.lo(idim) + fac );
+ slice_cc_nd_box.setHi( idim, slice_realbox.hi(idim) - fac );
+ }
+ }
+}
+
+
+/* \brief
+ * This function is called if the coordinates of the slice do not align with data points
+ * \param interp_lo is an IntVect which is flagged as 1, if interpolation
+ is required in the dimension.
+ */
+void
+InterpolateSliceValues(MultiFab& smf, IntVect interp_lo, RealBox slice_realbox,
+ Vector<Geometry> geom, int ncomp, int nghost,
+ IntVect slice_lo, IntVect slice_hi, IntVect SliceType,
+ const RealBox real_box)
+{
+ for (MFIter mfi(smf); mfi.isValid(); ++mfi)
+ {
+ const Box& bx = mfi.tilebox();
+ const auto IndType = smf.ixType();
+ const auto lo = amrex::lbound(bx);
+ const auto hi = amrex::ubound(bx);
+ FArrayBox& fabox = smf[mfi];
+
+ for ( int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
+ if ( interp_lo[idim] == 1 ) {
+ InterpolateLo( bx, fabox, slice_lo, geom, idim, SliceType,
+ slice_realbox, 0, ncomp, nghost, real_box);
+ }
+ }
+ }
+
+}
+
+void
+InterpolateLo(const Box& bx, FArrayBox &fabox, IntVect slice_lo,
+ Vector<Geometry> geom, int idir, IntVect IndType,
+ RealBox slice_realbox, int srccomp, int ncomp,
+ int nghost, const RealBox real_box )
+{
+ auto fabarr = fabox.array();
+ const auto lo = amrex::lbound(bx);
+ const auto hi = amrex::ubound(bx);
+ double fac = ( 1.0-IndType[idir] )*geom[0].CellSize(idir) * 0.5;
+ int imin = slice_lo[idir];
+ double minpos = imin*geom[0].CellSize(idir) + fac + real_box.lo(idir);
+ double maxpos = (imin+1)*geom[0].CellSize(idir) + fac + real_box.lo(idir);
+ double slice_minpos = slice_realbox.lo(idir) ;
+
+ switch (idir) {
+ case 0:
+ {
+ if ( imin >= lo.x && imin <= lo.x) {
+ for (int n = srccomp; n < srccomp + ncomp; ++n) {
+ 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) {
+ double minval = fabarr(i,j,k,n);
+ double maxval = fabarr(i+1,j,k,n);
+ double ratio = (maxval - minval) / (maxpos - minpos);
+ double xdiff = slice_minpos - minpos;
+ double newval = minval + xdiff * ratio;
+ fabarr(i,j,k,n) = newval;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ case 1:
+ {
+ if ( imin >= lo.y && imin <= lo.y) {
+ for (int n = srccomp; n < srccomp+ncomp; ++n) {
+ 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) {
+ double minval = fabarr(i,j,k,n);
+ double maxval = fabarr(i,j+1,k,n);
+ double ratio = (maxval - minval) / (maxpos - minpos);
+ double xdiff = slice_minpos - minpos;
+ double newval = minval + xdiff * ratio;
+ fabarr(i,j,k,n) = newval;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ if ( imin >= lo.z && imin <= lo.z) {
+ for (int n = srccomp; n < srccomp+ncomp; ++n) {
+ 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) {
+ double minval = fabarr(i,j,k,n);
+ double maxval = fabarr(i,j,k+1,n);
+ double ratio = (maxval - minval) / (maxpos - minpos);
+ double xdiff = slice_minpos - minpos;
+ double newval = minval + xdiff * ratio;
+ fabarr(i,j,k,n) = newval;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ }
+
+}
+
+
+
+
+
+
+
diff --git a/Source/Diagnostics/WarpXIO.cpp b/Source/Diagnostics/WarpXIO.cpp
index ccbdd280c..869d3580e 100644
--- a/Source/Diagnostics/WarpXIO.cpp
+++ b/Source/Diagnostics/WarpXIO.cpp
@@ -11,6 +11,8 @@
#include <AMReX_AmrMeshInSituBridge.H>
#endif
+#include "SliceDiagnostic.H"
+
#ifdef AMREX_USE_ASCENT
#include <ascent.hpp>
#include <AMReX_Conduit_Blueprint.H>
@@ -84,11 +86,11 @@ WarpX::WriteWarpXHeader(const std::string& name) const
// Geometry
for (int i = 0; i < AMREX_SPACEDIM; ++i) {
- HeaderFile << Geometry::ProbLo(i) << ' ';
+ HeaderFile << Geom(0).ProbLo(i) << ' ';
}
HeaderFile << '\n';
for (int i = 0; i < AMREX_SPACEDIM; ++i) {
- HeaderFile << Geometry::ProbHi(i) << ' ';
+ HeaderFile << Geom(0).ProbHi(i) << ' ';
}
HeaderFile << '\n';
@@ -283,7 +285,7 @@ WarpX::InitFromCheckpoint ()
}
}
- Geometry::ProbDomain(RealBox(prob_lo,prob_hi));
+ ResetProbDomain(RealBox(prob_lo,prob_hi));
for (int lev = 0; lev < nlevs; ++lev) {
BoxArray ba;
@@ -422,14 +424,14 @@ WarpX::GetCellCenteredData() {
AverageAndPackVectorField( *cc[lev], Efield_aux[lev], dcomp, ng );
dcomp += 3;
// then the magnetic field
- AverageAndPackVectorField( *cc[lev], Efield_aux[lev], dcomp, ng );
+ AverageAndPackVectorField( *cc[lev], Bfield_aux[lev], dcomp, ng );
dcomp += 3;
// then the current density
AverageAndPackVectorField( *cc[lev], current_fp[lev], dcomp, ng );
dcomp += 3;
+ // then the charge density
const std::unique_ptr<MultiFab>& charge_density = mypc->GetChargeDensity(lev);
AverageAndPackScalarField( *cc[lev], *charge_density, dcomp, ng );
-
cc[lev]->FillBoundary(geom[lev].periodicity());
}
@@ -612,36 +614,7 @@ WarpX::WritePlotFile () const
}
}
- Vector<std::string> particle_varnames;
- particle_varnames.push_back("weight");
-
- particle_varnames.push_back("momentum_x");
- particle_varnames.push_back("momentum_y");
- particle_varnames.push_back("momentum_z");
-
- particle_varnames.push_back("Ex");
- particle_varnames.push_back("Ey");
- particle_varnames.push_back("Ez");
-
- particle_varnames.push_back("Bx");
- particle_varnames.push_back("By");
- particle_varnames.push_back("Bz");
-
-#ifdef WARPX_RZ
- particle_varnames.push_back("theta");
-#endif
-
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- particle_varnames.push_back("xold");
- particle_varnames.push_back("yold");
- particle_varnames.push_back("zold");
-
- particle_varnames.push_back("uxold");
- particle_varnames.push_back("uyold");
- particle_varnames.push_back("uzold");
-#endif
-
- mypc->WritePlotFile(plotfilename, particle_plot_flags, particle_varnames);
+ mypc->WritePlotFile(plotfilename);
WriteJobInfo(plotfilename);
@@ -770,3 +743,94 @@ WarpX::WriteJobInfo (const std::string& dir) const
jobInfoFile.close();
}
}
+
+
+/* \brief
+ * The slice is ouput using visMF and can be visualized used amrvis.
+ */
+void
+WarpX::WriteSlicePlotFile () const
+{
+ if (F_fp[0] ) {
+ VisMF::Write( (*F_slice[0]), "vismf_F_slice");
+ }
+
+ if (rho_fp[0]) {
+ VisMF::Write( (*rho_slice[0]), "vismf_rho_slice");
+ }
+
+ VisMF::Write( (*Efield_slice[0][0]), amrex::Concatenate("vismf_Ex_slice_",istep[0]));
+ VisMF::Write( (*Efield_slice[0][1]), amrex::Concatenate("vismf_Ey_slice_",istep[0]));
+ VisMF::Write( (*Efield_slice[0][2]), amrex::Concatenate("vismf_Ez_slice_",istep[0]));
+ VisMF::Write( (*Bfield_slice[0][0]), amrex::Concatenate("vismf_Bx_slice_",istep[0]));
+ VisMF::Write( (*Bfield_slice[0][1]), amrex::Concatenate("vismf_By_slice_",istep[0]));
+ VisMF::Write( (*Bfield_slice[0][2]), amrex::Concatenate("vismf_Bz_slice_",istep[0]));
+ VisMF::Write( (*current_slice[0][0]), amrex::Concatenate("vismf_jx_slice_",istep[0]));
+ VisMF::Write( (*current_slice[0][1]), amrex::Concatenate("vismf_jy_slice_",istep[0]));
+ VisMF::Write( (*current_slice[0][2]), amrex::Concatenate("vismf_jz_slice_",istep[0]));
+
+}
+
+
+void
+WarpX::InitializeSliceMultiFabs ()
+{
+
+ int nlevels = Geom().size();
+
+ F_slice.resize(nlevels);
+ rho_slice.resize(nlevels);
+ current_slice.resize(nlevels);
+ Efield_slice.resize(nlevels);
+ Bfield_slice.resize(nlevels);
+
+}
+
+
+// To generate slice that inherits index type of underlying data //
+void
+WarpX::SliceGenerationForDiagnostics ()
+{
+
+ Vector<Geometry> dom_geom;
+ dom_geom = Geom();
+
+ if (F_fp[0] ) {
+ F_slice[0] = CreateSlice( *F_fp[0].get(), dom_geom, slice_realbox,
+ slice_cr_ratio );
+ }
+ if (rho_fp[0]) {
+ rho_slice[0] = CreateSlice( *rho_fp[0].get(), dom_geom, slice_realbox,
+ slice_cr_ratio );
+ }
+
+ for (int idim = 0; idim < 3; ++idim) {
+ Efield_slice[0][idim] = CreateSlice( *Efield_fp[0][idim].get(),
+ dom_geom, slice_realbox, slice_cr_ratio );
+ Bfield_slice[0][idim] = CreateSlice( *Bfield_fp[0][idim].get(),
+ dom_geom, slice_realbox, slice_cr_ratio );
+ current_slice[0][idim] = CreateSlice( *current_fp[0][idim].get(),
+ dom_geom, slice_realbox, slice_cr_ratio );
+ }
+
+
+}
+
+
+void
+WarpX::ClearSliceMultiFabs ()
+{
+
+ F_slice.clear();
+ rho_slice.clear();
+ current_slice.clear();
+ Efield_slice.clear();
+ Bfield_slice.clear();
+ F_slice.shrink_to_fit();
+ rho_slice.shrink_to_fit();
+ current_slice.shrink_to_fit();
+ Efield_slice.shrink_to_fit();
+ Bfield_slice.shrink_to_fit();
+
+}
+
diff --git a/Source/Evolve/WarpXEvolveEM.cpp b/Source/Evolve/WarpXEvolveEM.cpp
index 60b0b5fa3..4f33694cd 100644
--- a/Source/Evolve/WarpXEvolveEM.cpp
+++ b/Source/Evolve/WarpXEvolveEM.cpp
@@ -1,10 +1,10 @@
-
#include <cmath>
#include <limits>
#include <WarpX.H>
#include <WarpXConst.H>
#include <WarpX_f.H>
+#include <WarpXUtil.H>
#ifdef WARPX_USE_PY
#include <WarpX_py.H>
#endif
@@ -25,6 +25,10 @@ WarpX::EvolveEM (int numsteps)
static int last_check_file_step = 0;
static int last_insitu_step = 0;
+ if (do_compute_max_step_from_zmax){
+ computeMaxStepBoostAccelerator(geom[0]);
+ }
+
int numsteps_max;
if (numsteps < 0) { // Note that the default argument is numsteps = -1
numsteps_max = max_step;
@@ -38,7 +42,7 @@ WarpX::EvolveEM (int numsteps)
{
Real walltime_beg_step = amrex::second();
- // Start loop on time steps
+ // Start loop on time steps
amrex::Print() << "\nSTEP " << step+1 << " starts ...\n";
#ifdef WARPX_USE_PY
if (warpx_py_beforestep) warpx_py_beforestep();
@@ -53,16 +57,16 @@ WarpX::EvolveEM (int numsteps)
if (step > 0 && (step+1) % load_balance_int == 0)
{
LoadBalance();
- // Reset the costs to 0
- for (int lev = 0; lev <= finest_level; ++lev) {
- costs[lev]->setVal(0.0);
- }
+ // Reset the costs to 0
+ for (int lev = 0; lev <= finest_level; ++lev) {
+ costs[lev]->setVal(0.0);
+ }
}
for (int lev = 0; lev <= finest_level; ++lev) {
- // Perform running average of the costs
- // (Giving more importance to most recent costs)
- (*costs[lev].get()).mult( (1. - 2./load_balance_int) );
+ // Perform running average of the costs
+ // (Giving more importance to most recent costs)
+ (*costs[lev].get()).mult( (1. - 2./load_balance_int) );
}
}
@@ -80,12 +84,14 @@ WarpX::EvolveEM (int numsteps)
*Bfield_aux[lev][0],*Bfield_aux[lev][1],*Bfield_aux[lev][2]);
}
is_synchronized = false;
+
} else {
- // Beyond one step, we have E^{n} and B^{n}.
- // Particles have p^{n-1/2} and x^{n}.
+ // Beyond one step, we have E^{n} and B^{n}.
+ // Particles have p^{n-1/2} and x^{n}.
FillBoundaryE();
FillBoundaryB();
UpdateAuxilaryData();
+
}
if (do_subcycling == 0 || finest_level == 0) {
@@ -97,6 +103,10 @@ WarpX::EvolveEM (int numsteps)
amrex::Abort("Unsupported do_subcycling type");
}
+ if (num_mirrors>0){
+ applyMirrors(cur_time);
+ }
+
#ifdef WARPX_USE_PY
if (warpx_py_beforeEsolve) warpx_py_beforeEsolve();
#endif
@@ -105,8 +115,10 @@ WarpX::EvolveEM (int numsteps)
UpdateAuxilaryData();
for (int lev = 0; lev <= finest_level; ++lev) {
mypc->PushP(lev, 0.5*dt[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]);
+ *Efield_aux[lev][0],*Efield_aux[lev][1],
+ *Efield_aux[lev][2],
+ *Bfield_aux[lev][0],*Bfield_aux[lev][1],
+ *Bfield_aux[lev][2]);
}
is_synchronized = true;
}
@@ -118,18 +130,20 @@ WarpX::EvolveEM (int numsteps)
++istep[lev];
}
- cur_time += dt[0];
+ cur_time += dt[0];
bool to_make_plot = (plot_int > 0) && ((step+1) % plot_int == 0);
+ // slice generation //
+ bool to_make_slice_plot = (slice_plot_int > 0) && ( (step+1)% slice_plot_int == 0);
bool do_insitu = ((step+1) >= insitu_start) &&
- (insitu_int > 0) && ((step+1) % insitu_int == 0);
+ (insitu_int > 0) && ((step+1) % insitu_int == 0);
bool move_j = is_synchronized || to_make_plot || do_insitu;
// If is_synchronized we need to shift j too so that next step we can evolve E by dt/2.
// We might need to move j because we are going to make a plotfile.
- int num_moved = MoveWindow(move_j);
+ int num_moved = MoveWindow(move_j);
if (max_level == 0) {
int num_redistribute_ghost = num_moved + 1;
@@ -139,11 +153,11 @@ WarpX::EvolveEM (int numsteps)
mypc->Redistribute();
}
- bool to_sort = (sort_int > 0) && ((step+1) % sort_int == 0);
- if (to_sort) {
- amrex::Print() << "re-sorting particles \n";
- mypc->SortParticlesByCell();
- }
+ bool to_sort = (sort_int > 0) && ((step+1) % sort_int == 0);
+ if (to_sort) {
+ amrex::Print() << "re-sorting particles \n";
+ mypc->SortParticlesByCell();
+ }
amrex::Print()<< "STEP " << step+1 << " ends." << " TIME = " << cur_time
<< " DT = " << dt[0] << "\n";
@@ -153,10 +167,10 @@ WarpX::EvolveEM (int numsteps)
<< " s; This step = " << walltime_end_step-walltime_beg_step
<< " s; Avg. per step = " << walltime/(step+1) << " s\n";
- // sync up time
- for (int i = 0; i <= max_level; ++i) {
- t_new[i] = cur_time;
- }
+ // sync up time
+ for (int i = 0; i <= max_level; ++i) {
+ t_new[i] = cur_time;
+ }
if (do_boosted_frame_diagnostic) {
std::unique_ptr<MultiFab> cell_centered_data = nullptr;
@@ -166,7 +180,8 @@ WarpX::EvolveEM (int numsteps)
myBFD->writeLabFrameData(cell_centered_data.get(), *mypc, geom[0], cur_time, dt[0]);
}
- if (to_make_plot || do_insitu)
+ // slice gen //
+ if (to_make_plot || do_insitu || to_make_slice_plot)
{
FillBoundaryE();
FillBoundaryB();
@@ -178,34 +193,42 @@ WarpX::EvolveEM (int numsteps)
*Bfield_aux[lev][0],*Bfield_aux[lev][1],*Bfield_aux[lev][2]);
}
- last_plot_file_step = step+1;
- last_insitu_step = step+1;
-
- if (to_make_plot)
- WritePlotFile();
+ last_plot_file_step = step+1;
+ last_insitu_step = step+1;
- if (do_insitu)
- UpdateInSitu();
- }
+ if (to_make_plot)
+ WritePlotFile();
+ if (to_make_slice_plot)
+ {
+ InitializeSliceMultiFabs ();
+ SliceGenerationForDiagnostics();
+ WriteSlicePlotFile();
+ ClearSliceMultiFabs ();
+ }
- if (check_int > 0 && (step+1) % check_int == 0) {
- last_check_file_step = step+1;
- WriteCheckPointFile();
+ if (do_insitu)
+ UpdateInSitu();
}
- if (cur_time >= stop_time - 1.e-3*dt[0]) {
- max_time_reached = true;
- break;
- }
+ if (check_int > 0 && (step+1) % check_int == 0) {
+ last_check_file_step = step+1;
+ WriteCheckPointFile();
+ }
+
+ if (cur_time >= stop_time - 1.e-3*dt[0]) {
+ max_time_reached = true;
+ break;
+ }
#ifdef WARPX_USE_PY
if (warpx_py_afterstep) warpx_py_afterstep();
#endif
- // End loop on time steps
+ // End loop on time steps
}
- bool write_plot_file = plot_int > 0 && istep[0] > last_plot_file_step && (max_time_reached || istep[0] >= max_step);
+ bool write_plot_file = plot_int > 0 && istep[0] > last_plot_file_step
+ && (max_time_reached || istep[0] >= max_step);
bool do_insitu = (insitu_start >= istep[0]) && (insitu_int > 0) &&
(istep[0] > last_insitu_step) && (max_time_reached || istep[0] >= max_step);
@@ -218,8 +241,10 @@ WarpX::EvolveEM (int numsteps)
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]);
+ *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)
@@ -229,8 +254,9 @@ WarpX::EvolveEM (int numsteps)
UpdateInSitu();
}
- if (check_int > 0 && istep[0] > last_check_file_step && (max_time_reached || istep[0] >= max_step)) {
- WriteCheckPointFile();
+ if (check_int > 0 && istep[0] > last_check_file_step &&
+ (max_time_reached || istep[0] >= max_step)) {
+ WriteCheckPointFile();
}
if (do_boosted_frame_diagnostic) {
@@ -259,6 +285,7 @@ WarpX::OneStep_nosub (Real cur_time)
if (warpx_py_beforedeposition) warpx_py_beforedeposition();
#endif
PushParticlesandDepose(cur_time);
+
#ifdef WARPX_USE_PY
if (warpx_py_afterdeposition) warpx_py_afterdeposition();
#endif
@@ -462,23 +489,23 @@ WarpX::ComputeDt ()
Real deltat = 0.;
if (maxwell_fdtd_solver_id == 0) {
- // CFL time step Yee solver
+ // CFL time step Yee solver
#ifdef WARPX_RZ
- // Derived semi-analytically by R. Lehe
- deltat = cfl * 1./( std::sqrt((1+0.2105)/(dx[0]*dx[0]) + 1./(dx[1]*dx[1])) * PhysConst::c );
+ // Derived semi-analytically by R. Lehe
+ deltat = cfl * 1./( std::sqrt((1+0.2105)/(dx[0]*dx[0]) + 1./(dx[1]*dx[1])) * PhysConst::c );
#else
- deltat = cfl * 1./( std::sqrt(AMREX_D_TERM( 1./(dx[0]*dx[0]),
- + 1./(dx[1]*dx[1]),
- + 1./(dx[2]*dx[2]))) * PhysConst::c );
+ deltat = cfl * 1./( std::sqrt(AMREX_D_TERM( 1./(dx[0]*dx[0]),
+ + 1./(dx[1]*dx[1]),
+ + 1./(dx[2]*dx[2]))) * PhysConst::c );
#endif
} else {
- // CFL time step CKC solver
+ // CFL time step CKC solver
#if (BL_SPACEDIM == 3)
- const Real delta = std::min(dx[0],std::min(dx[1],dx[2]));
+ const Real delta = std::min(dx[0],std::min(dx[1],dx[2]));
#elif (BL_SPACEDIM == 2)
- const Real delta = std::min(dx[0],dx[1]);
+ const Real delta = std::min(dx[0],dx[1]);
#endif
- deltat = cfl*delta/PhysConst::c;
+ deltat = cfl*delta/PhysConst::c;
}
dt.resize(0);
dt.resize(max_level+1,deltat);
@@ -493,3 +520,105 @@ WarpX::ComputeDt ()
dt[0] = const_dt;
}
}
+
+/* \brief computes max_step for wakefield simulation in boosted frame.
+ * \param geom: Geometry object that contains simulation domain.
+ *
+ * max_step is set so that the simulation stop when the lower corner of the
+ * simulation box passes input parameter zmax_plasma_to_compute_max_step.
+ */
+void
+WarpX::computeMaxStepBoostAccelerator(amrex::Geometry a_geom){
+ // Sanity checks: can use zmax_plasma_to_compute_max_step only if
+ // the moving window and the boost are all in z direction.
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ WarpX::moving_window_dir == AMREX_SPACEDIM-1,
+ "Can use zmax_plasma_to_compute_max_step only if " +
+ "moving window along z. TODO: all directions.");
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ maxLevel() == 0,
+ "Can use zmax_plasma_to_compute_max_step only if " +
+ "max level = 0.");
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ (WarpX::boost_direction[0]-0)*(WarpX::boost_direction[0]-0) +
+ (WarpX::boost_direction[1]-0)*(WarpX::boost_direction[1]-0) +
+ (WarpX::boost_direction[2]-1)*(WarpX::boost_direction[2]-1) < 1.e-12,
+ "Can use zmax_plasma_to_compute_max_step only if " +
+ "warpx.boost_direction = z. TODO: all directions.");
+
+ // Lower end of the simulation domain. All quantities are given in boosted
+ // frame except zmax_plasma_to_compute_max_step.
+ const Real zmin_domain_boost = a_geom.ProbLo(AMREX_SPACEDIM-1);
+ // End of the plasma: Transform input argument
+ // zmax_plasma_to_compute_max_step to boosted frame.
+ const Real len_plasma_boost = zmax_plasma_to_compute_max_step/gamma_boost;
+ // Plasma velocity
+ const Real v_plasma_boost = -beta_boost * PhysConst::c;
+ // Get time at which the lower end of the simulation domain passes the
+ // upper end of the plasma (in the z direction).
+ const Real interaction_time_boost = (len_plasma_boost-zmin_domain_boost)/
+ (moving_window_v-v_plasma_boost);
+ // Divide by dt, and update value of max_step.
+ const int computed_max_step = interaction_time_boost/dt[0];
+ max_step = computed_max_step;
+ Print()<<"max_step computed in computeMaxStepBoostAccelerator: "
+ <<computed_max_step<<std::endl;
+}
+
+/* \brief Apply perfect mirror condition inside the box (not at a boundary).
+ * In practice, set all fields to 0 on a section of the simulation domain
+ * (as for a perfect conductor with a given thickness).
+ * The mirror normal direction has to be parallel to the z axis.
+ */
+void
+WarpX::applyMirrors(Real time){
+ // Loop over the mirrors
+ for(int i_mirror=0; i_mirror<num_mirrors; ++i_mirror){
+ // Get mirror properties (lower and upper z bounds)
+ Real z_min = mirror_z[i_mirror];
+ Real z_max_tmp = z_min + mirror_z_width[i_mirror];
+ // Boost quantities for boosted frame simulations
+ if (gamma_boost>1){
+ z_min = z_min/gamma_boost - PhysConst::c*beta_boost*time;
+ z_max_tmp = z_max_tmp/gamma_boost - PhysConst::c*beta_boost*time;
+ }
+ // Loop over levels
+ for(int lev=0; lev<=finest_level; lev++){
+ // Make sure that the mirror contains at least
+ // mirror_z_npoints[i_mirror] cells
+ Real dz = WarpX::CellSize(lev)[2];
+ Real z_max = std::max(z_max_tmp,
+ z_min+mirror_z_npoints[i_mirror]*dz);
+ // Get fine patch field MultiFabs
+ MultiFab& Ex = *Efield_fp[lev][0].get();
+ MultiFab& Ey = *Efield_fp[lev][1].get();
+ MultiFab& Ez = *Efield_fp[lev][2].get();
+ MultiFab& Bx = *Bfield_fp[lev][0].get();
+ MultiFab& By = *Bfield_fp[lev][1].get();
+ MultiFab& Bz = *Bfield_fp[lev][2].get();
+ // Set each field to zero between z_min and z_max
+ NullifyMF(Ex, lev, z_min, z_max);
+ NullifyMF(Ey, lev, z_min, z_max);
+ NullifyMF(Ez, lev, z_min, z_max);
+ NullifyMF(Bx, lev, z_min, z_max);
+ NullifyMF(By, lev, z_min, z_max);
+ NullifyMF(Bz, lev, z_min, z_max);
+ if (lev>0){
+ // Get coarse patch field MultiFabs
+ MultiFab& cEx = *Efield_cp[lev][0].get();
+ MultiFab& cEy = *Efield_cp[lev][1].get();
+ MultiFab& cEz = *Efield_cp[lev][2].get();
+ MultiFab& cBx = *Bfield_cp[lev][0].get();
+ MultiFab& cBy = *Bfield_cp[lev][1].get();
+ MultiFab& cBz = *Bfield_cp[lev][2].get();
+ // Set each field to zero between z_min and z_max
+ NullifyMF(cEx, lev, z_min, z_max);
+ NullifyMF(cEy, lev, z_min, z_max);
+ NullifyMF(cEz, lev, z_min, z_max);
+ NullifyMF(cBx, lev, z_min, z_max);
+ NullifyMF(cBy, lev, z_min, z_max);
+ NullifyMF(cBz, lev, z_min, z_max);
+ }
+ }
+ }
+}
diff --git a/Source/FieldSolver/SpectralSolver/Make.package b/Source/FieldSolver/SpectralSolver/Make.package
index 50127914d..b0ee54095 100644
--- a/Source/FieldSolver/SpectralSolver/Make.package
+++ b/Source/FieldSolver/SpectralSolver/Make.package
@@ -1,11 +1,12 @@
CEXE_headers += WarpX_Complex.H
CEXE_headers += SpectralSolver.H
+CEXE_sources += SpectralSolver.cpp
CEXE_headers += SpectralFieldData.H
CEXE_sources += SpectralFieldData.cpp
-CEXE_headers += PsatdAlgorithm.H
-CEXE_sources += PsatdAlgorithm.cpp
CEXE_headers += SpectralKSpace.H
CEXE_sources += SpectralKSpace.cpp
+include $(WARPX_HOME)/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
+
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/FieldSolver/SpectralSolver
VPATH_LOCATIONS += $(WARPX_HOME)/Source/FieldSolver/SpectralSolver
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
new file mode 100644
index 000000000..c62c21f44
--- /dev/null
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
@@ -0,0 +1,6 @@
+CEXE_headers += SpectralBaseAlgorithm.H
+CEXE_headers += PsatdAlgorithm.H
+CEXE_sources += PsatdAlgorithm.cpp
+
+INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/FieldSolver/SpectralSolver/SpectralAlgorithms
+VPATH_LOCATIONS += $(WARPX_HOME)/Source/FieldSolver/SpectralSolver/SpectralAlgorithms
diff --git a/Source/FieldSolver/SpectralSolver/PsatdAlgorithm.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H
index acefcc466..12718e38b 100644
--- a/Source/FieldSolver/SpectralSolver/PsatdAlgorithm.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H
@@ -1,31 +1,27 @@
#ifndef WARPX_PSATD_ALGORITHM_H_
#define WARPX_PSATD_ALGORITHM_H_
-#include <SpectralKSpace.H>
-#include <SpectralFieldData.H>
+#include <SpectralBaseAlgorithm.H>
/* \brief Class that updates the field in spectral space
* and stores the coefficients of the corresponding update equation.
*/
-class PsatdAlgorithm
+class PsatdAlgorithm : public SpectralBaseAlgorithm
{
- using SpectralCoefficients = amrex::FabArray< amrex::BaseFab <amrex::Real> >;
public:
PsatdAlgorithm(const SpectralKSpace& spectral_kspace,
const amrex::DistributionMapping& dm,
const int norder_x, const int norder_y,
const int norder_z, const bool nodal, const amrex::Real dt);
- PsatdAlgorithm() = default; // Default constructor
- PsatdAlgorithm& operator=(PsatdAlgorithm&& algorithm) = default;
- void pushSpectralFields(SpectralFieldData& f) const;
+
+ void InitializeSpectralCoefficients(const SpectralKSpace& spectral_kspace,
+ const amrex::DistributionMapping& dm,
+ const amrex::Real dt);
+
+ void pushSpectralFields(SpectralFieldData& f) const override final;
private:
- // Modified finite-order vectors
- KVectorComponent modified_kx_vec, modified_kz_vec;
-#if (AMREX_SPACEDIM==3)
- KVectorComponent modified_ky_vec;
-#endif
SpectralCoefficients C_coef, S_ck_coef, X1_coef, X2_coef, X3_coef;
};
diff --git a/Source/FieldSolver/SpectralSolver/PsatdAlgorithm.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp
index 56e58bcc4..d45b01bda 100644
--- a/Source/FieldSolver/SpectralSolver/PsatdAlgorithm.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp
@@ -9,14 +9,9 @@ PsatdAlgorithm::PsatdAlgorithm(const SpectralKSpace& spectral_kspace,
const DistributionMapping& dm,
const int norder_x, const int norder_y,
const int norder_z, const bool nodal, const Real dt)
-// Compute and assign the modified k vectors
-: modified_kx_vec(spectral_kspace.getModifiedKComponent(dm,0,norder_x,nodal)),
-#if (AMREX_SPACEDIM==3)
- modified_ky_vec(spectral_kspace.getModifiedKComponent(dm,1,norder_y,nodal)),
- modified_kz_vec(spectral_kspace.getModifiedKComponent(dm,2,norder_z,nodal))
-#else
- modified_kz_vec(spectral_kspace.getModifiedKComponent(dm,1,norder_z,nodal))
-#endif
+ // Initialize members of base class
+ : SpectralBaseAlgorithm( spectral_kspace, dm,
+ norder_x, norder_y, norder_z, nodal )
{
const BoxArray& ba = spectral_kspace.spectralspace_ba;
@@ -27,57 +22,8 @@ PsatdAlgorithm::PsatdAlgorithm(const SpectralKSpace& spectral_kspace,
X2_coef = SpectralCoefficients(ba, dm, 1, 0);
X3_coef = SpectralCoefficients(ba, dm, 1, 0);
- // Fill them with the right values:
- // Loop over boxes and allocate the corresponding coefficients
- // for each box owned by the local MPI proc
- for (MFIter mfi(ba, dm); mfi.isValid(); ++mfi){
-
- const Box& bx = ba[mfi];
-
- // Extract pointers for the k vectors
- const Real* modified_kx = modified_kx_vec[mfi].dataPtr();
-#if (AMREX_SPACEDIM==3)
- const Real* modified_ky = modified_ky_vec[mfi].dataPtr();
-#endif
- const Real* modified_kz = modified_kz_vec[mfi].dataPtr();
- // Extract arrays for the coefficients
- Array4<Real> C = C_coef[mfi].array();
- Array4<Real> S_ck = S_ck_coef[mfi].array();
- Array4<Real> X1 = X1_coef[mfi].array();
- Array4<Real> X2 = X2_coef[mfi].array();
- Array4<Real> X3 = X3_coef[mfi].array();
-
- // Loop over indices within one box
- ParallelFor(bx,
- [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
- {
- // Calculate norm of vector
- const Real k_norm = std::sqrt(
- std::pow(modified_kx[i], 2) +
-#if (AMREX_SPACEDIM==3)
- std::pow(modified_ky[j], 2) +
-#endif
- std::pow(modified_kz[k], 2));
-
- // Calculate coefficients
- constexpr Real c = PhysConst::c;
- constexpr Real ep0 = PhysConst::ep0;
- if (k_norm != 0){
- C(i,j,k) = std::cos(c*k_norm*dt);
- S_ck(i,j,k) = std::sin(c*k_norm*dt)/(c*k_norm);
- X1(i,j,k) = (1. - C(i,j,k))/(ep0 * c*c * k_norm*k_norm);
- X2(i,j,k) = (1. - S_ck(i,j,k)/dt)/(ep0 * k_norm*k_norm);
- X3(i,j,k) = (C(i,j,k) - S_ck(i,j,k)/dt)/(ep0 * k_norm*k_norm);
- } else { // Handle k_norm = 0, by using the analytical limit
- C(i,j,k) = 1.;
- S_ck(i,j,k) = dt;
- X1(i,j,k) = 0.5 * dt*dt / ep0;
- X2(i,j,k) = c*c * dt*dt / (6.*ep0);
- X3(i,j,k) = - c*c * dt*dt / (3.*ep0);
- }
- });
- }
-};
+ InitializeSpectralCoefficients(spectral_kspace, dm, dt);
+}
/* Advance the E and B field in spectral space (stored in `f`)
* over one time step */
@@ -85,23 +31,12 @@ void
PsatdAlgorithm::pushSpectralFields(SpectralFieldData& f) const{
// Loop over boxes
- for (MFIter mfi(f.Ex); mfi.isValid(); ++mfi){
+ for (MFIter mfi(f.fields); mfi.isValid(); ++mfi){
- const Box& bx = f.Ex[mfi].box();
+ const Box& bx = f.fields[mfi].box();
// Extract arrays for the fields to be updated
- Array4<Complex> Ex_arr = f.Ex[mfi].array();
- Array4<Complex> Ey_arr = f.Ey[mfi].array();
- Array4<Complex> Ez_arr = f.Ez[mfi].array();
- Array4<Complex> Bx_arr = f.Bx[mfi].array();
- Array4<Complex> By_arr = f.By[mfi].array();
- Array4<Complex> Bz_arr = f.Bz[mfi].array();
- // Extract arrays for J and rho
- Array4<const Complex> Jx_arr = f.Jx[mfi].array();
- Array4<const Complex> Jy_arr = f.Jy[mfi].array();
- Array4<const Complex> Jz_arr = f.Jz[mfi].array();
- Array4<const Complex> rho_old_arr = f.rho_old[mfi].array();
- Array4<const Complex> rho_new_arr = f.rho_new[mfi].array();
+ Array4<Complex> fields = f.fields[mfi].array();
// Extract arrays for the coefficients
Array4<const Real> C_arr = C_coef[mfi].array();
Array4<const Real> S_ck_arr = S_ck_coef[mfi].array();
@@ -120,55 +55,118 @@ PsatdAlgorithm::pushSpectralFields(SpectralFieldData& f) const{
[=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
{
// Record old values of the fields to be updated
- const Complex Ex_old = Ex_arr(i,j,k);
- const Complex Ey_old = Ey_arr(i,j,k);
- const Complex Ez_old = Ez_arr(i,j,k);
- const Complex Bx_old = Bx_arr(i,j,k);
- const Complex By_old = By_arr(i,j,k);
- const Complex Bz_old = Bz_arr(i,j,k);
+ using Idx = SpectralFieldIndex;
+ const Complex Ex_old = fields(i,j,k,Idx::Ex);
+ const Complex Ey_old = fields(i,j,k,Idx::Ey);
+ const Complex Ez_old = fields(i,j,k,Idx::Ez);
+ const Complex Bx_old = fields(i,j,k,Idx::Bx);
+ const Complex By_old = fields(i,j,k,Idx::By);
+ const Complex Bz_old = fields(i,j,k,Idx::Bz);
// Shortcut for the values of J and rho
- const Complex Jx = Jx_arr(i,j,k);
- const Complex Jy = Jy_arr(i,j,k);
- const Complex Jz = Jz_arr(i,j,k);
- const Complex rho_old = rho_old_arr(i,j,k);
- const Complex rho_new = rho_new_arr(i,j,k);
+ const Complex Jx = fields(i,j,k,Idx::Jx);
+ const Complex Jy = fields(i,j,k,Idx::Jy);
+ const Complex Jz = fields(i,j,k,Idx::Jz);
+ const Complex rho_old = fields(i,j,k,Idx::rho_old);
+ const Complex rho_new = fields(i,j,k,Idx::rho_new);
// k vector values, and coefficients
const Real kx = modified_kx_arr[i];
#if (AMREX_SPACEDIM==3)
const Real ky = modified_ky_arr[j];
+ const Real kz = modified_kz_arr[k];
#else
constexpr Real ky = 0;
+ const Real kz = modified_kz_arr[j];
#endif
- const Real kz = modified_kz_arr[k];
constexpr Real c2 = PhysConst::c*PhysConst::c;
constexpr Real inv_ep0 = 1./PhysConst::ep0;
- constexpr Complex I = Complex{0,1};
+ const Complex I = Complex{0,1};
const Real C = C_arr(i,j,k);
const Real S_ck = S_ck_arr(i,j,k);
const Real X1 = X1_arr(i,j,k);
const Real X2 = X2_arr(i,j,k);
const Real X3 = X3_arr(i,j,k);
+
// Update E (see WarpX online documentation: theory section)
- Ex_arr(i,j,k) = C*Ex_old
+ fields(i,j,k,Idx::Ex) = C*Ex_old
+ S_ck*(c2*I*(ky*Bz_old - kz*By_old) - inv_ep0*Jx)
- I*(X2*rho_new - X3*rho_old)*kx;
- Ey_arr(i,j,k) = C*Ey_old
+ fields(i,j,k,Idx::Ey) = C*Ey_old
+ S_ck*(c2*I*(kz*Bx_old - kx*Bz_old) - inv_ep0*Jy)
- I*(X2*rho_new - X3*rho_old)*ky;
- Ez_arr(i,j,k) = C*Ez_old
+ fields(i,j,k,Idx::Ez) = C*Ez_old
+ S_ck*(c2*I*(kx*By_old - ky*Bx_old) - inv_ep0*Jz)
- I*(X2*rho_new - X3*rho_old)*kz;
// Update B (see WarpX online documentation: theory section)
- Bx_arr(i,j,k) = C*Bx_old
+ fields(i,j,k,Idx::Bx) = C*Bx_old
- S_ck*I*(ky*Ez_old - kz*Ey_old)
+ X1*I*(ky*Jz - kz*Jy);
- By_arr(i,j,k) = C*By_old
+ fields(i,j,k,Idx::By) = C*By_old
- S_ck*I*(kz*Ex_old - kx*Ez_old)
+ X1*I*(kz*Jx - kx*Jz);
- Bz_arr(i,j,k) = C*Bz_old
+ fields(i,j,k,Idx::Bz) = C*Bz_old
- S_ck*I*(kx*Ey_old - ky*Ex_old)
+ X1*I*(kx*Jy - ky*Jx);
});
}
};
+
+void PsatdAlgorithm::InitializeSpectralCoefficients(const SpectralKSpace& spectral_kspace,
+ const amrex::DistributionMapping& dm,
+ const amrex::Real dt)
+{
+ const BoxArray& ba = spectral_kspace.spectralspace_ba;
+ // Fill them with the right values:
+ // Loop over boxes and allocate the corresponding coefficients
+ // for each box owned by the local MPI proc
+ for (MFIter mfi(ba, dm); mfi.isValid(); ++mfi){
+
+ const Box& bx = ba[mfi];
+
+ // Extract pointers for the k vectors
+ const Real* modified_kx = modified_kx_vec[mfi].dataPtr();
+#if (AMREX_SPACEDIM==3)
+ const Real* modified_ky = modified_ky_vec[mfi].dataPtr();
+#endif
+ const Real* modified_kz = modified_kz_vec[mfi].dataPtr();
+ // Extract arrays for the coefficients
+ Array4<Real> C = C_coef[mfi].array();
+ Array4<Real> S_ck = S_ck_coef[mfi].array();
+ Array4<Real> X1 = X1_coef[mfi].array();
+ Array4<Real> X2 = X2_coef[mfi].array();
+ Array4<Real> X3 = X3_coef[mfi].array();
+
+ // Loop over indices within one box
+ ParallelFor(bx,
+ [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
+ {
+ // Calculate norm of vector
+ const Real k_norm = std::sqrt(
+ std::pow(modified_kx[i], 2) +
+#if (AMREX_SPACEDIM==3)
+ std::pow(modified_ky[j], 2) +
+ std::pow(modified_kz[k], 2));
+#else
+ std::pow(modified_kz[j], 2));
+#endif
+
+
+ // Calculate coefficients
+ constexpr Real c = PhysConst::c;
+ constexpr Real ep0 = PhysConst::ep0;
+ if (k_norm != 0){
+ C(i,j,k) = std::cos(c*k_norm*dt);
+ S_ck(i,j,k) = std::sin(c*k_norm*dt)/(c*k_norm);
+ X1(i,j,k) = (1. - C(i,j,k))/(ep0 * c*c * k_norm*k_norm);
+ X2(i,j,k) = (1. - S_ck(i,j,k)/dt)/(ep0 * k_norm*k_norm);
+ X3(i,j,k) = (C(i,j,k) - S_ck(i,j,k)/dt)/(ep0 * k_norm*k_norm);
+ } else { // Handle k_norm = 0, by using the analytical limit
+ C(i,j,k) = 1.;
+ S_ck(i,j,k) = dt;
+ X1(i,j,k) = 0.5 * dt*dt / ep0;
+ X2(i,j,k) = c*c * dt*dt / (6.*ep0);
+ X3(i,j,k) = - c*c * dt*dt / (3.*ep0);
+ }
+ });
+ }
+}
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H
new file mode 100644
index 000000000..602eb2473
--- /dev/null
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H
@@ -0,0 +1,51 @@
+#ifndef WARPX_SPECTRAL_BASE_ALGORITHM_H_
+#define WARPX_SPECTRAL_BASE_ALGORITHM_H_
+
+#include <SpectralKSpace.H>
+#include <SpectralFieldData.H>
+
+/* \brief Class that updates the field in spectral space
+ * and stores the coefficients of the corresponding update equation.
+ *
+ * `SpectralBaseAlgorithm` is only a base class and cannot be used directly.
+ * Instead use its subclasses, which implement the specific field update
+ * equations for a given spectral algorithm.
+ */
+class SpectralBaseAlgorithm
+{
+ public:
+ // Member function that updates the fields in spectral space ;
+ // meant to be overridden in subclasses
+ virtual void pushSpectralFields(SpectralFieldData& f) const = 0;
+ // The destructor should also be a virtual function, so that
+ // a pointer to subclass of `SpectraBaseAlgorithm` actually
+ // calls the subclass's destructor.
+ virtual ~SpectralBaseAlgorithm() {};
+
+ protected: // Meant to be used in the subclasses
+
+ using SpectralCoefficients = amrex::FabArray< amrex::BaseFab <amrex::Real> >;
+
+ // Constructor
+ SpectralBaseAlgorithm(const SpectralKSpace& spectral_kspace,
+ const amrex::DistributionMapping& dm,
+ const int norder_x, const int norder_y,
+ const int norder_z, const bool nodal)
+ // Compute and assign the modified k vectors
+ : modified_kx_vec(spectral_kspace.getModifiedKComponent(dm,0,norder_x,nodal)),
+#if (AMREX_SPACEDIM==3)
+ modified_ky_vec(spectral_kspace.getModifiedKComponent(dm,1,norder_y,nodal)),
+ modified_kz_vec(spectral_kspace.getModifiedKComponent(dm,2,norder_z,nodal))
+#else
+ modified_kz_vec(spectral_kspace.getModifiedKComponent(dm,1,norder_z,nodal))
+#endif
+ {};
+
+ // Modified finite-order vectors
+ KVectorComponent modified_kx_vec, modified_kz_vec;
+#if (AMREX_SPACEDIM==3)
+ KVectorComponent modified_ky_vec;
+#endif
+};
+
+#endif // WARPX_SPECTRAL_BASE_ALGORITHM_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
index c62513de6..7954414b8 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
@@ -9,8 +9,9 @@
using SpectralField = amrex::FabArray< amrex::BaseFab <Complex> >;
/* Index for the fields that will be stored in spectral space */
-struct SpectralFieldIndex{
- enum { Ex=0, Ey, Ez, Bx, By, Bz, Jx, Jy, Jz, rho_old, rho_new };
+struct SpectralFieldIndex {
+ enum { Ex=0, Ey, Ez, Bx, By, Bz, Jx, Jy, Jz, rho_old, rho_new, n_fields };
+ // n_fields is automatically the total number of fields
};
/* \brief Class that stores the fields in spectral space, and performs the
@@ -24,7 +25,7 @@ class SpectralFieldData
// (plans are only initialized for the boxes that are owned by
// the local MPI rank)
#ifdef AMREX_USE_GPU
- // Add cuFFT-specific code
+ using FFTplans = amrex::LayoutData<cufftHandle>;
#else
using FFTplans = amrex::LayoutData<fftw_plan>;
#endif
@@ -37,15 +38,17 @@ class SpectralFieldData
SpectralFieldData& operator=(SpectralFieldData&& field_data) = default;
~SpectralFieldData();
void ForwardTransform( const amrex::MultiFab& mf,
- const int field_index, const int i_comp );
+ const int field_index, const int i_comp);
void BackwardTransform( amrex::MultiFab& mf,
- const int field_index, const int i_comp );
+ const int field_index, const int i_comp);
private:
- SpectralField Ex, Ey, Ez, Bx, By, Bz, Jx, Jy, Jz, rho_old, rho_new;
+ // `fields` stores fields in spectral space, as multicomponent FabArray
+ SpectralField fields;
// tmpRealField and tmpSpectralField store fields
// right before/after the Fourier transform
- SpectralField tmpRealField, tmpSpectralField;
+ SpectralField tmpSpectralField; // contains Complexs
+ amrex::MultiFab tmpRealField; // contains Reals
FFTplans forward_plan, backward_plan;
// Correcting "shift" factors when performing FFT from/to
// a cell-centered grid in real space, instead of a nodal grid
@@ -54,7 +57,6 @@ class SpectralFieldData
#if (AMREX_SPACEDIM==3)
SpectralShiftFactor yshift_FFTfromCell, yshift_FFTtoCell;
#endif
- SpectralField& getSpectralField( const int field_index );
};
#endif // WARPX_SPECTRAL_FIELD_DATA_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
index 291fe945e..a2b695568 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
@@ -10,21 +10,13 @@ SpectralFieldData::SpectralFieldData( const BoxArray& realspace_ba,
const BoxArray& spectralspace_ba = k_space.spectralspace_ba;
// Allocate the arrays that contain the fields in spectral space
- Ex = SpectralField(spectralspace_ba, dm, 1, 0);
- Ey = SpectralField(spectralspace_ba, dm, 1, 0);
- Ez = SpectralField(spectralspace_ba, dm, 1, 0);
- Bx = SpectralField(spectralspace_ba, dm, 1, 0);
- By = SpectralField(spectralspace_ba, dm, 1, 0);
- Bz = SpectralField(spectralspace_ba, dm, 1, 0);
- Jx = SpectralField(spectralspace_ba, dm, 1, 0);
- Jy = SpectralField(spectralspace_ba, dm, 1, 0);
- Jz = SpectralField(spectralspace_ba, dm, 1, 0);
- rho_old = SpectralField(spectralspace_ba, dm, 1, 0);
- rho_new = SpectralField(spectralspace_ba, dm, 1, 0);
+ // (one component per field)
+ fields = SpectralField(spectralspace_ba, dm,
+ SpectralFieldIndex::n_fields, 0);
// Allocate temporary arrays - in real space and spectral space
// These arrays will store the data just before/after the FFT
- tmpRealField = SpectralField(realspace_ba, dm, 1, 0);
+ tmpRealField = MultiFab(realspace_ba, dm, 1, 0);
tmpSpectralField = SpectralField(spectralspace_ba, dm, 1, 0);
// By default, we assume the FFT is done from/to a nodal grid in real space
@@ -56,31 +48,65 @@ SpectralFieldData::SpectralFieldData( const BoxArray& realspace_ba,
// Loop over boxes and allocate the corresponding plan
// for each box owned by the local MPI proc
for ( MFIter mfi(spectralspace_ba, dm); mfi.isValid(); ++mfi ){
- Box bx = spectralspace_ba[mfi];
+ // Note: the size of the real-space box and spectral-space box
+ // differ when using real-to-complex FFT. When initializing
+ // the FFT plan, the valid dimensions are those of the real-space box.
+ IntVect fft_size = realspace_ba[mfi].length();
#ifdef AMREX_USE_GPU
- // Add cuFFT-specific code
+ // Create cuFFT plans
+ // Creating 3D plan for real to complex -- double precision
+ // Assuming CUDA is used for programming GPU
+ // Note that D2Z is inherently forward plan
+ // and Z2D is inherently backward plan
+ cufftResult result;
+#if (AMREX_SPACEDIM == 3)
+ result = cufftPlan3d( &forward_plan[mfi], fft_size[2],
+ fft_size[1],fft_size[0], CUFFT_D2Z);
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " cufftplan3d forward failed! \n";
+ }
+
+ result = cufftPlan3d( &backward_plan[mfi], fft_size[2],
+ fft_size[1], fft_size[0], CUFFT_Z2D);
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " cufftplan3d backward failed! \n";
+ }
+#else
+ result = cufftPlan2d( &forward_plan[mfi], fft_size[1],
+ fft_size[0], CUFFT_D2Z );
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " cufftplan2d forward failed! \n";
+ }
+
+ result = cufftPlan2d( &backward_plan[mfi], fft_size[1],
+ fft_size[0], CUFFT_Z2D );
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " cufftplan2d backward failed! \n";
+ }
+#endif
+
#else
// Create FFTW plans
forward_plan[mfi] =
// Swap dimensions: AMReX FAB are Fortran-order but FFTW is C-order
#if (AMREX_SPACEDIM == 3)
- fftw_plan_dft_3d( bx.length(2), bx.length(1), bx.length(0),
+ fftw_plan_dft_r2c_3d( fft_size[2], fft_size[1], fft_size[0],
#else
- fftw_plan_dft_2d( bx.length(1), bx.length(0),
+ fftw_plan_dft_r2c_2d( fft_size[1], fft_size[0],
#endif
- reinterpret_cast<fftw_complex*>( tmpRealField[mfi].dataPtr() ),
+ tmpRealField[mfi].dataPtr(),
reinterpret_cast<fftw_complex*>( tmpSpectralField[mfi].dataPtr() ),
- FFTW_FORWARD, FFTW_ESTIMATE );
+ FFTW_ESTIMATE );
backward_plan[mfi] =
// Swap dimensions: AMReX FAB are Fortran-order but FFTW is C-order
#if (AMREX_SPACEDIM == 3)
- fftw_plan_dft_3d( bx.length(2), bx.length(1), bx.length(0),
+ fftw_plan_dft_c2r_3d( fft_size[2], fft_size[1], fft_size[0],
#else
- fftw_plan_dft_2d( bx.length(1), bx.length(0),
+ fftw_plan_dft_c2r_2d( fft_size[1], fft_size[0],
#endif
reinterpret_cast<fftw_complex*>( tmpSpectralField[mfi].dataPtr() ),
- reinterpret_cast<fftw_complex*>( tmpRealField[mfi].dataPtr() ),
- FFTW_BACKWARD, FFTW_ESTIMATE );
+ tmpRealField[mfi].dataPtr(),
+ FFTW_ESTIMATE );
#endif
}
}
@@ -91,7 +117,9 @@ SpectralFieldData::~SpectralFieldData()
if (tmpRealField.size() > 0){
for ( MFIter mfi(tmpRealField); mfi.isValid(); ++mfi ){
#ifdef AMREX_USE_GPU
- // Add cuFFT-specific code
+ // Destroy cuFFT plans
+ cufftDestroy( forward_plan[mfi] );
+ cufftDestroy( backward_plan[mfi] );
#else
// Destroy FFTW plans
fftw_destroy_plan( forward_plan[mfi] );
@@ -131,28 +159,38 @@ SpectralFieldData::ForwardTransform( const MultiFab& mf,
realspace_bx.enclosedCells(); // Discard last point in nodal direction
AMREX_ALWAYS_ASSERT( realspace_bx == tmpRealField[mfi].box() );
Array4<const Real> mf_arr = mf[mfi].array();
- Array4<Complex> tmp_arr = tmpRealField[mfi].array();
+ Array4<Real> tmp_arr = tmpRealField[mfi].array();
ParallelFor( realspace_bx,
[=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
- tmp_arr(i,j,k) = mf_arr(i,j,k,i_comp);
+ tmp_arr(i,j,k) = mf_arr(i,j,k,i_comp);
});
}
// Perform Fourier transform from `tmpRealField` to `tmpSpectralField`
#ifdef AMREX_USE_GPU
- // Add cuFFT-specific code ; make sure that this is done on the same
- // GPU stream as the above copy
+ // Perform Fast Fourier Transform on GPU using cuFFT
+ // make sure that this is done on the same
+ // GPU stream as the above copy
+ cufftResult result;
+ cudaStream_t stream = amrex::Gpu::Device::cudaStream();
+ cufftSetStream ( forward_plan[mfi], stream);
+ result = cufftExecD2Z( forward_plan[mfi],
+ tmpRealField[mfi].dataPtr(),
+ reinterpret_cast<cuDoubleComplex*>(
+ tmpSpectralField[mfi].dataPtr()) );
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " forward transform using cufftExecD2Z failed ! \n";
+ }
#else
fftw_execute( forward_plan[mfi] );
#endif
// Copy the spectral-space field `tmpSpectralField` to the appropriate
- // field (specified by the input argument field_index )
+ // index of the FabArray `fields` (specified by `field_index`)
// and apply correcting shift factor if the real space data comes
// from a cell-centered grid in real space instead of a nodal grid.
{
- SpectralField& field = getSpectralField( field_index );
- Array4<Complex> field_arr = field[mfi].array();
+ Array4<Complex> fields_arr = SpectralFieldData::fields[mfi].array();
Array4<const Complex> tmp_arr = tmpSpectralField[mfi].array();
const Complex* xshift_arr = xshift_FFTfromCell[mfi].dataPtr();
#if (AMREX_SPACEDIM == 3)
@@ -161,6 +199,7 @@ SpectralFieldData::ForwardTransform( const MultiFab& mf,
const Complex* zshift_arr = zshift_FFTfromCell[mfi].dataPtr();
// Loop over indices within one box
const Box spectralspace_bx = tmpSpectralField[mfi].box();
+
ParallelFor( spectralspace_bx,
[=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
Complex spectral_field_value = tmp_arr(i,j,k);
@@ -168,10 +207,12 @@ SpectralFieldData::ForwardTransform( const MultiFab& mf,
if (is_nodal_x==false) spectral_field_value *= xshift_arr[i];
#if (AMREX_SPACEDIM == 3)
if (is_nodal_y==false) spectral_field_value *= yshift_arr[j];
-#endif
if (is_nodal_z==false) spectral_field_value *= zshift_arr[k];
- // Copy field into temporary array
- field_arr(i,j,k) = spectral_field_value;
+#elif (AMREX_SPACEDIM == 2)
+ if (is_nodal_z==false) spectral_field_value *= zshift_arr[j];
+#endif
+ // Copy field into the right index
+ fields_arr(i,j,k,field_index) = spectral_field_value;
});
}
}
@@ -182,7 +223,8 @@ SpectralFieldData::ForwardTransform( const MultiFab& mf,
* real space, and store it in the component `i_comp` of `mf` */
void
SpectralFieldData::BackwardTransform( MultiFab& mf,
- const int field_index, const int i_comp )
+ const int field_index,
+ const int i_comp )
{
// Check field index type, in order to apply proper shift in spectral space
const bool is_nodal_x = mf.is_nodal(0);
@@ -200,10 +242,8 @@ SpectralFieldData::BackwardTransform( MultiFab& mf,
// field (specified by the input argument field_index)
// and apply correcting shift factor if the field is to be transformed
// to a cell-centered grid in real space instead of a nodal grid.
- // Normalize (divide by 1/N) since the FFT+IFFT results in a factor N
{
- SpectralField& field = getSpectralField( field_index );
- Array4<const Complex> field_arr = field[mfi].array();
+ Array4<const Complex> field_arr = SpectralFieldData::fields[mfi].array();
Array4<Complex> tmp_arr = tmpSpectralField[mfi].array();
const Complex* xshift_arr = xshift_FFTtoCell[mfi].dataPtr();
#if (AMREX_SPACEDIM == 3)
@@ -212,60 +252,57 @@ SpectralFieldData::BackwardTransform( MultiFab& mf,
const Complex* zshift_arr = zshift_FFTtoCell[mfi].dataPtr();
// Loop over indices within one box
const Box spectralspace_bx = tmpSpectralField[mfi].box();
- // For normalization: divide by the number of points in the box
- const Real inv_N = 1./spectralspace_bx.numPts();
+
ParallelFor( spectralspace_bx,
[=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
- Complex spectral_field_value = field_arr(i,j,k);
+ Complex spectral_field_value = field_arr(i,j,k,field_index);
// Apply proper shift in each dimension
if (is_nodal_x==false) spectral_field_value *= xshift_arr[i];
#if (AMREX_SPACEDIM == 3)
if (is_nodal_y==false) spectral_field_value *= yshift_arr[j];
-#endif
if (is_nodal_z==false) spectral_field_value *= zshift_arr[k];
- // Copy field into temporary array (after normalization)
- tmp_arr(i,j,k) = inv_N*spectral_field_value;
+#elif (AMREX_SPACEDIM == 2)
+ if (is_nodal_z==false) spectral_field_value *= zshift_arr[j];
+#endif
+ // Copy field into temporary array
+ tmp_arr(i,j,k) = spectral_field_value;
});
}
// Perform Fourier transform from `tmpSpectralField` to `tmpRealField`
#ifdef AMREX_USE_GPU
- // Add cuFFT-specific code ; make sure that this is done on the same
+ // Perform Fast Fourier Transform on GPU using cuFFT.
+ // make sure that this is done on the same
// GPU stream as the above copy
+ cufftResult result;
+ cudaStream_t stream = amrex::Gpu::Device::cudaStream();
+ cufftSetStream ( backward_plan[mfi], stream);
+ result = cufftExecZ2D( backward_plan[mfi],
+ reinterpret_cast<cuDoubleComplex*>(
+ tmpSpectralField[mfi].dataPtr()),
+ tmpRealField[mfi].dataPtr() );
+ if ( result != CUFFT_SUCCESS ) {
+ amrex::Print() << " Backward transform using cufftexecZ2D failed! \n";
+ }
#else
fftw_execute( backward_plan[mfi] );
#endif
// Copy the temporary field `tmpRealField` to the real-space field `mf`
+
+ // Normalize (divide by 1/N) since the FFT+IFFT results in a factor N
{
const Box realspace_bx = tmpRealField[mfi].box();
Array4<Real> mf_arr = mf[mfi].array();
- Array4<const Complex> tmp_arr = tmpRealField[mfi].array();
+ Array4<const Real> tmp_arr = tmpRealField[mfi].array();
+ // Normalization: divide by the number of points in realspace
+ const Real inv_N = 1./realspace_bx.numPts();
+
ParallelFor( realspace_bx,
[=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
- mf_arr(i,j,k,i_comp) = tmp_arr(i,j,k).real();
+ // Copy and normalize field
+ mf_arr(i,j,k,i_comp) = inv_N*tmp_arr(i,j,k);
});
}
}
}
-
-
-SpectralField&
-SpectralFieldData::getSpectralField( const int field_index )
-{
- switch(field_index)
- {
- case SpectralFieldIndex::Ex : return Ex; break;
- case SpectralFieldIndex::Ey : return Ey; break;
- case SpectralFieldIndex::Ez : return Ez; break;
- case SpectralFieldIndex::Bx : return Bx; break;
- case SpectralFieldIndex::By : return By; break;
- case SpectralFieldIndex::Bz : return Bz; break;
- case SpectralFieldIndex::Jx : return Jx; break;
- case SpectralFieldIndex::Jy : return Jy; break;
- case SpectralFieldIndex::Jz : return Jz; break;
- case SpectralFieldIndex::rho_old : return rho_old; break;
- case SpectralFieldIndex::rho_new : return rho_new; break;
- default : return tmpSpectralField; // For synthax; should not occur in practice
- }
-}
diff --git a/Source/FieldSolver/SpectralSolver/SpectralKSpace.H b/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
index ad17e6423..ae7124b2e 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
@@ -33,7 +33,9 @@ class SpectralKSpace
const amrex::DistributionMapping& dm,
const amrex::RealVect realspace_dx );
KVectorComponent getKComponent(
- const amrex::DistributionMapping& dm, const int i_dim ) const;
+ const amrex::DistributionMapping& dm,
+ const amrex::BoxArray& realspace_ba,
+ const int i_dim, const bool only_positive_k ) const;
KVectorComponent getModifiedKComponent(
const amrex::DistributionMapping& dm, const int i_dim,
const int n_order, const bool nodal ) const;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp b/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
index d91891a30..6fe5e3939 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
@@ -28,19 +28,33 @@ SpectralKSpace::SpectralKSpace( const BoxArray& realspace_ba,
// For local FFTs, boxes in spectral space start at 0 in
// each direction and have the same number of points as the
// (cell-centered) real space box
- // TODO: this will be different for the real-to-complex FFT
// TODO: this will be different for the hybrid FFT scheme
Box realspace_bx = realspace_ba[i];
- Print() << realspace_bx.smallEnd() << " " << realspace_bx.bigEnd() << std::endl;
- Box bx = Box( IntVect::TheZeroVector(),
- realspace_bx.bigEnd() - realspace_bx.smallEnd() );
- spectral_bl.push_back( bx );
+ IntVect fft_size = realspace_bx.length();
+ // Because the spectral solver uses real-to-complex FFTs, we only
+ // need the positive k values along the fastest axis
+ // (first axis for AMReX Fortran-order arrays) in spectral space.
+ // This effectively reduces the size of the spectral space by half
+ // see e.g. the FFTW documentation for real-to-complex FFTs
+ IntVect spectral_bx_size = fft_size;
+ spectral_bx_size[0] = fft_size[0]/2 + 1;
+ // Define the corresponding box
+ Box spectral_bx = Box( IntVect::TheZeroVector(),
+ spectral_bx_size - IntVect::TheUnitVector() );
+ spectral_bl.push_back( spectral_bx );
}
spectralspace_ba.define( spectral_bl );
// Allocate the components of the k vector: kx, ky (only in 3D), kz
+ bool only_positive_k;
for (int i_dim=0; i_dim<AMREX_SPACEDIM; i_dim++) {
- k_vec[i_dim] = getKComponent( dm, i_dim );
+ if (i_dim==0) {
+ // Real-to-complex FFTs: first axis contains only the positive k
+ only_positive_k = true;
+ } else {
+ only_positive_k = false;
+ }
+ k_vec[i_dim] = getKComponent(dm, realspace_ba, i_dim, only_positive_k);
}
}
@@ -50,7 +64,9 @@ SpectralKSpace::SpectralKSpace( const BoxArray& realspace_ba,
*/
KVectorComponent
SpectralKSpace::getKComponent( const DistributionMapping& dm,
- const int i_dim ) const
+ const BoxArray& realspace_ba,
+ const int i_dim,
+ const bool only_positive_k ) const
{
// Initialize an empty ManagedVector in each box
KVectorComponent k_comp(spectralspace_ba, dm);
@@ -65,21 +81,31 @@ SpectralKSpace::getKComponent( const DistributionMapping& dm,
k.resize( N );
// Fill the k vector
- const Real dk = 2*MathConst::pi/(N*dx[i_dim]);
+ IntVect fft_size = realspace_ba[mfi].length();
+ const Real dk = 2*MathConst::pi/(fft_size[i_dim]*dx[i_dim]);
AMREX_ALWAYS_ASSERT_WITH_MESSAGE( bx.smallEnd(i_dim) == 0,
"Expected box to start at 0, in spectral space.");
AMREX_ALWAYS_ASSERT_WITH_MESSAGE( bx.bigEnd(i_dim) == N-1,
"Expected different box end index in spectral space.");
- const int mid_point = (N+1)/2;
- // Fill positive values of k (FFT conventions: first half is positive)
- for (int i=0; i<mid_point; i++ ){
- k[i] = i*dk;
- }
- // Fill negative values of k (FFT conventions: second half is negative)
- for (int i=mid_point; i<N; i++){
- k[i] = (i-N)*dk;
+ if (only_positive_k){
+ // Fill the full axis with positive k values
+ // (typically: first axis, in a real-to-complex FFT)
+ for (int i=0; i<N; i++ ){
+ k[i] = i*dk;
+ }
+ } else {
+ const int mid_point = (N+1)/2;
+ // Fill positive values of k
+ // (FFT conventions: first half is positive)
+ for (int i=0; i<mid_point; i++ ){
+ k[i] = i*dk;
+ }
+ // Fill negative values of k
+ // (FFT conventions: second half is negative)
+ for (int i=mid_point; i<N; i++){
+ k[i] = (i-N)*dk;
+ }
}
- // TODO: this will be different for the real-to-complex transform
// TODO: this will be different for the hybrid FFT scheme
}
return k_comp;
@@ -116,9 +142,14 @@ SpectralKSpace::getSpectralShiftFactor( const DistributionMapping& dm,
case ShiftType::TransformFromCellCentered: sign = -1.; break;
case ShiftType::TransformToCellCentered: sign = 1.;
}
- constexpr Complex I{0,1};
+ const Complex I{0,1};
for (int i=0; i<k.size(); i++ ){
+#ifdef AMREX_USE_GPU
+ shift[i] = thrust::exp( I*sign*k[i]*0.5*dx[i_dim] );
+#else
shift[i] = std::exp( I*sign*k[i]*0.5*dx[i_dim] );
+#endif
+
}
}
return shift_factor;
@@ -161,12 +192,13 @@ SpectralKSpace::getModifiedKComponent( const DistributionMapping& dm,
// Fill the modified k vector
for (int i=0; i<k.size(); i++ ){
+ modified_k[i] = 0;
for (int n=1; n<stencil_coef.size(); n++){
if (nodal){
- modified_k[i] = stencil_coef[n]* \
+ modified_k[i] += stencil_coef[n]* \
std::sin( k[i]*n*delta_x )/( n*delta_x );
} else {
- modified_k[i] = stencil_coef[n]* \
+ modified_k[i] += stencil_coef[n]* \
std::sin( k[i]*(n-0.5)*delta_x )/( (n-0.5)*delta_x );
}
}
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.H b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
index 7444452af..d4019a9a3 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralSolver.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
@@ -1,8 +1,7 @@
#ifndef WARPX_SPECTRAL_SOLVER_H_
#define WARPX_SPECTRAL_SOLVER_H_
-#include <SpectralKSpace.H>
-#include <PsatdAlgorithm.H>
+#include <SpectralBaseAlgorithm.H>
#include <SpectralFieldData.H>
/* \brief Top-level class for the electromagnetic spectral solver
@@ -14,28 +13,17 @@
class SpectralSolver
{
public:
- // Inline definition of the member functions of `SpectralSolver`
+ // Inline definition of the member functions of `SpectralSolver`,
+ // except the constructor (see `SpectralSolver.cpp`)
// The body of these functions is short, since the work is done in the
// underlying classes `SpectralFieldData` and `PsatdAlgorithm`
- /* \brief Initialize the spectral solver */
+ // Constructor
SpectralSolver( const amrex::BoxArray& realspace_ba,
const amrex::DistributionMapping& dm,
const int norder_x, const int norder_y,
const int norder_z, const bool nodal,
- const amrex::RealVect dx, const amrex::Real dt ) {
- // Initialize all structures using the same distribution mapping dm
-
- // - Initialize k space object (Contains info about the size of
- // the spectral space corresponding to each box in `realspace_ba`,
- // as well as the value of the corresponding k coordinates)
- const SpectralKSpace k_space= SpectralKSpace(realspace_ba, dm, dx);
- // - Initialize the algorithm (coefficients) over this space
- algorithm = PsatdAlgorithm( k_space, dm, norder_x, norder_y,
- norder_z, nodal, dt );
- // - Initialize arrays for fields in Fourier space + FFT plans
- field_data = SpectralFieldData( realspace_ba, k_space, dm );
- };
+ const amrex::RealVect dx, const amrex::Real dt );
/* \brief Transform the component `i_comp` of MultiFab `mf`
* to spectral space, and store the corresponding result internally
@@ -59,14 +47,20 @@ class SpectralSolver
/* \brief Update the fields in spectral space, over one timestep */
void pushSpectralFields(){
BL_PROFILE("SpectralSolver::pushSpectralFields");
- algorithm.pushSpectralFields( field_data );
+ // Virtual function: the actual function used here depends
+ // on the sub-class of `SpectralBaseAlgorithm` that was
+ // initialized in the constructor of `SpectralSolver`
+ algorithm->pushSpectralFields( field_data );
};
private:
SpectralFieldData field_data; // Store field in spectral space
// and perform the Fourier transforms
- PsatdAlgorithm algorithm; // Contains Psatd coefficients
- // and field update equation
+ std::unique_ptr<SpectralBaseAlgorithm> algorithm;
+ // Defines field update equation in spectral space,
+ // and the associated coefficients.
+ // SpectralBaseAlgorithm is a base class ; this pointer is meant
+ // to point an instance of a *sub-class* defining a specific algorithm
};
#endif // WARPX_SPECTRAL_SOLVER_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
new file mode 100644
index 000000000..c21c3cfb1
--- /dev/null
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
@@ -0,0 +1,35 @@
+#include <SpectralKSpace.H>
+#include <SpectralSolver.H>
+#include <PsatdAlgorithm.H>
+
+/* \brief Initialize the spectral Maxwell solver
+ *
+ * This function selects the spectral algorithm to be used, allocates the
+ * corresponding coefficients for the discretized field update equation,
+ * and prepares the structures that store the fields in spectral space.
+ */
+SpectralSolver::SpectralSolver(
+ const amrex::BoxArray& realspace_ba,
+ const amrex::DistributionMapping& dm,
+ const int norder_x, const int norder_y,
+ const int norder_z, const bool nodal,
+ const amrex::RealVect dx, const amrex::Real dt ) {
+
+ // Initialize all structures using the same distribution mapping dm
+
+ // - Initialize k space object (Contains info about the size of
+ // the spectral space corresponding to each box in `realspace_ba`,
+ // as well as the value of the corresponding k coordinates)
+ const SpectralKSpace k_space= SpectralKSpace(realspace_ba, dm, dx);
+
+ // - Select the algorithm depending on the input parameters
+ // Initialize the corresponding coefficients over k space
+ // TODO: Add more algorithms + selection depending on input parameters
+ // For the moment, this only uses the standard PsatdAlgorithm
+ algorithm = std::unique_ptr<PsatdAlgorithm>( new PsatdAlgorithm(
+ k_space, dm, norder_x, norder_y, norder_z, nodal, dt ) );
+
+ // - Initialize arrays for fields in spectral space + FFT plans
+ field_data = SpectralFieldData( realspace_ba, k_space, dm );
+
+};
diff --git a/Source/FieldSolver/WarpXFFT.cpp b/Source/FieldSolver/WarpXFFT.cpp
index 4bccc956b..13d92f6f3 100644
--- a/Source/FieldSolver/WarpXFFT.cpp
+++ b/Source/FieldSolver/WarpXFFT.cpp
@@ -56,6 +56,7 @@ BuildFFTOwnerMask (const MultiFab& mf, const Geometry& geom)
for (const auto& b : bl) {
fab.setVal(nonowner, b, 0, 1);
}
+
}
return mask;
@@ -89,7 +90,7 @@ CopyDataFromFFTToValid (MultiFab& mf, const MultiFab& mf_fft, const BoxArray& ba
const FArrayBox& srcfab = mf_fft[mfi];
const Box& srcbox = srcfab.box();
-
+
if (srcbox.contains(bx))
{
// Copy the interior region (without guard cells)
@@ -107,6 +108,8 @@ CopyDataFromFFTToValid (MultiFab& mf, const MultiFab& mf_fft, const BoxArray& ba
// the cell that has non-zero mask is the one which is retained.
mf.setVal(0.0, 0);
mf.ParallelAdd(mftmp);
+
+
}
}
@@ -130,7 +133,11 @@ WarpX::AllocLevelDataFFT (int lev)
// Allocate and initialize objects for the spectral solver
// (all use the same distribution mapping)
std::array<Real,3> dx = CellSize(lev);
- RealVect dx_vect = RealVect( AMREX_D_DECL(dx[0], dx[1], dx[2]) );
+#if (AMREX_SPACEDIM == 3)
+ RealVect dx_vect(dx[0], dx[1], dx[2]);
+#elif (AMREX_SPACEDIM == 2)
+ RealVect dx_vect(dx[0], dx[2]);
+#endif
spectral_solver_fp[lev].reset( new SpectralSolver( ba_fp_fft, dm_fp_fft,
nox_fft, noy_fft, noz_fft, do_nodal, dx_vect, dt[lev] ) );
}
@@ -403,6 +410,7 @@ WarpX::PushPSATD (int lev, amrex::Real /* dt */)
BL_PROFILE_VAR_START(blp_push_eb);
if (fft_hybrid_mpi_decomposition){
+#ifndef AMREX_USE_CUDA // When running on CPU: use PICSAR code
if (Efield_fp_fft[lev][0]->local_size() == 1)
//Only one FFT patch on this MPI
{
@@ -443,6 +451,9 @@ WarpX::PushPSATD (int lev, amrex::Real /* dt */)
{
amrex::Abort("WarpX::PushPSATD: TODO");
}
+#else // AMREX_USE_CUDA is defined ; running on GPU
+ amrex::Abort("The option `psatd.fft_hybrid_mpi_decomposition` does not work on GPU.");
+#endif
} else {
// Not using the hybrid decomposition
auto& solver = *spectral_solver_fp[lev];
@@ -470,6 +481,7 @@ WarpX::PushPSATD (int lev, amrex::Real /* dt */)
solver.BackwardTransform(*Bfield_fp_fft[lev][0], SpectralFieldIndex::Bx);
solver.BackwardTransform(*Bfield_fp_fft[lev][1], SpectralFieldIndex::By);
solver.BackwardTransform(*Bfield_fp_fft[lev][2], SpectralFieldIndex::Bz);
+
}
BL_PROFILE_VAR_STOP(blp_push_eb);
@@ -486,4 +498,7 @@ WarpX::PushPSATD (int lev, amrex::Real /* dt */)
{
amrex::Abort("WarpX::PushPSATD: TODO");
}
+
}
+
+
diff --git a/Source/FieldSolver/WarpXPushFieldsEM.cpp b/Source/FieldSolver/WarpXPushFieldsEM.cpp
index 6a9ceae5a..c53e13f8f 100644
--- a/Source/FieldSolver/WarpXPushFieldsEM.cpp
+++ b/Source/FieldSolver/WarpXPushFieldsEM.cpp
@@ -17,30 +17,30 @@
using namespace amrex;
void
-WarpX::EvolveB (Real dt)
+WarpX::EvolveB (Real a_dt)
{
for (int lev = 0; lev <= finest_level; ++lev) {
- EvolveB(lev, dt);
+ EvolveB(lev, a_dt);
}
}
void
-WarpX::EvolveB (int lev, Real dt)
+WarpX::EvolveB (int lev, Real a_dt)
{
BL_PROFILE("WarpX::EvolveB()");
- EvolveB(lev, PatchType::fine, dt);
+ EvolveB(lev, PatchType::fine, a_dt);
if (lev > 0)
{
- EvolveB(lev, PatchType::coarse, dt);
+ EvolveB(lev, PatchType::coarse, a_dt);
}
}
void
-WarpX::EvolveB (int lev, PatchType patch_type, amrex::Real dt)
+WarpX::EvolveB (int lev, PatchType patch_type, amrex::Real a_dt)
{
const int patch_level = (patch_type == PatchType::fine) ? lev : lev-1;
const std::array<Real,3>& dx = WarpX::CellSize(patch_level);
- Real dtsdx = dt/dx[0], dtsdy = dt/dx[1], dtsdz = dt/dx[2];
+ Real dtsdx = a_dt/dx[0], dtsdy = a_dt/dx[1], dtsdz = a_dt/dx[2];
MultiFab *Ex, *Ey, *Ez, *Bx, *By, *Bz;
if (patch_type == PatchType::fine)
@@ -65,6 +65,10 @@ WarpX::EvolveB (int lev, PatchType patch_type, amrex::Real dt)
MultiFab* cost = costs[lev].get();
const IntVect& rr = (lev > 0) ? refRatio(lev-1) : IntVect::TheUnitVector();
+ // xmin is only used by the picsar kernel with cylindrical geometry,
+ // in which case it is actually rmin.
+ const Real xmin = Geom(0).ProbLo(0);
+
// Loop through the grids, and over the tiles within each grid
#ifdef _OPENMP
#pragma omp parallel if (Gpu::notInLaunchRegion())
@@ -77,10 +81,6 @@ WarpX::EvolveB (int lev, PatchType patch_type, amrex::Real dt)
const Box& tby = mfi.tilebox(By_nodal_flag);
const Box& tbz = mfi.tilebox(Bz_nodal_flag);
- // xmin is only used by the picsar kernel with cylindrical geometry,
- // in which case it is actually rmin.
- const Real xmin = mfi.tilebox().smallEnd(0)*dx[0];
-
if (do_nodal) {
auto const& Bxfab = Bx->array(mfi);
auto const& Byfab = By->array(mfi);
@@ -164,30 +164,30 @@ WarpX::EvolveB (int lev, PatchType patch_type, amrex::Real dt)
}
void
-WarpX::EvolveE (Real dt)
+WarpX::EvolveE (Real a_dt)
{
for (int lev = 0; lev <= finest_level; ++lev)
{
- EvolveE(lev, dt);
+ EvolveE(lev, a_dt);
}
}
void
-WarpX::EvolveE (int lev, Real dt)
+WarpX::EvolveE (int lev, Real a_dt)
{
BL_PROFILE("WarpX::EvolveE()");
- EvolveE(lev, PatchType::fine, dt);
+ EvolveE(lev, PatchType::fine, a_dt);
if (lev > 0)
{
- EvolveE(lev, PatchType::coarse, dt);
+ EvolveE(lev, PatchType::coarse, a_dt);
}
}
void
-WarpX::EvolveE (int lev, PatchType patch_type, amrex::Real dt)
+WarpX::EvolveE (int lev, PatchType patch_type, amrex::Real a_dt)
{
- const Real mu_c2_dt = (PhysConst::mu0*PhysConst::c*PhysConst::c) * dt;
- const Real c2dt = (PhysConst::c*PhysConst::c) * dt;
+ const Real mu_c2_dt = (PhysConst::mu0*PhysConst::c*PhysConst::c) * a_dt;
+ const Real c2dt = (PhysConst::c*PhysConst::c) * a_dt;
int patch_level = (patch_type == PatchType::fine) ? lev : lev-1;
const std::array<Real,3>& dx = WarpX::CellSize(patch_level);
@@ -224,6 +224,10 @@ WarpX::EvolveE (int lev, PatchType patch_type, amrex::Real dt)
MultiFab* cost = costs[lev].get();
const IntVect& rr = (lev > 0) ? refRatio(lev-1) : IntVect::TheUnitVector();
+ // xmin is only used by the picsar kernel with cylindrical geometry,
+ // in which case it is actually rmin.
+ const Real xmin = Geom(0).ProbLo(0);
+
// Loop through the grids, and over the tiles within each grid
#ifdef _OPENMP
#pragma omp parallel if (Gpu::notInLaunchRegion())
@@ -236,10 +240,6 @@ WarpX::EvolveE (int lev, PatchType patch_type, amrex::Real dt)
const Box& tey = mfi.tilebox(Ey_nodal_flag);
const Box& tez = mfi.tilebox(Ez_nodal_flag);
- // xmin is only used by the picsar kernel with cylindrical geometry,
- // in which case it is actually rmin.
- const Real xmin = mfi.tilebox().smallEnd(0)*dx[0];
-
if (do_nodal) {
auto const& Exfab = Ex->array(mfi);
auto const& Eyfab = Ey->array(mfi);
@@ -358,27 +358,27 @@ WarpX::EvolveE (int lev, PatchType patch_type, amrex::Real dt)
}
void
-WarpX::EvolveF (Real dt, DtType dt_type)
+WarpX::EvolveF (Real a_dt, DtType a_dt_type)
{
if (!do_dive_cleaning) return;
for (int lev = 0; lev <= finest_level; ++lev)
{
- EvolveF(lev, dt, dt_type);
+ EvolveF(lev, a_dt, a_dt_type);
}
}
void
-WarpX::EvolveF (int lev, Real dt, DtType dt_type)
+WarpX::EvolveF (int lev, Real a_dt, DtType a_dt_type)
{
if (!do_dive_cleaning) return;
- EvolveF(lev, PatchType::fine, dt, dt_type);
- if (lev > 0) EvolveF(lev, PatchType::coarse, dt, dt_type);
+ EvolveF(lev, PatchType::fine, a_dt, a_dt_type);
+ if (lev > 0) EvolveF(lev, PatchType::coarse, a_dt, a_dt_type);
}
void
-WarpX::EvolveF (int lev, PatchType patch_type, Real dt, DtType dt_type)
+WarpX::EvolveF (int lev, PatchType patch_type, Real a_dt, DtType a_dt_type)
{
if (!do_dive_cleaning) return;
@@ -388,7 +388,7 @@ WarpX::EvolveF (int lev, PatchType patch_type, Real dt, DtType dt_type)
int patch_level = (patch_type == PatchType::fine) ? lev : lev-1;
const auto& dx = WarpX::CellSize(patch_level);
- const std::array<Real,3> dtsdx {dt/dx[0], dt/dx[1], dt/dx[2]};
+ const std::array<Real,3> dtsdx {a_dt/dx[0], a_dt/dx[1], a_dt/dx[2]};
MultiFab *Ex, *Ey, *Ez, *rho, *F;
if (patch_type == PatchType::fine)
@@ -408,12 +408,12 @@ WarpX::EvolveF (int lev, PatchType patch_type, Real dt, DtType dt_type)
F = F_cp[lev].get();
}
- const int rhocomp = (dt_type == DtType::FirstHalf) ? 0 : 1;
+ const int rhocomp = (a_dt_type == DtType::FirstHalf) ? 0 : 1;
MultiFab src(rho->boxArray(), rho->DistributionMap(), 1, 0);
ComputeDivE(src, 0, {Ex,Ey,Ez}, dx);
MultiFab::Saxpy(src, -mu_c2, *rho, rhocomp, 0, 1, 0);
- MultiFab::Saxpy(*F, dt, src, 0, 0, 1, 0);
+ MultiFab::Saxpy(*F, a_dt, src, 0, 0, 1, 0);
if (do_pml && pml[lev]->ok())
{
diff --git a/Source/Filter/BilinearFilter.H b/Source/Filter/BilinearFilter.H
index 9bade3c77..4fcfec14b 100644
--- a/Source/Filter/BilinearFilter.H
+++ b/Source/Filter/BilinearFilter.H
@@ -1,30 +1,17 @@
-#include <AMReX_MultiFab.H>
-#include <AMReX_CudaContainers.H>
+#include <Filter.H>
-#ifndef WARPX_FILTER_H_
-#define WARPX_FILTER_H_
+#ifndef WARPX_BILIN_FILTER_H_
+#define WARPX_BILIN_FILTER_H_
-class BilinearFilter
+class BilinearFilter : public Filter
{
public:
- BilinearFilter () = default;
+
+ 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;
-
- // public for cuda
- void Filter(const amrex::Box& tbx,
- amrex::Array4<amrex::Real const> const& tmp,
- amrex::Array4<amrex::Real > const& dst,
- int scomp, int dcomp, int ncomp);
-
-private:
-
- amrex::Gpu::ManagedVector<amrex::Real> stencil_x, stencil_y, stencil_z;
- amrex::Dim3 slen;
};
-#endif
+#endif // #ifndef WARPX_BILIN_FILTER_H_
diff --git a/Source/Filter/BilinearFilter.cpp b/Source/Filter/BilinearFilter.cpp
index f6acaa5df..68ebde687 100644
--- a/Source/Filter/BilinearFilter.cpp
+++ b/Source/Filter/BilinearFilter.cpp
@@ -68,173 +68,3 @@ void BilinearFilter::ComputeStencils(){
slen.z = 1;
#endif
}
-
-
-#ifdef AMREX_USE_CUDA
-
-void
-BilinearFilter::ApplyStencil (MultiFab& dstmf, const MultiFab& srcmf, int scomp, int dcomp, int ncomp)
-{
- BL_PROFILE("BilinearFilter::ApplyStencil()");
- ncomp = std::min(ncomp, srcmf.nComp());
-
- for (MFIter mfi(dstmf); mfi.isValid(); ++mfi)
- {
- const auto& src = srcmf.array(mfi);
- const auto& dst = dstmf.array(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
- FArrayBox tmp_fab(gbx,ncomp);
- Elixir tmp_eli = tmp_fab.elixir(); // Prevent the tmp data from being deleted too early
- auto const& tmp = tmp_fab.array();
-
- // Copy values in srcfab into tmpfab
- const Box& ibx = gbx & srcmf[mfi].box();
- AMREX_PARALLEL_FOR_4D ( gbx, ncomp, i, j, k, n,
- {
- if (ibx.contains(IntVect(AMREX_D_DECL(i,j,k)))) {
- tmp(i,j,k,n) = src(i,j,k,n+scomp);
- } else {
- tmp(i,j,k,n) = 0.0;
- }
- });
-
- // Apply filter
- Filter(tbx, tmp, dst, 0, dcomp, ncomp);
- }
-}
-
-void BilinearFilter::Filter (const Box& tbx,
- Array4<Real const> const& tmp,
- Array4<Real > const& dst,
- int scomp, int dcomp, int ncomp)
-{
- 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();
- Dim3 slen_local = slen;
- AMREX_PARALLEL_FOR_4D ( tbx, ncomp, i, j, k, n,
- {
- Real d = 0.0;
-
- for (int iz=0; iz < slen_local.z; ++iz){
- for (int iy=0; iy < slen_local.y; ++iy){
- for (int ix=0; ix < slen_local.x; ++ix){
-#if (AMREX_SPACEDIM == 3)
- Real sss = sx[ix]*sy[iy]*sz[iz];
-#else
- Real sss = sx[ix]*sz[iy];
-#endif
-#if (AMREX_SPACEDIM == 3)
- d += 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
- d += 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
- }
- }
- }
-
- dst(i,j,k,dcomp+n) = d;
- });
-}
-
-#else
-
-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.array(), dstfab.array(), 0, dcomp, ncomp);
- }
- }
-}
-
-void BilinearFilter::Filter (const Box& tbx,
- Array4<Real const> const& tmp,
- Array4<Real > const& dst,
- int scomp, int dcomp, int ncomp)
-{
- const auto lo = amrex::lbound(tbx);
- const auto hi = amrex::ubound(tbx);
- // 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
- }
- }
- }
- }
- }
- }
- }
-}
-
-#endif
diff --git a/Source/Filter/Filter.H b/Source/Filter/Filter.H
new file mode 100644
index 000000000..eaa0498c9
--- /dev/null
+++ b/Source/Filter/Filter.H
@@ -0,0 +1,43 @@
+#include <AMReX_MultiFab.H>
+#include <AMReX_CudaContainers.H>
+
+#ifndef WARPX_FILTER_H_
+#define WARPX_FILTER_H_
+
+class Filter
+{
+public:
+ Filter () = default;
+
+ // Apply stencil on MultiFab.
+ // Guard cells are handled inside this function
+ void ApplyStencil(amrex::MultiFab& dstmf,
+ const amrex::MultiFab& srcmf, int scomp=0,
+ int dcomp=0, int ncomp=10000);
+
+ // Apply stencil on a FabArray.
+ void ApplyStencil (amrex::FArrayBox& dstfab,
+ const amrex::FArrayBox& srcfab, const amrex::Box& tbx,
+ int scomp=0, int dcomp=0, int ncomp=10000);
+
+ // public for cuda
+ void DoFilter(const amrex::Box& tbx,
+ amrex::Array4<amrex::Real const> const& tmp,
+ amrex::Array4<amrex::Real > const& dst,
+ int scomp, int dcomp, int ncomp);
+
+ // In 2D, stencil_length_each_dir = {length(stencil_x), length(stencil_z)}
+ amrex::IntVect stencil_length_each_dir;
+
+protected:
+ // Stencil along each direction.
+ // in 2D, stencil_y is not initialized.
+ amrex::Gpu::ManagedVector<amrex::Real> stencil_x, stencil_y, stencil_z;
+ // Length of each stencil.
+ // In 2D, slen = {length(stencil_x), length(stencil_z), 1}
+ amrex::Dim3 slen;
+
+private:
+
+};
+#endif // #ifndef WARPX_FILTER_H_
diff --git a/Source/Filter/Filter.cpp b/Source/Filter/Filter.cpp
new file mode 100644
index 000000000..f8a2dd6c2
--- /dev/null
+++ b/Source/Filter/Filter.cpp
@@ -0,0 +1,257 @@
+#include <WarpX.H>
+#include <Filter.H>
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+using namespace amrex;
+
+#ifdef AMREX_USE_CUDA
+
+/* \brief Apply stencil on MultiFab (GPU version, 2D/3D).
+ * \param dstmf Destination MultiFab
+ * \param srcmf source MultiFab
+ * \param scomp first component of srcmf on which the filter is applied
+ * \param dcomp first component of dstmf on which the filter is applied
+ * \param ncomp Number of components on which the filter is applied.
+ */
+void
+Filter::ApplyStencil (MultiFab& dstmf, const MultiFab& srcmf, int scomp, int dcomp, int ncomp)
+{
+ BL_PROFILE("BilinearFilter::ApplyStencil(MultiFab)");
+ ncomp = std::min(ncomp, srcmf.nComp());
+
+ for (MFIter mfi(dstmf); mfi.isValid(); ++mfi)
+ {
+ const auto& src = srcmf.array(mfi);
+ const auto& dst = dstmf.array(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
+ FArrayBox tmp_fab(gbx,ncomp);
+ Elixir tmp_eli = tmp_fab.elixir(); // Prevent the tmp data from being deleted too early
+ auto const& tmp = tmp_fab.array();
+
+ // Copy values in srcfab into tmpfab
+ const Box& ibx = gbx & srcmf[mfi].box();
+ AMREX_PARALLEL_FOR_4D ( gbx, ncomp, i, j, k, n,
+ {
+ if (ibx.contains(IntVect(AMREX_D_DECL(i,j,k)))) {
+ tmp(i,j,k,n) = src(i,j,k,n+scomp);
+ } else {
+ tmp(i,j,k,n) = 0.0;
+ }
+ });
+
+ // Apply filter
+ DoFilter(tbx, tmp, dst, 0, dcomp, ncomp);
+ }
+}
+
+/* \brief Apply stencil on FArrayBox (GPU version, 2D/3D).
+ * \param dstfab Destination FArrayBox
+ * \param srcmf source FArrayBox
+ * \param tbx Grown box on which srcfab is defined.
+ * \param scomp first component of srcfab on which the filter is applied
+ * \param dcomp first component of dstfab on which the filter is applied
+ * \param ncomp Number of components on which the filter is applied.
+ */
+void
+Filter::ApplyStencil (FArrayBox& dstfab, const FArrayBox& srcfab,
+ const Box& tbx, int scomp, int dcomp, int ncomp)
+{
+ BL_PROFILE("BilinearFilter::ApplyStencil(FArrayBox)");
+ ncomp = std::min(ncomp, srcfab.nComp());
+ const auto& src = srcfab.array();
+ const auto& dst = dstfab.array();
+ const Box& gbx = amrex::grow(tbx,stencil_length_each_dir-1);
+
+ // tmpfab has enough ghost cells for the stencil
+ FArrayBox tmp_fab(gbx,ncomp);
+ Elixir tmp_eli = tmp_fab.elixir(); // Prevent the tmp data from being deleted too early
+ auto const& tmp = tmp_fab.array();
+
+ // Copy values in srcfab into tmpfab
+ const Box& ibx = gbx & srcfab.box();
+ AMREX_PARALLEL_FOR_4D ( gbx, ncomp, i, j, k, n,
+ {
+ if (ibx.contains(IntVect(AMREX_D_DECL(i,j,k)))) {
+ tmp(i,j,k,n) = src(i,j,k,n+scomp);
+ } else {
+ tmp(i,j,k,n) = 0.0;
+ }
+ });
+
+ // Apply filter
+ DoFilter(tbx, tmp, dst, 0, dcomp, ncomp);
+}
+
+/* \brief Apply stencil (2D/3D, CPU/GPU)
+ */
+void Filter::DoFilter (const Box& tbx,
+ Array4<Real const> const& tmp,
+ Array4<Real > const& dst,
+ int scomp, int dcomp, int ncomp)
+{
+ 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();
+ Dim3 slen_local = slen;
+ AMREX_PARALLEL_FOR_4D ( tbx, ncomp, i, j, k, n,
+ {
+ Real d = 0.0;
+
+ for (int iz=0; iz < slen_local.z; ++iz){
+ for (int iy=0; iy < slen_local.y; ++iy){
+ for (int ix=0; ix < slen_local.x; ++ix){
+#if (AMREX_SPACEDIM == 3)
+ Real sss = sx[ix]*sy[iy]*sz[iz];
+#else
+ Real sss = sx[ix]*sz[iy];
+#endif
+#if (AMREX_SPACEDIM == 3)
+ d += 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
+ d += 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
+ }
+ }
+ }
+
+ dst(i,j,k,dcomp+n) = d;
+ });
+}
+
+#else
+
+/* \brief Apply stencil on MultiFab (CPU version, 2D/3D).
+ * \param dstmf Destination MultiFab
+ * \param srcmf source MultiFab
+ * \param scomp first component of srcmf on which the filter is applied
+ * \param dcomp first component of dstmf on which the filter is applied
+ * \param ncomp Number of components on which the filter is applied.
+ */
+void
+Filter::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
+ DoFilter(tbx, tmpfab.array(), dstfab.array(), 0, dcomp, ncomp);
+ }
+ }
+}
+
+/* \brief Apply stencil on FArrayBox (CPU version, 2D/3D).
+ * \param dstfab Destination FArrayBox
+ * \param srcmf source FArrayBox
+ * \param tbx Grown box on which srcfab is defined.
+ * \param scomp first component of srcfab on which the filter is applied
+ * \param dcomp first component of dstfab on which the filter is applied
+ * \param ncomp Number of components on which the filter is applied.
+ */
+void
+Filter::ApplyStencil (FArrayBox& dstfab, const FArrayBox& srcfab,
+ const Box& tbx, int scomp, int dcomp, int ncomp)
+{
+ BL_PROFILE("BilinearFilter::ApplyStencil(FArrayBox)");
+ ncomp = std::min(ncomp, srcfab.nComp());
+ FArrayBox tmpfab;
+ 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
+ DoFilter(tbx, tmpfab.array(), dstfab.array(), 0, dcomp, ncomp);
+}
+
+void Filter::DoFilter (const Box& tbx,
+ Array4<Real const> const& tmp,
+ Array4<Real > const& dst,
+ int scomp, int dcomp, int ncomp)
+{
+ const auto lo = amrex::lbound(tbx);
+ const auto hi = amrex::ubound(tbx);
+ // 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
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif // #ifdef AMREX_USE_CUDA
diff --git a/Source/Filter/Make.package b/Source/Filter/Make.package
index 36e74bfb0..8b8e9b50b 100644
--- a/Source/Filter/Make.package
+++ b/Source/Filter/Make.package
@@ -1,5 +1,9 @@
+CEXE_headers += Filter.H
+CEXE_sources += Filter.cpp
CEXE_sources += BilinearFilter.cpp
CEXE_headers += BilinearFilter.H
+CEXE_sources += NCIGodfreyFilter.cpp
+CEXE_headers += NCIGodfreyFilter.H
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Filter
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Filter
diff --git a/Source/Filter/NCIGodfreyFilter.H b/Source/Filter/NCIGodfreyFilter.H
new file mode 100644
index 000000000..a53039dfa
--- /dev/null
+++ b/Source/Filter/NCIGodfreyFilter.H
@@ -0,0 +1,30 @@
+#include <Filter.H>
+
+#ifndef WARPX_GODFREY_FILTER_H_
+#define WARPX_GODFREY_FILTER_H_
+
+enum class godfrey_coeff_set { Ex_Ey_Bz=0, Bx_By_Ez=1 };
+
+class NCIGodfreyFilter : public Filter
+{
+public:
+
+ NCIGodfreyFilter () = default;
+
+ NCIGodfreyFilter(godfrey_coeff_set coeff_set_, amrex::Real cdtodz_, amrex::Real l_lower_order_in_v_);
+
+ void ComputeStencils();
+
+ void getGodfreyCoeffs(godfrey_coeff_set coeff_set_in);
+
+ static constexpr int stencil_width = 4;
+
+private:
+
+ godfrey_coeff_set coeff_set;
+ amrex::Real cdtodz;
+ int l_lower_order_in_v;
+
+};
+
+#endif // #ifndef WARPX_GODFREY_FILTER_H_
diff --git a/Source/Filter/NCIGodfreyFilter.cpp b/Source/Filter/NCIGodfreyFilter.cpp
new file mode 100644
index 000000000..3f589260a
--- /dev/null
+++ b/Source/Filter/NCIGodfreyFilter.cpp
@@ -0,0 +1,78 @@
+#include <WarpX.H>
+#include <NCIGodfreyFilter.H>
+#include <NCIGodfreyTables.H>
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+using namespace amrex;
+
+NCIGodfreyFilter::NCIGodfreyFilter(godfrey_coeff_set coeff_set_, amrex::Real cdtodz_, amrex::Real l_lower_order_in_v_){
+ // Store parameters into class data members
+ coeff_set = coeff_set_;
+ cdtodz = cdtodz_;
+ l_lower_order_in_v = l_lower_order_in_v_;
+ // NCI Godfrey filter has fixed size, and is applied along z only.
+#if (AMREX_SPACEDIM == 3)
+ stencil_length_each_dir = {1,1,5};
+ slen = {1,1,5};
+#else
+ stencil_length_each_dir = {1,5};
+ slen = {1,5,1};
+#endif
+}
+
+void NCIGodfreyFilter::ComputeStencils(){
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+#if ( AMREX_SPACEDIM == 3 )
+ slen.z==5,
+#else
+ slen.y==5,
+#endif
+ "ERROR: NCI filter requires 5 points in z");
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(l_lower_order_in_v==1,
+ "ERROR: NCI corrector requires l_lower_order_in_v=1, i.e., Galerkin scheme");
+
+ // Interpolate coefficients from the table, and store into prestencil.
+ int index = tab_length*cdtodz;
+ index = min(index, tab_length-2);
+ index = max(index, 0);
+ Real weight_right = cdtodz - index/tab_length;
+ Real prestencil[4];
+ for(int i=0; i<tab_width; i++){
+ if (coeff_set == godfrey_coeff_set::Ex_Ey_Bz) {
+ prestencil[i] = (1-weight_right)*table_nci_godfrey_Ex_Ey_Bz[index ][i] +
+ weight_right*table_nci_godfrey_Ex_Ey_Bz[index+1][i];
+ } else if (coeff_set == godfrey_coeff_set::Bx_By_Ez) {
+ prestencil[i] = (1-weight_right)*table_nci_godfrey_Bx_By_Ez[index ][i] +
+ weight_right*table_nci_godfrey_Bx_By_Ez[index+1][i];
+ }
+ }
+
+ // Compute stencil_z
+ stencil_z.resize( 5 );
+ stencil_z[0] = (256 + 128*prestencil[0] + 96*prestencil[1] + 80*prestencil[2] + 70*prestencil[3]) / 256;
+ stencil_z[1] = -( 64*prestencil[0] + 64*prestencil[1] + 60*prestencil[2] + 56*prestencil[3]) / 256;
+ stencil_z[2] = ( 16*prestencil[1] + 24*prestencil[2] + 28*prestencil[3]) / 256;
+ stencil_z[3] = -( 4*prestencil[2] + 8*prestencil[3]) / 256;
+ stencil_z[4] = ( 1*prestencil[3]) / 256;
+
+ // Compute stencil_x and stencil_y (no filter in these directions,
+ // so only 1 coeff, equal to 1)
+ stencil_x.resize(1);
+ stencil_x[0] = 1.;
+#if (AMREX_SPACEDIM == 3)
+ stencil_y.resize(1);
+ stencil_y[0] = 1.;
+#endif
+
+ // Due to the way Filter::DoFilter() is written,
+ // coefficient 0 has to be /2
+ stencil_x[0] /= 2.;
+#if (AMREX_SPACEDIM == 3)
+ stencil_y[0] /= 2.;
+#endif
+ stencil_z[0] /= 2.;
+
+}
diff --git a/Source/FortranInterface/WarpX_f.F90 b/Source/FortranInterface/WarpX_f.F90
index ccd6dd48a..d7f7a8053 100644
--- a/Source/FortranInterface/WarpX_f.F90
+++ b/Source/FortranInterface/WarpX_f.F90
@@ -186,6 +186,41 @@ contains
end subroutine warpx_compute_dive_2d
+ subroutine warpx_compute_dive_rz (lo, hi, dive, dlo, dhi, &
+ Ex, xlo, xhi, Ey, ylo, yhi, Ez, zlo, zhi, dx, rmin) &
+ bind(c, name='warpx_compute_dive_rz')
+ integer, intent(in) :: lo(2),hi(2),dlo(2),dhi(2),xlo(2),xhi(2),ylo(2),yhi(2),zlo(2),zhi(2)
+ real(amrex_real), intent(in) :: dx(3), rmin
+ real(amrex_real), intent(in ) :: Ex (xlo(1):xhi(1),xlo(2):xhi(2))
+ real(amrex_real), intent(in ) :: Ey (ylo(1):yhi(1),ylo(2):yhi(2))
+ real(amrex_real), intent(in ) :: Ez (zlo(1):zhi(1),zlo(2):zhi(2))
+ real(amrex_real), intent(inout) :: dive(dlo(1):dhi(1),dlo(2):dhi(2))
+
+ integer :: i,k
+ real(amrex_real) :: dxinv(3)
+ real(amrex_real) :: ru, rd
+
+ dxinv = 1.d0/dx
+
+ do k = lo(2), hi(2)
+ do i = lo(1), hi(1)
+ if (i == 0 .and. rmin == 0.) then
+ ! the bulk equation diverges on axis
+ ! (due to the 1/r terms). The following expressions regularize
+ ! these divergences.
+ dive(i,k) = 4.*dxinv(1) * Ex(i,k) &
+ + dxinv(3) * (Ez(i,k) - Ez(i,k-1))
+ else
+ ru = 1.d0 + 0.5d0/(rmin*dxinv(1) + i)
+ rd = 1.d0 - 0.5d0/(rmin*dxinv(1) + i)
+ dive(i,k) = dxinv(1) * (ru*Ex(i,k) - rd*Ex(i-1,k)) &
+ + dxinv(3) * (Ez(i,k) - Ez(i,k-1))
+ end if
+ end do
+ end do
+ end subroutine warpx_compute_dive_rz
+
+
subroutine warpx_sync_current_2d (lo, hi, crse, clo, chi, fine, flo, fhi, dir) &
bind(c, name='warpx_sync_current_2d')
integer, intent(in) :: lo(2), hi(2), flo(2), fhi(2), clo(2), chi(2), dir
diff --git a/Source/FortranInterface/WarpX_f.H b/Source/FortranInterface/WarpX_f.H
index 473ca645a..98dd8685d 100644
--- a/Source/FortranInterface/WarpX_f.H
+++ b/Source/FortranInterface/WarpX_f.H
@@ -39,16 +39,9 @@
#define WRPX_PUSH_LEAPFROG warpx_push_leapfrog_3d
#define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_3d
-#define WRPX_LORENTZ_TRANSFORM_Z warpx_lorentz_transform_z
-#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
-
-
#elif (AMREX_SPACEDIM == 2)
#define WRPX_COMPUTE_DIVB warpx_compute_divb_2d
-#define WRPX_COMPUTE_DIVE warpx_compute_dive_2d
#define WRPX_SYNC_CURRENT warpx_sync_current_2d
#define WRPX_SYNC_RHO warpx_sync_rho_2d
@@ -69,10 +62,11 @@
#define WRPX_PUSH_LEAPFROG warpx_push_leapfrog_2d
#define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_2d
-#define WRPX_LORENTZ_TRANSFORM_Z warpx_lorentz_transform_z
-#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
+#ifdef WARPX_RZ
+#define WRPX_COMPUTE_DIVE warpx_compute_dive_rz
+#else
+#define WRPX_COMPUTE_DIVE warpx_compute_dive_2d
+#endif
#endif
@@ -81,17 +75,11 @@ extern "C"
{
#endif
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
void warpx_copy_attribs(const long* np,
const amrex_real* xp, const amrex_real* yp, const amrex_real* zp,
const amrex_real* uxp, const amrex_real* uyp, const amrex_real* uzp,
amrex_real* xpold, amrex_real* ypold, amrex_real* zpold,
amrex_real* uxpold, amrex_real* uypold, amrex_real* uzpold);
-#endif
- void WRPX_COPY_SLICE(const int* lo, const int* hi,
- const amrex_real* tmp, const int* tlo, const int* thi,
- amrex_real* buf, const int* blo, const int* bhi,
- const int* ncomp, const int* i_boost, const int* i_lab);
// Charge deposition
void warpx_charge_deposition(amrex::Real* rho,
@@ -103,6 +91,12 @@ extern "C"
const long* nox, const long* noy,const long* noz,
const long* lvect, const long* charge_depo_algo);
+ // Charge deposition finalize for RZ
+ void warpx_charge_deposition_rz_volume_scaling(
+ amrex::Real* rho, const long* rho_ng, const int* rho_ntot,
+ const amrex::Real* rmin,
+ const amrex::Real* dr);
+
// Current deposition
void warpx_current_deposition(
amrex::Real* jx, const long* jx_ng, const int* jx_ntot,
@@ -116,7 +110,7 @@ extern "C"
const amrex::Real* dt,
const amrex::Real* dx, const amrex::Real* dy, const amrex::Real* dz,
const long* nox, const long* noy,const long* noz,
- const long* lvect, const long* current_depo_algo);
+ const int* l_nodal, const long* lvect, const long* current_depo_algo);
// Current deposition finalize for RZ
void warpx_current_deposition_rz_volume_scaling(
@@ -166,12 +160,6 @@ extern "C"
const amrex::Real* charge, const amrex::Real* mass, const amrex::Real* dt,
const long* particle_pusher_algo);
- // Particle pusher (position)
-
- void warpx_particle_pusher_positions(const long* np,
- amrex::Real* xp, amrex::Real* yp, amrex::Real* zp,
- amrex::Real* uxp, amrex::Real* uyp, amrex::Real* uzp, amrex::Real* gaminv,
- const amrex::Real* dt);
// Laser pusher
@@ -190,7 +178,7 @@ extern "C"
amrex::Real* u_Xx, amrex::Real* u_Xy, amrex::Real* u_Xz,
amrex::Real* u_Yx, amrex::Real* u_Yy, amrex::Real* u_Yz,
amrex::Real* positionx, amrex::Real* positiony, amrex::Real* positionz );
-
+
void update_laser_particle( const long* np,
amrex::Real* xp, amrex::Real* yp, amrex::Real* zp,
amrex::Real* uxp, amrex::Real* uyp, amrex::Real* uzp,
@@ -199,7 +187,7 @@ extern "C"
amrex::Real* nvecx, amrex::Real* nvecy, amrex::Real* nvecz,
amrex::Real* mobility, amrex::Real* dt, const amrex::Real* c,
const amrex::Real* beta_boost, const amrex::Real* gamma_boost );
-
+
// Maxwell solver
void warpx_push_evec(
@@ -345,10 +333,6 @@ extern "C"
const amrex::Real* dt, const amrex::Real* prob_lo,
const amrex::Real* prob_hi);
- void WRPX_LORENTZ_TRANSFORM_Z(amrex::Real* data, const int* dlo, const int* dhi,
- const int* tlo, const int* thi,
- const amrex::Real* gamma_boost, const amrex::Real* beta_boost);
-
// These functions are used to evolve E and B in the PML
void WRPX_COMPUTE_DIVB (const int* lo, const int* hi,
@@ -363,7 +347,11 @@ extern "C"
const BL_FORT_FAB_ARG_ANYD(ex),
const BL_FORT_FAB_ARG_ANYD(ey),
const BL_FORT_FAB_ARG_ANYD(ez),
- const amrex::Real* dx);
+ const amrex::Real* dx
+#ifdef WARPX_RZ
+ ,const amrex::Real* rmin
+#endif
+ );
void WRPX_PUSH_PML_BVEC(const int* xlo, const int* xhi,
const int* ylo, const int* yhi,
@@ -460,14 +448,6 @@ extern "C"
const BL_FORT_FAB_ARG_ANYD(fine),
const int* ncomp);
- void WRPX_PXR_NCI_CORR_INIT(amrex::Real*, amrex::Real*, const int,
- const amrex::Real, const int);
-
- void WRPX_PXR_GODFREY_FILTER (const int* lo, const int* hi,
- amrex_real* fou, const int* olo, const int* ohi,
- const amrex_real* fin, const int* ilo, const int* ihi,
- const amrex_real* stencil, const int* nsten);
-
#ifdef WARPX_USE_PSATD
void warpx_fft_mpi_init (int fcomm);
void warpx_fft_domain_decomp (int* warpx_local_nz, int* warpx_local_z0,
diff --git a/Source/FortranInterface/WarpX_picsar.F90 b/Source/FortranInterface/WarpX_picsar.F90
index 151342ff5..33f85c633 100644
--- a/Source/FortranInterface/WarpX_picsar.F90
+++ b/Source/FortranInterface/WarpX_picsar.F90
@@ -18,7 +18,8 @@
#define WRPX_PXR_GETEB_ENERGY_CONSERVING geteb2drz_energy_conserving_generic
#define WRPX_PXR_CURRENT_DEPOSITION depose_jrjtjz_generic_rz
-#define WRPX_PXR_RZ_VOLUME_SCALING apply_rz_volume_scaling
+#define WRPX_PXR_RZ_VOLUME_SCALING_RHO apply_rz_volume_scaling_rho
+#define WRPX_PXR_RZ_VOLUME_SCALING_J apply_rz_volume_scaling_j
#define WRPX_PXR_PUSH_BVEC pxrpush_emrz_bvec
#define WRPX_PXR_PUSH_EVEC pxrpush_emrz_evec
@@ -116,7 +117,7 @@ contains
pxr_ll4symtry = ll4symtry .eq. 1
pxr_l_lower_order_in_v = l_lower_order_in_v .eq. 1
pxr_l_nodal = l_nodal .eq. 1
-
+
exg_nguards = ixyzmin - exg_lo
eyg_nguards = ixyzmin - eyg_lo
ezg_nguards = ixyzmin - ezg_lo
@@ -217,6 +218,11 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
IF ((nox.eq.1).and.(noy.eq.1).and.(noz.eq.1)) THEN
CALL depose_rho_vecHVv2_1_1_1(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,nx,ny,nz,&
nxguard,nyguard,nzguard,lvect)
+
+ ELSE IF ((nox.eq.2).and.(noy.eq.2).and.(noz.eq.2)) THEN
+ CALL depose_rho_vecHVv2_2_2_2(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,nx,ny,nz,&
+ nxguard,nyguard,nzguard,lvect)
+
ELSE
CALL pxr_depose_rho_n(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,nx,ny,nz,&
nxguard,nyguard,nzguard,nox,noy,noz, &
@@ -227,9 +233,15 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
! Dimension 2
#elif (AMREX_SPACEDIM==2)
+#ifdef WARPX_RZ
+ logical(pxr_logical) :: l_2drz = .TRUE._c_long
+#else
+ logical(pxr_logical) :: l_2drz = .FALSE._c_long
+#endif
+
CALL pxr_depose_rho_n_2dxz(rho,np,xp,yp,zp,w,q,xmin,zmin,dx,dz,nx,nz,&
nxguard,nzguard,nox,noz, &
- .TRUE._c_long, .FALSE._c_long, .FALSE._c_long, 0_c_long)
+ .TRUE._c_long, .FALSE._c_long, l_2drz, 0_c_long)
#endif
@@ -238,6 +250,46 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
! _________________________________________________________________
!>
!> @brief
+ !> Applies the inverse volume scaling for RZ charge deposition
+ !>
+ !> @details
+ !> The scaling is done for both single mode (FDTD) and
+ !> multi mode (spectral) (todo)
+ !
+ !> @param[inout] rho charge array
+ !> @param[in] rmin tile grid minimum radius
+ !> @param[in] dr radial space discretization steps
+ !> @param[in] nx,ny,nz number of cells
+ !> @param[in] nxguard,nyguard,nzguard number of guard cells
+ !>
+ subroutine warpx_charge_deposition_rz_volume_scaling(rho,rho_ng,rho_ntot,rmin,dr) &
+ bind(C, name="warpx_charge_deposition_rz_volume_scaling")
+
+ integer, intent(in) :: rho_ntot(AMREX_SPACEDIM)
+ integer(c_long), intent(in) :: rho_ng
+ real(amrex_real), intent(IN OUT):: rho(*)
+ real(amrex_real), intent(IN) :: rmin, dr
+
+#ifdef WARPX_RZ
+ integer(c_long) :: type_rz_depose = 1
+#endif
+
+ ! Compute the number of valid cells and guard cells
+ integer(c_long) :: rho_nvalid(AMREX_SPACEDIM), rho_nguards(AMREX_SPACEDIM)
+ rho_nvalid = rho_ntot - 2*rho_ng
+ rho_nguards = rho_ng
+
+#ifdef WARPX_RZ
+ CALL WRPX_PXR_RZ_VOLUME_SCALING_RHO( &
+ rho,rho_nguards,rho_nvalid, &
+ rmin,dr,type_rz_depose)
+#endif
+
+ end subroutine warpx_charge_deposition_rz_volume_scaling
+
+ ! _________________________________________________________________
+ !>
+ !> @brief
!> Main subroutine for the current deposition
!>
!> @details
@@ -263,14 +315,14 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
subroutine warpx_current_deposition( &
jx,jx_ng,jx_ntot,jy,jy_ng,jy_ntot,jz,jz_ng,jz_ntot, &
np,xp,yp,zp,uxp,uyp,uzp,gaminv,w,q,xmin,ymin,zmin,dt,dx,dy,dz,nox,noy,noz,&
- lvect,current_depo_algo) &
+ l_nodal,lvect,current_depo_algo) &
bind(C, name="warpx_current_deposition")
integer, intent(in) :: jx_ntot(AMREX_SPACEDIM), jy_ntot(AMREX_SPACEDIM), jz_ntot(AMREX_SPACEDIM)
integer(c_long), intent(in) :: jx_ng, jy_ng, jz_ng
integer(c_long), intent(IN) :: np
integer(c_long), intent(IN) :: nox,noy,noz
-
+ integer(c_int), intent(in) :: l_nodal
real(amrex_real), intent(IN OUT):: jx(*), jy(*), jz(*)
real(amrex_real), intent(IN) :: q
real(amrex_real), intent(IN) :: dx,dy,dz
@@ -281,6 +333,7 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
real(amrex_real), intent(IN), dimension(np) :: gaminv
integer(c_long), intent(IN) :: lvect
integer(c_long), intent(IN) :: current_depo_algo
+ logical(pxr_logical) :: pxr_l_nodal
! Compute the number of valid cells and guard cells
integer(c_long) :: jx_nvalid(AMREX_SPACEDIM), jy_nvalid(AMREX_SPACEDIM), jz_nvalid(AMREX_SPACEDIM), &
@@ -291,6 +344,7 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
jx_nguards = jx_ng
jy_nguards = jy_ng
jz_nguards = jz_ng
+ pxr_l_nodal = l_nodal .eq. 1
! Dimension 3
#if (AMREX_SPACEDIM==3)
@@ -300,7 +354,7 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
jz,jz_nguards,jz_nvalid, &
np,xp,yp,zp,uxp,uyp,uzp,gaminv,w,q, &
xmin,ymin,zmin,dt,dx,dy,dz, &
- nox,noy,noz,current_depo_algo)
+ nox,noy,noz,pxr_l_nodal,current_depo_algo)
! Dimension 2
#elif (AMREX_SPACEDIM==2)
CALL WRPX_PXR_CURRENT_DEPOSITION( &
@@ -308,8 +362,8 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
jy,jy_nguards,jy_nvalid, &
jz,jz_nguards,jz_nvalid, &
np,xp,yp,zp,uxp,uyp,uzp,gaminv,w,q, &
- xmin,zmin,dt,dx,dz,nox,noz,lvect, &
- current_depo_algo)
+ xmin,zmin,dt,dx,dz,nox,noz,pxr_l_nodal, &
+ lvect,current_depo_algo)
#endif
end subroutine warpx_current_deposition
@@ -340,8 +394,9 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
real(amrex_real), intent(IN OUT):: jx(*), jy(*), jz(*)
real(amrex_real), intent(IN) :: rmin, dr
+#ifdef WARPX_RZ
integer(c_long) :: type_rz_depose = 1
-
+#endif
! Compute the number of valid cells and guard cells
integer(c_long) :: jx_nvalid(AMREX_SPACEDIM), jy_nvalid(AMREX_SPACEDIM), jz_nvalid(AMREX_SPACEDIM), &
jx_nguards(AMREX_SPACEDIM), jy_nguards(AMREX_SPACEDIM), jz_nguards(AMREX_SPACEDIM)
@@ -353,7 +408,7 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
jz_nguards = jz_ng
#ifdef WARPX_RZ
- CALL WRPX_PXR_RZ_VOLUME_SCALING( &
+ CALL WRPX_PXR_RZ_VOLUME_SCALING_J( &
jx,jx_nguards,jx_nvalid, &
jy,jy_nguards,jy_nvalid, &
jz,jz_nguards,jz_nvalid, &
@@ -413,7 +468,7 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
END SELECT
!!!! --- push particle species positions a time step
-#if (AMREX_SPACEDIM == 3)
+#if (AMREX_SPACEDIM == 3) || (defined WARPX_RZ)
CALL pxr_pushxyz(np,xp,yp,zp,uxp,uyp,uzp,gaminv,dt)
#elif (AMREX_SPACEDIM == 2)
CALL pxr_pushxz(np,xp,zp,uxp,uzp,gaminv,dt)
@@ -477,38 +532,6 @@ subroutine warpx_charge_deposition(rho,np,xp,yp,zp,w,q,xmin,ymin,zmin,dx,dy,dz,n
! _________________________________________________________________
!>
!> @brief
- !> Main subroutine for the particle pusher of positions
- !>
- !> @param[in] np number of super-particles
- !> @param[in] xp,yp,zp particle position arrays
- !> @param[in] uxp,uyp,uzp normalized momentum in each direction
- !> @param[in] gaminv particle Lorentz factors
- !> @param[in] dt time step
- !> @param[in] particle_pusher_algo Particle pusher algorithm
- subroutine warpx_particle_pusher_positions(np,xp,yp,zp,uxp,uyp,uzp, &
- gaminv,dt) &
- bind(C, name="warpx_particle_pusher_positions")
-
- INTEGER(c_long), INTENT(IN) :: np
- REAL(amrex_real),INTENT(INOUT) :: gaminv(np)
- REAL(amrex_real),INTENT(INOUT) :: xp(np),yp(np),zp(np)
- REAL(amrex_real),INTENT(INOUT) :: uxp(np),uyp(np),uzp(np)
- REAL(amrex_real),INTENT(IN) :: dt
-
- CALL pxr_set_gamma(np,uxp,uyp,uzp,gaminv)
-
- !!!! --- push particle species positions a time step
-#if (AMREX_SPACEDIM == 3)
- CALL pxr_pushxyz(np,xp,yp,zp,uxp,uyp,uzp,gaminv,dt)
-#elif (AMREX_SPACEDIM == 2)
- CALL pxr_pushxz(np,xp,zp,uxp,uzp,gaminv,dt)
-#endif
-
- end subroutine warpx_particle_pusher_positions
-
- ! _________________________________________________________________
- !>
- !> @brief
!> Main subroutine for the Maxwell solver (E field)
!>
!> @param[in] xlo, xhi, ylo, yhi, zlo, zhi lower and higher bounds
diff --git a/Source/Initialization/Make.package b/Source/Initialization/Make.package
index b825924c6..edcf402c9 100644
--- a/Source/Initialization/Make.package
+++ b/Source/Initialization/Make.package
@@ -1,4 +1,5 @@
CEXE_sources += CustomDensityProb.cpp
+CEXE_sources += PlasmaProfiles.cpp
CEXE_sources += WarpXInitData.cpp
CEXE_sources += CustomMomentumProb.cpp
CEXE_sources += PlasmaInjector.cpp
diff --git a/Source/Initialization/PlasmaInjector.H b/Source/Initialization/PlasmaInjector.H
index f6b76e8b6..f998e217e 100644
--- a/Source/Initialization/PlasmaInjector.H
+++ b/Source/Initialization/PlasmaInjector.H
@@ -10,6 +10,8 @@
#include "AMReX_ParmParse.H"
#include "AMReX_Utility.H"
+enum class predefined_profile_flag { Null, parabolic_channel };
+
///
/// PlasmaDensityProfile describes how the charge density
/// is set in particle initialization. Subclasses must define a
@@ -59,6 +61,24 @@ private:
};
///
+/// This describes predefined density distributions.
+///
+class PredefinedDensityProfile : public PlasmaDensityProfile
+{
+public:
+ PredefinedDensityProfile(const std::string& species_name);
+ virtual amrex::Real getDensity(amrex::Real x,
+ amrex::Real y,
+ amrex::Real z) const override;
+ amrex::Real ParabolicChannel(amrex::Real x,
+ amrex::Real y,
+ amrex::Real z) const;
+private:
+ predefined_profile_flag which_profile = predefined_profile_flag::Null;
+ amrex::Vector<amrex::Real> params;
+};
+
+///
/// This describes a density function parsed in the input file.
///
class ParseDensityProfile : public PlasmaDensityProfile
@@ -273,6 +293,7 @@ public:
amrex::Real z_rms;
amrex::Real q_tot;
long npart;
+ int do_symmetrize = 0;
bool radially_weighted = true;
diff --git a/Source/Initialization/PlasmaInjector.cpp b/Source/Initialization/PlasmaInjector.cpp
index 0da9318de..f9642d1b6 100644
--- a/Source/Initialization/PlasmaInjector.cpp
+++ b/Source/Initialization/PlasmaInjector.cpp
@@ -70,6 +70,17 @@ CustomDensityProfile::CustomDensityProfile(const std::string& species_name)
pp.getarr("custom_profile_params", params);
}
+PredefinedDensityProfile::PredefinedDensityProfile(const std::string& species_name)
+{
+ ParmParse pp(species_name);
+ std::string which_profile_s;
+ pp.getarr("predefined_profile_params", params);
+ pp.query("predefined_profile_name", which_profile_s);
+ if (which_profile_s == "parabolic_channel"){
+ which_profile = predefined_profile_flag::parabolic_channel;
+ }
+}
+
ParseDensityProfile::ParseDensityProfile(std::string parse_density_function)
: _parse_density_function(parse_density_function)
{
@@ -275,6 +286,7 @@ PlasmaInjector::PlasmaInjector(int ispecies, const std::string& name)
pp.get("z_rms", z_rms);
pp.get("q_tot", q_tot);
pp.get("npart", npart);
+ pp.query("do_symmetrize", do_symmetrize);
gaussian_beam = true;
parseMomentum(pp);
}
@@ -333,6 +345,8 @@ void PlasmaInjector::parseDensity(ParmParse pp){
rho_prof.reset(new ConstantDensityProfile(density));
} else if (rho_prof_s == "custom") {
rho_prof.reset(new CustomDensityProfile(species_name));
+ } else if (rho_prof_s == "predefined") {
+ rho_prof.reset(new PredefinedDensityProfile(species_name));
} else if (rho_prof_s == "parse_density_function") {
pp.get("density_function(x,y,z)", str_density_function);
rho_prof.reset(new ParseDensityProfile(str_density_function));
diff --git a/Source/Initialization/PlasmaProfiles.cpp b/Source/Initialization/PlasmaProfiles.cpp
new file mode 100644
index 000000000..d9d207f7e
--- /dev/null
+++ b/Source/Initialization/PlasmaProfiles.cpp
@@ -0,0 +1,41 @@
+#include <PlasmaInjector.H>
+#include <cmath>
+#include <iostream>
+#include <WarpXConst.H>
+
+using namespace amrex;
+
+Real PredefinedDensityProfile::getDensity(Real x, Real y, Real z) const {
+ Real n;
+ if ( which_profile == predefined_profile_flag::parabolic_channel ) {
+ n = ParabolicChannel(x,y,z);
+ }
+ return n;
+}
+
+///
+/// plateau between linear upramp and downramp, and parab transverse profile
+///
+Real PredefinedDensityProfile::ParabolicChannel(Real x, Real y, Real z) const {
+ // params = [z_start ramp_up plateau ramp_down rc n0]
+ Real z_start = params[0];
+ Real ramp_up = params[1];
+ Real plateau = params[2];
+ Real ramp_down = params[3];
+ Real rc = params[4];
+ Real n0 = params[5];
+ Real n;
+ Real kp = PhysConst::q_e/PhysConst::c*sqrt( n0/(PhysConst::m_e*PhysConst::ep0) );
+
+ if ((z-z_start)>=0 and (z-z_start)<ramp_up ) {
+ n = (z-z_start)/ramp_up;
+ } else if ((z-z_start)>=ramp_up and (z-z_start)<ramp_up+plateau ) {
+ n = 1;
+ } else if ((z-z_start)>=ramp_up+plateau and (z-z_start)<ramp_up+plateau+ramp_down) {
+ n = 1-((z-z_start)-ramp_up-plateau)/ramp_down;
+ } else {
+ n = 0;
+ }
+ n *= n0*(1+4*(x*x+y*y)/(kp*kp*std::pow(rc,4)));
+ return n;
+}
diff --git a/Source/Initialization/WarpXInitData.cpp b/Source/Initialization/WarpXInitData.cpp
index 23637ec97..d583b2b0f 100644
--- a/Source/Initialization/WarpXInitData.cpp
+++ b/Source/Initialization/WarpXInitData.cpp
@@ -7,6 +7,7 @@
#include <WarpX.H>
#include <WarpX_f.H>
#include <BilinearFilter.H>
+#include <NCIGodfreyFilter.H>
#ifdef BL_USE_SENSEI_INSITU
#include <AMReX_AmrMeshInSituBridge.H>
@@ -161,8 +162,6 @@ WarpX::InitNCICorrector ()
{
if (WarpX::use_fdtd_nci_corr)
{
- mypc->fdtd_nci_stencilz_ex.resize(max_level+1);
- mypc->fdtd_nci_stencilz_by.resize(max_level+1);
for (int lev = 0; lev <= max_level; ++lev)
{
const Geometry& gm = Geom(lev);
@@ -174,10 +173,15 @@ WarpX::InitNCICorrector ()
dz = dx[1];
}
cdtodz = PhysConst::c * dt[lev] / dz;
- WRPX_PXR_NCI_CORR_INIT( (mypc->fdtd_nci_stencilz_ex)[lev].data(),
- (mypc->fdtd_nci_stencilz_by)[lev].data(),
- mypc->nstencilz_fdtd_nci_corr, cdtodz,
- WarpX::l_lower_order_in_v);
+
+ // Initialize Godfrey filters
+ // Same filter for fields Ex, Ey and Bz
+ nci_godfrey_filter_exeybz[lev].reset( new NCIGodfreyFilter(godfrey_coeff_set::Ex_Ey_Bz, cdtodz, WarpX::l_lower_order_in_v) );
+ // Same filter for fields Bx, By and Ez
+ nci_godfrey_filter_bxbyez[lev].reset( new NCIGodfreyFilter(godfrey_coeff_set::Bx_By_Ez, cdtodz, WarpX::l_lower_order_in_v) );
+ // Compute Godfrey filters stencils
+ nci_godfrey_filter_exeybz[lev]->ComputeStencils();
+ nci_godfrey_filter_bxbyez[lev]->ComputeStencils();
}
}
}
@@ -318,6 +322,7 @@ WarpX::InitLevelData (int lev, Real time)
void
WarpX::InitLevelDataFFT (int lev, Real time)
{
+
Efield_fp_fft[lev][0]->setVal(0.0);
Efield_fp_fft[lev][1]->setVal(0.0);
Efield_fp_fft[lev][2]->setVal(0.0);
@@ -342,6 +347,7 @@ WarpX::InitLevelDataFFT (int lev, Real time)
current_cp_fft[lev][2]->setVal(0.0);
rho_cp_fft[lev]->setVal(0.0);
}
+
}
#endif
diff --git a/Source/Laser/LaserParticleContainer.H b/Source/Laser/LaserParticleContainer.H
index 624e795e5..516e368ab 100644
--- a/Source/Laser/LaserParticleContainer.H
+++ b/Source/Laser/LaserParticleContainer.H
@@ -13,21 +13,21 @@ class LaserParticleContainer
: public WarpXParticleContainer
{
public:
- LaserParticleContainer (amrex::AmrCore* amr_core, int ispecies);
+ LaserParticleContainer (amrex::AmrCore* amr_core, int ispecies, const std::string& name);
virtual ~LaserParticleContainer () {}
virtual void InitData () final;
#ifdef WARPX_DO_ELECTROSTATIC
virtual void EvolveES (const amrex::Vector<std::array<std::unique_ptr<amrex::MultiFab>, 3> >& E,
- amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rho,
+ amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rho,
amrex::Real t, amrex::Real dt) { BL_ASSERT(false); }
#endif // WARPX_DO_ELECTROSTATIC
virtual void Evolve (int lev,
- const amrex::MultiFab&, const amrex::MultiFab&, const amrex::MultiFab&,
- const amrex::MultiFab&, const amrex::MultiFab&, const amrex::MultiFab&,
- amrex::MultiFab& jx, amrex::MultiFab& jy, amrex::MultiFab& jz,
+ const amrex::MultiFab&, const amrex::MultiFab&, const amrex::MultiFab&,
+ const amrex::MultiFab&, const amrex::MultiFab&, const amrex::MultiFab&,
+ amrex::MultiFab& jx, amrex::MultiFab& jy, amrex::MultiFab& jz,
amrex::MultiFab*, amrex::MultiFab*, amrex::MultiFab*,
amrex::MultiFab* rho, amrex::MultiFab* crho,
const amrex::MultiFab*, const amrex::MultiFab*, const amrex::MultiFab*,
@@ -44,6 +44,10 @@ public:
virtual void PostRestart () final;
+protected:
+
+ std::string laser_name;
+
private:
// runtime paramters
@@ -80,11 +84,19 @@ private:
std::string field_function;
// laser particle domain
- amrex::RealBox prob_domain;
-
+ amrex::RealBox laser_injection_box;
+ // Theoretical position of the antenna. Used if do_continuous_injection=1.
+ // Track the position of the antenna until it enters the simulation domain.
+ amrex::Vector<amrex::Real> updated_position;
+
void ComputeSpacing (int lev, amrex::Real& Sx, amrex::Real& Sy) const;
void ComputeWeightMobility (amrex::Real Sx, amrex::Real Sy);
void InitData (int lev);
+ // Inject the laser antenna during the simulation, if it started
+ // outside of the simulation domain and enters it.
+ void ContinuousInjection(const amrex::RealBox& injection_box) override;
+ // Update position of the antenna
+ void UpdateContinuousInjectionPosition(amrex::Real dt) override;
};
#endif
diff --git a/Source/Laser/LaserParticleContainer.cpp b/Source/Laser/LaserParticleContainer.cpp
index db5499b8e..2f964b6f3 100644
--- a/Source/Laser/LaserParticleContainer.cpp
+++ b/Source/Laser/LaserParticleContainer.cpp
@@ -15,19 +15,19 @@ namespace
{
Vector<Real> CrossProduct (const Vector<Real>& a, const Vector<Real>& b)
{
- return { a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0] };
+ return { a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0] };
}
}
-LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies)
- : WarpXParticleContainer(amr_core, ispecies)
+LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies, const std::string& name)
+ : WarpXParticleContainer(amr_core, ispecies),
+ laser_name(name)
{
charge = 1.0;
mass = std::numeric_limits<Real>::max();
-
- if (WarpX::use_laser)
- {
- ParmParse pp("laser");
+ do_boosted_frame_diags = 0;
+
+ ParmParse pp(laser_name);
// Parse the type of laser profile and set the corresponding flag `profile`
std::string laser_type_s;
@@ -35,10 +35,10 @@ LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies)
std::transform(laser_type_s.begin(), laser_type_s.end(), laser_type_s.begin(), ::tolower);
if (laser_type_s == "gaussian") {
profile = laser_t::Gaussian;
- } else if(laser_type_s == "harris") {
- profile = laser_t::Harris;
- } else if(laser_type_s == "parse_field_function") {
- profile = laser_t::parse_field_function;
+ } else if(laser_type_s == "harris") {
+ profile = laser_t::Harris;
+ } else if(laser_type_s == "parse_field_function") {
+ profile = laser_t::parse_field_function;
} else {
amrex::Abort("Unknown laser type");
}
@@ -50,94 +50,94 @@ LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies)
pp.query("pusher_algo", pusher_algo);
pp.get("wavelength", wavelength);
pp.get("e_max", e_max);
+ pp.query("do_continuous_injection", do_continuous_injection);
if ( profile == laser_t::Gaussian ) {
// Parse the properties of the Gaussian profile
- pp.get("profile_waist", profile_waist);
- pp.get("profile_duration", profile_duration);
- pp.get("profile_t_peak", profile_t_peak);
- pp.get("profile_focal_distance", profile_focal_distance);
- stc_direction = p_X;
- pp.queryarr("stc_direction", stc_direction);
- pp.query("zeta", zeta);
- pp.query("beta", beta);
- pp.query("phi2", phi2);
+ pp.get("profile_waist", profile_waist);
+ pp.get("profile_duration", profile_duration);
+ pp.get("profile_t_peak", profile_t_peak);
+ pp.get("profile_focal_distance", profile_focal_distance);
+ stc_direction = p_X;
+ pp.queryarr("stc_direction", stc_direction);
+ pp.query("zeta", zeta);
+ pp.query("beta", beta);
+ pp.query("phi2", phi2);
}
- if ( profile == laser_t::Harris ) {
- // Parse the properties of the Harris profile
- pp.get("profile_waist", profile_waist);
- pp.get("profile_duration", profile_duration);
- pp.get("profile_focal_distance", profile_focal_distance);
- }
+ if ( profile == laser_t::Harris ) {
+ // Parse the properties of the Harris profile
+ pp.get("profile_waist", profile_waist);
+ pp.get("profile_duration", profile_duration);
+ pp.get("profile_focal_distance", profile_focal_distance);
+ }
- if ( profile == laser_t::parse_field_function ) {
- // Parse the properties of the parse_field_function profile
- pp.get("field_function(X,Y,t)", field_function);
- parser.define(field_function);
- parser.registerVariables({"X","Y","t"});
-
- ParmParse pp("my_constants");
- std::set<std::string> symbols = parser.symbols();
- symbols.erase("X");
- symbols.erase("Y");
- symbols.erase("t"); // after removing variables, we are left with constants
- for (auto it = symbols.begin(); it != symbols.end(); ) {
- Real v;
- if (pp.query(it->c_str(), v)) {
- parser.setConstant(*it, v);
- it = symbols.erase(it);
- } else {
- ++it;
- }
- }
- for (auto const& s : symbols) { // make sure there no unknown symbols
- amrex::Abort("Laser Profile: Unknown symbol "+s);
+ if ( profile == laser_t::parse_field_function ) {
+ // Parse the properties of the parse_field_function profile
+ pp.get("field_function(X,Y,t)", field_function);
+ parser.define(field_function);
+ parser.registerVariables({"X","Y","t"});
+
+ ParmParse ppc("my_constants");
+ std::set<std::string> symbols = parser.symbols();
+ symbols.erase("X");
+ symbols.erase("Y");
+ symbols.erase("t"); // after removing variables, we are left with constants
+ for (auto it = symbols.begin(); it != symbols.end(); ) {
+ Real v;
+ if (ppc.query(it->c_str(), v)) {
+ parser.setConstant(*it, v);
+ it = symbols.erase(it);
+ } else {
+ ++it;
}
}
+ for (auto const& s : symbols) { // make sure there no unknown symbols
+ amrex::Abort("Laser Profile: Unknown symbol "+s);
+ }
+ }
// Plane normal
Real s = 1.0/std::sqrt(nvec[0]*nvec[0] + nvec[1]*nvec[1] + nvec[2]*nvec[2]);
nvec = { nvec[0]*s, nvec[1]*s, nvec[2]*s };
- if (WarpX::gamma_boost > 1.) {
- // Check that the laser direction is equal to the boost direction
- AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
- nvec[0]*WarpX::boost_direction[0]
- + nvec[1]*WarpX::boost_direction[1]
- + nvec[2]*WarpX::boost_direction[2] - 1. < 1.e-12,
- "The Lorentz boost should be in the same direction as the laser propagation");
- // Get the position of the plane, along the boost direction, in the lab frame
- // and convert the position of the antenna to the boosted frame
- Z0_lab = nvec[0]*position[0] + nvec[1]*position[1] + nvec[2]*position[2];
- Real Z0_boost = Z0_lab/WarpX::gamma_boost;
- position[0] += (Z0_boost-Z0_lab)*nvec[0];
- position[1] += (Z0_boost-Z0_lab)*nvec[1];
- position[2] += (Z0_boost-Z0_lab)*nvec[2];
- }
+ if (WarpX::gamma_boost > 1.) {
+ // Check that the laser direction is equal to the boost direction
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE( nvec[0]*WarpX::boost_direction[0]
+ + nvec[1]*WarpX::boost_direction[1]
+ + nvec[2]*WarpX::boost_direction[2] - 1. < 1.e-12,
+ "The Lorentz boost should be in the same direction as the laser propagation");
+ // Get the position of the plane, along the boost direction, in the lab frame
+ // and convert the position of the antenna to the boosted frame
+ Z0_lab = nvec[0]*position[0] + nvec[1]*position[1] + nvec[2]*position[2];
+ Real Z0_boost = Z0_lab/WarpX::gamma_boost;
+ position[0] += (Z0_boost-Z0_lab)*nvec[0];
+ position[1] += (Z0_boost-Z0_lab)*nvec[1];
+ position[2] += (Z0_boost-Z0_lab)*nvec[2];
+ }
// The first polarization vector
s = 1.0/std::sqrt(p_X[0]*p_X[0] + p_X[1]*p_X[1] + p_X[2]*p_X[2]);
p_X = { p_X[0]*s, p_X[1]*s, p_X[2]*s };
Real dp = std::inner_product(nvec.begin(), nvec.end(), p_X.begin(), 0.0);
- AMREX_ALWAYS_ASSERT_WITH_MESSAGE(std::abs(dp) < 1.0e-14,
- "Laser plane vector is not perpendicular to the main polarization vector");
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(std::abs(dp) < 1.0e-14,
+ "Laser plane vector is not perpendicular to the main polarization vector");
p_Y = CrossProduct(nvec, p_X); // The second polarization vector
s = 1.0/std::sqrt(stc_direction[0]*stc_direction[0] + stc_direction[1]*stc_direction[1] + stc_direction[2]*stc_direction[2]);
stc_direction = { stc_direction[0]*s, stc_direction[1]*s, stc_direction[2]*s };
dp = std::inner_product(nvec.begin(), nvec.end(), stc_direction.begin(), 0.0);
- AMREX_ALWAYS_ASSERT_WITH_MESSAGE(std::abs(dp) < 1.0e-14,
- "stc_direction is not perpendicular to the laser plane vector");
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(std::abs(dp) < 1.0e-14,
+ "stc_direction is not perpendicular to the laser plane vector");
// Get angle between p_X and stc_direction
// in 2d, stcs are in the simulation plane
#if AMREX_SPACEDIM == 3
theta_stc = acos(stc_direction[0]*p_X[0] +
- stc_direction[1]*p_X[1] +
- stc_direction[2]*p_X[2]);
+ stc_direction[1]*p_X[1] +
+ stc_direction[2]*p_X[2]);
#else
theta_stc = 0.;
#endif
@@ -150,19 +150,96 @@ LaserParticleContainer::LaserParticleContainer (AmrCore* amr_core, int ispecies)
u_Y = {0., 1., 0.};
#endif
- prob_domain = Geometry::ProbDomain();
- {
- Vector<Real> lo, hi;
- if (pp.queryarr("prob_lo", lo)) {
- prob_domain.setLo(lo);
- }
- if (pp.queryarr("prob_hi", hi)) {
- prob_domain.setHi(hi);
- }
+ laser_injection_box= Geom(0).ProbDomain();
+ {
+ Vector<Real> lo, hi;
+ if (pp.queryarr("prob_lo", lo)) {
+ laser_injection_box.setLo(lo);
+ }
+ if (pp.queryarr("prob_hi", hi)) {
+ laser_injection_box.setHi(hi);
+ }
+ }
+
+ if (do_continuous_injection){
+ // If laser antenna initially outside of the box, store its theoretical
+ // position in z_antenna_th
+ updated_position = position;
+
+ // Sanity checks
+ int dir = WarpX::moving_window_dir;
+ std::vector<Real> windir(3, 0.0);
+#if (AMREX_SPACEDIM==2)
+ windir[2*dir] = 1.0;
+#else
+ windir[dir] = 1.0;
+#endif
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ (nvec[0]-windir[0]) + (nvec[1]-windir[1]) + (nvec[2]-windir[2])
+ < 1.e-12, "do_continous_injection for laser particle only works" +
+ " if moving window direction and laser propagation direction are the same");
+ if ( WarpX::gamma_boost>1 ){
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ (WarpX::boost_direction[0]-0)*(WarpX::boost_direction[0]-0) +
+ (WarpX::boost_direction[1]-0)*(WarpX::boost_direction[1]-0) +
+ (WarpX::boost_direction[2]-1)*(WarpX::boost_direction[2]-1) < 1.e-12,
+ "do_continous_injection for laser particle only works if " +
+ "warpx.boost_direction = z. TODO: all directions.");
}
}
}
+/* \brief Check if laser particles enter the box, and inject if necessary.
+ * \param injection_box: a RealBox where particles should be injected.
+ */
+void
+LaserParticleContainer::ContinuousInjection (const RealBox& injection_box)
+{
+ // Input parameter injection_box contains small box where injection
+ // should occur.
+ // So far, LaserParticleContainer::laser_injection_box contains the
+ // outdated full problem domain at t=0.
+
+ // Convert updated_position to Real* to use RealBox::contains().
+#if (AMREX_SPACEDIM == 3)
+ const Real* p_pos = updated_position.dataPtr();
+#else
+ const Real p_pos[2] = {updated_position[0], updated_position[2]};
+#endif
+ if ( injection_box.contains(p_pos) ){
+ // Update laser_injection_box with current value
+ laser_injection_box = injection_box;
+ // Inject laser particles. LaserParticleContainer::InitData
+ // is called only once, when the antenna enters the simulation
+ // domain.
+ InitData();
+ }
+}
+
+/* \brief update position of the antenna if running in boosted frame.
+ * \param dt time step (level 0).
+ * The up-to-date antenna position is stored in updated_position.
+ */
+void
+LaserParticleContainer::UpdateContinuousInjectionPosition(Real dt)
+{
+ int dir = WarpX::moving_window_dir;
+ if (do_continuous_injection and (WarpX::gamma_boost > 1)){
+ // In boosted-frame simulations, the antenna has moved since the last
+ // call to this function, and injection position needs to be updated
+#if ( AMREX_SPACEDIM == 3 )
+ updated_position[dir] -= WarpX::beta_boost *
+ WarpX::boost_direction[dir] * PhysConst::c * dt;
+#elif ( AMREX_SPACEDIM == 2 )
+ // In 2D, dir=0 corresponds to x and dir=1 corresponds to z
+ // This needs to be converted in order to index `boost_direction`
+ // which has 3 components, for both 2D and 3D simulations.
+ updated_position[2*dir] -= WarpX::beta_boost *
+ WarpX::boost_direction[2*dir] * PhysConst::c * dt;
+#endif
+ }
+}
+
void
LaserParticleContainer::InitData ()
{
@@ -178,60 +255,64 @@ LaserParticleContainer::InitData (int lev)
ComputeSpacing(lev, S_X, S_Y);
ComputeWeightMobility(S_X, S_Y);
- auto Transform = [&](int i, int j) -> Vector<Real>
- {
+ // LaserParticleContainer::position contains the initial position of the
+ // laser antenna. In the boosted frame, the antenna is moving.
+ // Update its position with updated_position.
+ if (do_continuous_injection){
+ position = updated_position;
+ }
+
+ auto Transform = [&](int i, int j) -> Vector<Real>{
#if (AMREX_SPACEDIM == 3)
- return { position[0] + (S_X*(i+0.5))*u_X[0] + (S_Y*(j+0.5))*u_Y[0],
- position[1] + (S_X*(i+0.5))*u_X[1] + (S_Y*(j+0.5))*u_Y[1],
- position[2] + (S_X*(i+0.5))*u_X[2] + (S_Y*(j+0.5))*u_Y[2] };
+ return { position[0] + (S_X*(i+0.5))*u_X[0] + (S_Y*(j+0.5))*u_Y[0],
+ position[1] + (S_X*(i+0.5))*u_X[1] + (S_Y*(j+0.5))*u_Y[1],
+ position[2] + (S_X*(i+0.5))*u_X[2] + (S_Y*(j+0.5))*u_Y[2] };
#else
- return { position[0] + (S_X*(i+0.5))*u_X[0],
- 0.0,
- position[2] + (S_X*(i+0.5))*u_X[2] };
+ return { position[0] + (S_X*(i+0.5))*u_X[0],
+ 0.0,
+ position[2] + (S_X*(i+0.5))*u_X[2] };
#endif
};
// Given the "lab" frame coordinates, return the real coordinates in the laser plane coordinates
- auto InverseTransform = [&](const Vector<Real>& pos) -> Vector<Real>
- {
+ auto InverseTransform = [&](const Vector<Real>& pos) -> Vector<Real>{
#if (AMREX_SPACEDIM == 3)
- return {u_X[0]*(pos[0]-position[0])+u_X[1]*(pos[1]-position[1])+u_X[2]*(pos[2]-position[2]),
- u_Y[0]*(pos[0]-position[0])+u_Y[1]*(pos[1]-position[1])+u_Y[2]*(pos[2]-position[2])};
+ return {u_X[0]*(pos[0]-position[0])+u_X[1]*(pos[1]-position[1])+u_X[2]*(pos[2]-position[2]),
+ u_Y[0]*(pos[0]-position[0])+u_Y[1]*(pos[1]-position[1])+u_Y[2]*(pos[2]-position[2])};
#else
- return {u_X[0]*(pos[0]-position[0])+u_X[2]*(pos[2]-position[2]), 0.0};
+ return {u_X[0]*(pos[0]-position[0])+u_X[2]*(pos[2]-position[2]), 0.0};
#endif
};
Vector<int> plane_lo(2, std::numeric_limits<int>::max());
Vector<int> plane_hi(2, std::numeric_limits<int>::min());
{
- auto compute_min_max = [&](Real x, Real y, Real z)
- {
- const Vector<Real>& pos_plane = InverseTransform({x, y, z});
- int i = pos_plane[0]/S_X;
- int j = pos_plane[1]/S_Y;
- plane_lo[0] = std::min(plane_lo[0], i);
- plane_lo[1] = std::min(plane_lo[1], j);
- plane_hi[0] = std::max(plane_hi[0], i);
- plane_hi[1] = std::max(plane_hi[1], j);
- };
-
- const Real* prob_lo = prob_domain.lo();
- const Real* prob_hi = prob_domain.hi();
+ auto compute_min_max = [&](Real x, Real y, Real z){
+ const Vector<Real>& pos_plane = InverseTransform({x, y, z});
+ int i = pos_plane[0]/S_X;
+ int j = pos_plane[1]/S_Y;
+ plane_lo[0] = std::min(plane_lo[0], i);
+ plane_lo[1] = std::min(plane_lo[1], j);
+ plane_hi[0] = std::max(plane_hi[0], i);
+ plane_hi[1] = std::max(plane_hi[1], j);
+ };
+
+ const Real* prob_lo = laser_injection_box.lo();
+ const Real* prob_hi = laser_injection_box.hi();
#if (AMREX_SPACEDIM == 3)
- compute_min_max(prob_lo[0], prob_lo[1], prob_lo[2]);
- compute_min_max(prob_hi[0], prob_lo[1], prob_lo[2]);
- compute_min_max(prob_lo[0], prob_hi[1], prob_lo[2]);
- compute_min_max(prob_hi[0], prob_hi[1], prob_lo[2]);
- compute_min_max(prob_lo[0], prob_lo[1], prob_hi[2]);
- compute_min_max(prob_hi[0], prob_lo[1], prob_hi[2]);
- compute_min_max(prob_lo[0], prob_hi[1], prob_hi[2]);
- compute_min_max(prob_hi[0], prob_hi[1], prob_hi[2]);
+ compute_min_max(prob_lo[0], prob_lo[1], prob_lo[2]);
+ compute_min_max(prob_hi[0], prob_lo[1], prob_lo[2]);
+ compute_min_max(prob_lo[0], prob_hi[1], prob_lo[2]);
+ compute_min_max(prob_hi[0], prob_hi[1], prob_lo[2]);
+ compute_min_max(prob_lo[0], prob_lo[1], prob_hi[2]);
+ compute_min_max(prob_hi[0], prob_lo[1], prob_hi[2]);
+ compute_min_max(prob_lo[0], prob_hi[1], prob_hi[2]);
+ compute_min_max(prob_hi[0], prob_hi[1], prob_hi[2]);
#else
- compute_min_max(prob_lo[0], 0.0, prob_lo[1]);
- compute_min_max(prob_hi[0], 0.0, prob_lo[1]);
- compute_min_max(prob_lo[0], 0.0, prob_hi[1]);
- compute_min_max(prob_hi[0], 0.0, prob_hi[1]);
+ compute_min_max(prob_lo[0], 0.0, prob_lo[1]);
+ compute_min_max(prob_hi[0], 0.0, prob_lo[1]);
+ compute_min_max(prob_lo[0], 0.0, prob_hi[1]);
+ compute_min_max(prob_hi[0], 0.0, prob_hi[1]);
#endif
}
@@ -272,22 +353,22 @@ LaserParticleContainer::InitData (int lev)
const Box& bx = plane_ba[i];
for (IntVect cell = bx.smallEnd(); cell <= bx.bigEnd(); bx.next(cell))
{
- const Vector<Real>& pos = Transform(cell[0], cell[1]);
+ const Vector<Real>& pos = Transform(cell[0], cell[1]);
#if (AMREX_SPACEDIM == 3)
- const Real* x = pos.dataPtr();
+ const Real* x = pos.dataPtr();
#else
- const Real x[2] = {pos[0], pos[2]};
+ const Real x[2] = {pos[0], pos[2]};
#endif
- if (prob_domain.contains(x))
- {
- for (int k = 0; k<2; ++k) {
- particle_x.push_back(pos[0]);
- particle_y.push_back(pos[1]);
- particle_z.push_back(pos[2]);
- }
- particle_w.push_back( weight);
- particle_w.push_back(-weight);
- }
+ if (laser_injection_box.contains(x))
+ {
+ for (int k = 0; k<2; ++k) {
+ particle_x.push_back(pos[0]);
+ particle_y.push_back(pos[1]);
+ particle_z.push_back(pos[2]);
+ }
+ particle_w.push_back( weight);
+ particle_w.push_back(-weight);
+ }
}
}
}
@@ -299,15 +380,15 @@ LaserParticleContainer::InitData (int lev)
if (Verbose()) amrex::Print() << "Adding laser particles\n";
AddNParticles(lev,
np, particle_x.dataPtr(), particle_y.dataPtr(), particle_z.dataPtr(),
- particle_ux.dataPtr(), particle_uy.dataPtr(), particle_uz.dataPtr(),
- 1, particle_w.dataPtr(), 1);
+ particle_ux.dataPtr(), particle_uy.dataPtr(), particle_uz.dataPtr(),
+ 1, particle_w.dataPtr(), 1);
}
void
LaserParticleContainer::Evolve (int lev,
- const MultiFab&, const MultiFab&, const MultiFab&,
- const MultiFab&, const MultiFab&, const MultiFab&,
- MultiFab& jx, MultiFab& jy, MultiFab& jz,
+ const MultiFab&, const MultiFab&, const MultiFab&,
+ const MultiFab&, const MultiFab&, const MultiFab&,
+ MultiFab& jx, MultiFab& jy, MultiFab& jz,
MultiFab* cjx, MultiFab* cjy, MultiFab* cjz,
MultiFab* rho, MultiFab* crho,
const MultiFab*, const MultiFab*, const MultiFab*,
@@ -337,19 +418,17 @@ LaserParticleContainer::Evolve (int lev,
#endif
{
#ifdef _OPENMP
- int thread_num = omp_get_thread_num();
+ int thread_num = omp_get_thread_num();
#else
- int thread_num = 0;
+ int thread_num = 0;
#endif
Cuda::ManagedDeviceVector<Real> plane_Xp, plane_Yp, amplitude_E;
for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
- {
+ {
Real wt = amrex::second();
- const Box& box = pti.validbox();
-
auto& attribs = pti.GetAttribs();
auto& wp = attribs[PIdx::w ];
@@ -357,80 +436,80 @@ LaserParticleContainer::Evolve (int lev,
auto& uyp = attribs[PIdx::uy];
auto& uzp = attribs[PIdx::uz];
- const long np = pti.numParticles();
+ const long np = pti.numParticles();
// For now, laser particles do not take the current buffers into account
const long np_current = np;
m_giv[thread_num].resize(np);
- plane_Xp.resize(np);
- plane_Yp.resize(np);
+ plane_Xp.resize(np);
+ plane_Yp.resize(np);
amplitude_E.resize(np);
- //
- // copy data from particle container to temp arrays
- //
- BL_PROFILE_VAR_START(blp_copy);
+ //
+ // copy data from particle container to temp arrays
+ //
+ BL_PROFILE_VAR_START(blp_copy);
pti.GetPosition(m_xp[thread_num], m_yp[thread_num], m_zp[thread_num]);
- BL_PROFILE_VAR_STOP(blp_copy);
+ BL_PROFILE_VAR_STOP(blp_copy);
if (rho) DepositCharge(pti, wp, rho, crho, 0, np_current, np, thread_num, lev);
- //
- // Particle Push
- //
- BL_PROFILE_VAR_START(blp_pxr_pp);
+ //
+ // Particle Push
+ //
+ BL_PROFILE_VAR_START(blp_pxr_pp);
// Find the coordinates of the particles in the emission plane
calculate_laser_plane_coordinates( &np,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- plane_Xp.dataPtr(), plane_Yp.dataPtr(),
- &u_X[0], &u_X[1], &u_X[2], &u_Y[0], &u_Y[1], &u_Y[2],
- &position[0], &position[1], &position[2] );
- // Calculate the laser amplitude to be emitted,
- // at the position of the emission plane
- if (profile == laser_t::Gaussian) {
- warpx_gaussian_laser( &np, plane_Xp.dataPtr(), plane_Yp.dataPtr(),
- &t_lab, &wavelength, &e_max, &profile_waist, &profile_duration,
- &profile_t_peak, &profile_focal_distance, amplitude_E.dataPtr(),
- &zeta, &beta, &phi2, &theta_stc );
- }
+ m_xp[thread_num].dataPtr(),
+ m_yp[thread_num].dataPtr(),
+ m_zp[thread_num].dataPtr(),
+ plane_Xp.dataPtr(), plane_Yp.dataPtr(),
+ &u_X[0], &u_X[1], &u_X[2], &u_Y[0], &u_Y[1], &u_Y[2],
+ &position[0], &position[1], &position[2] );
+ // Calculate the laser amplitude to be emitted,
+ // at the position of the emission plane
+ if (profile == laser_t::Gaussian) {
+ warpx_gaussian_laser( &np, plane_Xp.dataPtr(), plane_Yp.dataPtr(),
+ &t_lab, &wavelength, &e_max, &profile_waist, &profile_duration,
+ &profile_t_peak, &profile_focal_distance, amplitude_E.dataPtr(),
+ &zeta, &beta, &phi2, &theta_stc );
+ }
if (profile == laser_t::Harris) {
- warpx_harris_laser( &np, plane_Xp.dataPtr(), plane_Yp.dataPtr(),
+ warpx_harris_laser( &np, plane_Xp.dataPtr(), plane_Yp.dataPtr(),
&t, &wavelength, &e_max, &profile_waist, &profile_duration,
&profile_focal_distance, amplitude_E.dataPtr() );
- }
+ }
if (profile == laser_t::parse_field_function) {
for (int i = 0; i < np; ++i) {
amplitude_E[i] = parser.eval(plane_Xp[i], plane_Yp[i], t);
}
- }
- // Calculate the corresponding momentum and position for the particles
+ }
+ // Calculate the corresponding momentum and position for the particles
update_laser_particle(
- &np,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
- m_giv[thread_num].dataPtr(),
- wp.dataPtr(), amplitude_E.dataPtr(), &p_X[0], &p_X[1], &p_X[2],
- &nvec[0], &nvec[1], &nvec[2], &mobility, &dt,
- &PhysConst::c, &WarpX::beta_boost, &WarpX::gamma_boost );
- BL_PROFILE_VAR_STOP(blp_pxr_pp);
-
- //
- // Current Deposition
- //
+ &np,
+ m_xp[thread_num].dataPtr(),
+ m_yp[thread_num].dataPtr(),
+ m_zp[thread_num].dataPtr(),
+ uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
+ m_giv[thread_num].dataPtr(),
+ wp.dataPtr(), amplitude_E.dataPtr(), &p_X[0], &p_X[1], &p_X[2],
+ &nvec[0], &nvec[1], &nvec[2], &mobility, &dt,
+ &PhysConst::c, &WarpX::beta_boost, &WarpX::gamma_boost );
+ BL_PROFILE_VAR_STOP(blp_pxr_pp);
+
+ //
+ // Current Deposition
+ //
DepositCurrent(pti, wp, uxp, uyp, uzp, jx, jy, jz,
cjx, cjy, cjz, np_current, np, thread_num, lev, dt);
- //
- // copy particle data back
- //
- BL_PROFILE_VAR_START(blp_copy);
+ //
+ // copy particle data back
+ //
+ BL_PROFILE_VAR_START(blp_copy);
pti.SetPosition(m_xp[thread_num], m_yp[thread_num], m_zp[thread_num]);
BL_PROFILE_VAR_STOP(blp_copy);
@@ -445,7 +524,7 @@ LaserParticleContainer::Evolve (int lev,
costfab->plus(wt, work_box);
});
}
- }
+ }
}
}
@@ -466,14 +545,14 @@ LaserParticleContainer::ComputeSpacing (int lev, Real& Sx, Real& Sy) const
const Real eps = dx[0]*1.e-50;
#if (AMREX_SPACEDIM == 3)
Sx = std::min(std::min(dx[0]/(std::abs(u_X[0])+eps),
- dx[1]/(std::abs(u_X[1])+eps)),
- dx[2]/(std::abs(u_X[2])+eps));
+ dx[1]/(std::abs(u_X[1])+eps)),
+ dx[2]/(std::abs(u_X[2])+eps));
Sy = std::min(std::min(dx[0]/(std::abs(u_Y[0])+eps),
- dx[1]/(std::abs(u_Y[1])+eps)),
- dx[2]/(std::abs(u_Y[2])+eps));
+ dx[1]/(std::abs(u_Y[1])+eps)),
+ dx[2]/(std::abs(u_Y[2])+eps));
#else
Sx = std::min(dx[0]/(std::abs(u_X[0])+eps),
- dx[2]/(std::abs(u_X[2])+eps));
+ dx[2]/(std::abs(u_X[2])+eps));
Sy = 1.0;
#endif
}
diff --git a/Source/Make.WarpX b/Source/Make.WarpX
index 926523d82..c1ef54c33 100644
--- a/Source/Make.WarpX
+++ b/Source/Make.WarpX
@@ -41,7 +41,7 @@ endif
CFLAGS += -fPIC
FFLAGS += -fPIC
F90FLAGS += -fPIC
- USERSuffix = .Lib
+ USERSuffix := .Lib
DEFINES += -DWARPX_USE_PY
endif
@@ -107,7 +107,7 @@ ifeq ($(USE_PSATD),TRUE)
INCLUDE_LOCATIONS += $(FFTW_HOME)/include
LIBRARY_LOCATIONS += $(FFTW_HOME)/lib
endif
- USERSuffix += .PSATD
+ USERSuffix := $(USERSuffix).PSATD
DEFINES += -DWARPX_USE_PSATD
ifeq ($(USE_CUDA),TRUE)
DEFINES += -DFFTW -DCUDA_FFT=1 # PICSAR uses it
@@ -119,14 +119,10 @@ ifeq ($(USE_PSATD),TRUE)
endif
ifeq ($(USE_RZ),TRUE)
- USERSuffix += .RZ
+ USERSuffix := $(USERSuffix).RZ
DEFINES += -DWARPX_RZ
endif
-ifeq ($(STORE_OLD_PARTICLE_ATTRIBS),TRUE)
- DEFINES += -DWARPX_STORE_OLD_PARTICLE_ATTRIBS
-endif
-
ifeq ($(DO_ELECTROSTATIC),TRUE)
include $(AMREX_HOME)/Src/LinearSolvers/C_to_F_MG/Make.package
include $(AMREX_HOME)/Src/LinearSolvers/F_MG/FParallelMG.mak
@@ -158,17 +154,23 @@ else
SHARED_OPTION = -shared
endif
-installwarpx: libwarpx$(DIM)d.so
- mv libwarpx$(DIM)d.so Python/pywarpx
- cd Python; python setup.py install --with-libwarpx $(DIM) $(PYINSTALLOPTIONS)
+ifeq ($(USE_RZ),TRUE)
+ PYDIM = rz
+else
+ PYDIM = $(DIM)d
+endif
+
+installwarpx: libwarpx$(PYDIM).so
+ mv libwarpx$(PYDIM).so Python/pywarpx
+ cd Python; python setup.py install --with-libwarpx $(PYDIM) $(PYINSTALLOPTIONS)
-libwarpx$(DIM)d.a: $(objForExecs)
+libwarpx$(PYDIM).a: $(objForExecs)
@echo Making static library $@ ...
$(SILENT) $(AR) -crv $@ $^
$(SILENT) $(RM) AMReX_buildInfo.cpp
@echo SUCCESS
-libwarpx$(DIM)d.so: $(objForExecs)
+libwarpx$(PYDIM).so: $(objForExecs)
@echo Making dynamic library $@ ...
$(SILENT) $(CXX) $(SHARED_OPTION) -fPIC -o $@ $^ $(LDFLAGS) $(libraries)
$(SILENT) $(RM) AMReX_buildInfo.cpp
diff --git a/Source/Parallelization/Make.package b/Source/Parallelization/Make.package
index cbb1b5234..3d1fcf1da 100644
--- a/Source/Parallelization/Make.package
+++ b/Source/Parallelization/Make.package
@@ -1,5 +1,6 @@
CEXE_sources += WarpXComm.cpp
CEXE_sources += WarpXRegrid.cpp
+CEXE_headers += WarpXSumGuardCells.H
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Parallelization
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Parallelization
diff --git a/Source/Parallelization/WarpXComm.cpp b/Source/Parallelization/WarpXComm.cpp
index 28971eb0c..00dcb85d0 100644
--- a/Source/Parallelization/WarpXComm.cpp
+++ b/Source/Parallelization/WarpXComm.cpp
@@ -1,5 +1,6 @@
#include <WarpX.H>
#include <WarpX_f.H>
+#include <WarpXSumGuardCells.H>
#include <AMReX_FillPatchUtil_F.H>
@@ -78,7 +79,7 @@ WarpX::UpdateAuxilaryData ()
MultiFab::Subtract(dBz, *Bfield_cp[lev][2], 0, 0, 1, ng);
const Real* dx = Geom(lev-1).CellSize();
- const int ref_ratio = refRatio(lev-1)[0];
+ const int refinement_ratio = refRatio(lev-1)[0];
#ifdef _OPENMP
#pragma omp parallel
#endif
@@ -88,7 +89,7 @@ WarpX::UpdateAuxilaryData ()
{
Box ccbx = mfi.fabbox();
ccbx.enclosedCells();
- ccbx.coarsen(ref_ratio).refine(ref_ratio); // so that ccbx is coarsenable
+ ccbx.coarsen(refinement_ratio).refine(refinement_ratio); // so that ccbx is coarsenable
const FArrayBox& cxfab = dBx[mfi];
const FArrayBox& cyfab = dBy[mfi];
@@ -105,18 +106,18 @@ WarpX::UpdateAuxilaryData ()
BL_TO_FORTRAN_ANYD(cxfab),
BL_TO_FORTRAN_ANYD(cyfab),
BL_TO_FORTRAN_ANYD(czfab),
- dx, &ref_ratio,&use_limiter);
+ dx, &refinement_ratio,&use_limiter);
#else
amrex_interp_div_free_bfield(ccbx.loVect(), ccbx.hiVect(),
BL_TO_FORTRAN_ANYD(bfab[0]),
BL_TO_FORTRAN_ANYD(bfab[2]),
BL_TO_FORTRAN_ANYD(cxfab),
BL_TO_FORTRAN_ANYD(czfab),
- dx, &ref_ratio,&use_limiter);
+ dx, &refinement_ratio,&use_limiter);
amrex_interp_cc_bfield(ccbx.loVect(), ccbx.hiVect(),
BL_TO_FORTRAN_ANYD(bfab[1]),
BL_TO_FORTRAN_ANYD(cyfab),
- &ref_ratio,&use_limiter);
+ &refinement_ratio,&use_limiter);
#endif
for (int idim = 0; idim < 3; ++idim)
@@ -152,7 +153,7 @@ WarpX::UpdateAuxilaryData ()
MultiFab::Subtract(dEy, *Efield_cp[lev][1], 0, 0, 1, ng);
MultiFab::Subtract(dEz, *Efield_cp[lev][2], 0, 0, 1, ng);
- const int ref_ratio = refRatio(lev-1)[0];
+ const int refinement_ratio = refRatio(lev-1)[0];
#ifdef _OPEMP
#pragma omp parallel
#endif
@@ -162,7 +163,7 @@ WarpX::UpdateAuxilaryData ()
{
Box ccbx = mfi.fabbox();
ccbx.enclosedCells();
- ccbx.coarsen(ref_ratio).refine(ref_ratio); // so that ccbx is coarsenable
+ ccbx.coarsen(refinement_ratio).refine(refinement_ratio); // so that ccbx is coarsenable
const FArrayBox& cxfab = dEx[mfi];
const FArrayBox& cyfab = dEy[mfi];
@@ -179,18 +180,18 @@ WarpX::UpdateAuxilaryData ()
BL_TO_FORTRAN_ANYD(cxfab),
BL_TO_FORTRAN_ANYD(cyfab),
BL_TO_FORTRAN_ANYD(czfab),
- &ref_ratio,&use_limiter);
+ &refinement_ratio,&use_limiter);
#else
amrex_interp_efield(ccbx.loVect(), ccbx.hiVect(),
BL_TO_FORTRAN_ANYD(efab[0]),
BL_TO_FORTRAN_ANYD(efab[2]),
BL_TO_FORTRAN_ANYD(cxfab),
BL_TO_FORTRAN_ANYD(czfab),
- &ref_ratio,&use_limiter);
+ &refinement_ratio,&use_limiter);
amrex_interp_nd_efield(ccbx.loVect(), ccbx.hiVect(),
BL_TO_FORTRAN_ANYD(efab[1]),
BL_TO_FORTRAN_ANYD(cyfab),
- &ref_ratio);
+ &refinement_ratio);
#endif
for (int idim = 0; idim < 3; ++idim)
@@ -245,7 +246,7 @@ void
WarpX::FillBoundaryE (int lev, PatchType patch_type)
{
if (patch_type == PatchType::fine)
- {
+ {
if (do_pml && pml[lev]->ok())
{
pml[lev]->ExchangeE(patch_type,
@@ -355,14 +356,15 @@ WarpX::SyncCurrent ()
{
BL_PROFILE("SyncCurrent()");
- // Restrict fine patch current onto the coarse patch, before fine patch SumBoundary
+ // Restrict fine patch current onto the coarse patch, before
+ // summing the guard cells of the fine patch
for (int lev = 1; lev <= finest_level; ++lev)
{
current_cp[lev][0]->setVal(0.0);
current_cp[lev][1]->setVal(0.0);
current_cp[lev][2]->setVal(0.0);
- const IntVect& ref_ratio = refRatio(lev-1);
+ const IntVect& refinement_ratio = refRatio(lev-1);
std::array<const MultiFab*,3> fine { current_fp[lev][0].get(),
current_fp[lev][1].get(),
@@ -370,7 +372,7 @@ WarpX::SyncCurrent ()
std::array< MultiFab*,3> crse { current_cp[lev][0].get(),
current_cp[lev][1].get(),
current_cp[lev][2].get() };
- SyncCurrent(fine, crse, ref_ratio[0]);
+ SyncCurrent(fine, crse, refinement_ratio[0]);
}
Vector<Array<std::unique_ptr<MultiFab>,3> > j_fp(finest_level+1);
@@ -391,8 +393,9 @@ WarpX::SyncCurrent ()
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.
+ // At this point, current_fp may have false values close to the
+ // edges of each FAB. This will be solved with when summing
+ // the guard cells later.
// j_fp contains the exact MultiFab current_fp before this step.
}
}
@@ -427,11 +430,11 @@ WarpX::SyncCurrent ()
{
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
+ // 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);
+ WarpXSumGuardCells(*(current_fp[lev][0]),period);
+ WarpXSumGuardCells(*(current_fp[lev][1]),period);
+ WarpXSumGuardCells(*(current_fp[lev][2]),period);
}
// Add fine level's coarse patch to coarse level's fine patch
@@ -461,9 +464,9 @@ WarpX::SyncCurrent ()
for (int lev = 1; lev <= finest_level; ++lev)
{
const auto& cperiod = Geom(lev-1).periodicity();
- current_cp[lev][0]->SumBoundary(cperiod);
- current_cp[lev][1]->SumBoundary(cperiod);
- current_cp[lev][2]->SumBoundary(cperiod);
+ WarpXSumGuardCells(*(current_cp[lev][0]),cperiod);
+ WarpXSumGuardCells(*(current_cp[lev][1]),cperiod);
+ WarpXSumGuardCells(*(current_cp[lev][2]),cperiod);
}
if (WarpX::use_filter) {
@@ -476,7 +479,7 @@ WarpX::SyncCurrent ()
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
+ // current_fp has right number of ghost cells and
// correct filtered values here.
}
}
@@ -521,10 +524,10 @@ WarpX::SyncCurrent ()
void
WarpX::SyncCurrent (const std::array<const amrex::MultiFab*,3>& fine,
const std::array< amrex::MultiFab*,3>& crse,
- int ref_ratio)
+ int refinement_ratio)
{
- BL_ASSERT(ref_ratio == 2);
- const IntVect& ng = (fine[0]->nGrowVect() + 1) /ref_ratio;
+ BL_ASSERT(refinement_ratio == 2);
+ const IntVect& ng = (fine[0]->nGrowVect() + 1) /refinement_ratio;
#ifdef _OPEMP
#pragma omp parallel
@@ -536,7 +539,7 @@ WarpX::SyncCurrent (const std::array<const amrex::MultiFab*,3>& fine,
for (MFIter mfi(*crse[idim],true); mfi.isValid(); ++mfi)
{
const Box& bx = mfi.growntilebox(ng);
- Box fbx = amrex::grow(amrex::refine(bx,ref_ratio),1);
+ Box fbx = amrex::grow(amrex::refine(bx,refinement_ratio),1);
ffab.resize(fbx);
fbx &= (*fine[idim])[mfi].box();
ffab.setVal(0.0);
@@ -556,12 +559,13 @@ WarpX::SyncRho (amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rhof,
{
if (!rhof[0]) return;
- // Restrict fine patch onto the coarse patch, before fine patch SumBoundary
+ // Restrict fine patch onto the coarse patch,
+ // before summing the guard cells of the fine patch
for (int lev = 1; lev <= finest_level; ++lev)
{
rhoc[lev]->setVal(0.0);
- const IntVect& ref_ratio = refRatio(lev-1);
- SyncRho(*rhof[lev], *rhoc[lev], ref_ratio[0]);
+ const IntVect& refinement_ratio = refRatio(lev-1);
+ SyncRho(*rhof[lev], *rhoc[lev], refinement_ratio[0]);
}
Vector<std::unique_ptr<MultiFab> > rho_f_g(finest_level+1);
@@ -607,7 +611,7 @@ WarpX::SyncRho (amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rhof,
for (int lev = 0; lev <= finest_level; ++lev)
{
const auto& period = Geom(lev).periodicity();
- rhof[lev]->SumBoundary(period);
+ WarpXSumGuardCells( *(rhof[lev]), period, 0, rhof[lev]->nComp() );
}
// Add fine level's coarse patch to coarse level's fine patch
@@ -631,7 +635,7 @@ WarpX::SyncRho (amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rhof,
for (int lev = 1; lev <= finest_level; ++lev)
{
const auto& cperiod = Geom(lev-1).periodicity();
- rhoc[lev]->SumBoundary(cperiod);
+ WarpXSumGuardCells( *(rhoc[lev]), cperiod, 0, rhoc[lev]->nComp() );
}
if (WarpX::use_filter) {
@@ -669,10 +673,10 @@ WarpX::SyncRho (amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rhof,
* averaging the values of the charge density of the fine patch (on the same level).
*/
void
-WarpX::SyncRho (const MultiFab& fine, MultiFab& crse, int ref_ratio)
+WarpX::SyncRho (const MultiFab& fine, MultiFab& crse, int refinement_ratio)
{
- BL_ASSERT(ref_ratio == 2);
- const IntVect& ng = (fine.nGrowVect()+1)/ref_ratio;
+ BL_ASSERT(refinement_ratio == 2);
+ const IntVect& ng = (fine.nGrowVect()+1)/refinement_ratio;
const int nc = fine.nComp();
#ifdef _OPEMP
@@ -683,7 +687,7 @@ WarpX::SyncRho (const MultiFab& fine, MultiFab& crse, int ref_ratio)
for (MFIter mfi(crse,true); mfi.isValid(); ++mfi)
{
const Box& bx = mfi.growntilebox(ng);
- Box fbx = amrex::grow(amrex::refine(bx,ref_ratio),1);
+ Box fbx = amrex::grow(amrex::refine(bx,refinement_ratio),1);
ffab.resize(fbx, nc);
fbx &= fine[mfi].box();
ffab.setVal(0.0);
@@ -706,7 +710,7 @@ WarpX::RestrictCurrentFromFineToCoarsePatch (int lev)
current_cp[lev][1]->setVal(0.0);
current_cp[lev][2]->setVal(0.0);
- const IntVect& ref_ratio = refRatio(lev-1);
+ const IntVect& refinement_ratio = refRatio(lev-1);
std::array<const MultiFab*,3> fine { current_fp[lev][0].get(),
current_fp[lev][1].get(),
@@ -714,7 +718,7 @@ WarpX::RestrictCurrentFromFineToCoarsePatch (int lev)
std::array< MultiFab*,3> crse { current_cp[lev][0].get(),
current_cp[lev][1].get(),
current_cp[lev][2].get() };
- SyncCurrent(fine, crse, ref_ratio[0]);
+ SyncCurrent(fine, crse, refinement_ratio[0]);
}
void
@@ -729,10 +733,9 @@ WarpX::ApplyFilterandSumBoundaryJ (int lev, PatchType patch_type)
ng += bilinear_filter.stencil_length_each_dir-1;
MultiFab jf(j[idim]->boxArray(), j[idim]->DistributionMap(), 1, ng);
bilinear_filter.ApplyStencil(jf, *j[idim]);
- jf.SumBoundary(period);
- MultiFab::Copy(*j[idim], jf, 0, 0, 1, 0);
+ WarpXSumGuardCells(*(j[idim]), jf, period);
} else {
- j[idim]->SumBoundary(period);
+ WarpXSumGuardCells(*(j[idim]), period);
}
}
}
@@ -780,8 +783,7 @@ WarpX::AddCurrentFromFineLevelandSumBoundary (int lev)
MultiFab::Add(jfb, jfc, 0, 0, 1, ng);
mf.ParallelAdd(jfb, 0, 0, 1, ng, IntVect::TheZeroVector(), period);
- jfc.SumBoundary(period);
- MultiFab::Copy(*current_cp[lev+1][idim], jfc, 0, 0, 1, 0);
+ WarpXSumGuardCells(*current_cp[lev+1][idim], jfc, period);
}
else if (use_filter) // but no buffer
{
@@ -792,8 +794,7 @@ WarpX::AddCurrentFromFineLevelandSumBoundary (int lev)
current_cp[lev+1][idim]->DistributionMap(), 1, ng);
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);
+ WarpXSumGuardCells(*current_cp[lev+1][idim], jf, period);
}
else if (current_buf[lev+1][idim]) // but no filter
{
@@ -803,14 +804,14 @@ WarpX::AddCurrentFromFineLevelandSumBoundary (int lev)
mf.ParallelAdd(*current_buf[lev+1][idim], 0, 0, 1,
current_buf[lev+1][idim]->nGrowVect(), IntVect::TheZeroVector(),
period);
- current_cp[lev+1][idim]->SumBoundary(period);
+ WarpXSumGuardCells(*(current_cp[lev+1][idim]), period);
}
else // no filter, no buffer
{
mf.ParallelAdd(*current_cp[lev+1][idim], 0, 0, 1,
current_cp[lev+1][idim]->nGrowVect(), IntVect::TheZeroVector(),
period);
- current_cp[lev+1][idim]->SumBoundary(period);
+ WarpXSumGuardCells(*(current_cp[lev+1][idim]), period);
}
MultiFab::Add(*current_fp[lev][idim], mf, 0, 0, 1, 0);
}
@@ -823,8 +824,8 @@ WarpX::RestrictRhoFromFineToCoarsePatch (int lev)
{
if (rho_fp[lev]) {
rho_cp[lev]->setVal(0.0);
- const IntVect& ref_ratio = refRatio(lev-1);
- SyncRho(*rho_fp[lev], *rho_cp[lev], ref_ratio[0]);
+ const IntVect& refinement_ratio = refRatio(lev-1);
+ SyncRho(*rho_fp[lev], *rho_cp[lev], refinement_ratio[0]);
}
}
@@ -840,10 +841,9 @@ WarpX::ApplyFilterandSumBoundaryRho (int lev, PatchType patch_type, int icomp, i
ng += bilinear_filter.stencil_length_each_dir-1;
MultiFab rf(r->boxArray(), r->DistributionMap(), ncomp, ng);
bilinear_filter.ApplyStencil(rf, *r, icomp, 0, ncomp);
- rf.SumBoundary(period);
- MultiFab::Copy(*r, rf, 0, icomp, ncomp, 0);
+ WarpXSumGuardCells(*r, rf, period, icomp, ncomp );
} else {
- r->SumBoundary(icomp, ncomp, period);
+ WarpXSumGuardCells(*r, period, icomp, ncomp);
}
}
@@ -885,9 +885,7 @@ WarpX::AddRhoFromFineLevelandSumBoundary(int lev, int icomp, int ncomp)
MultiFab::Add(rhofb, rhofc, 0, 0, ncomp, ng);
mf.ParallelAdd(rhofb, 0, 0, ncomp, ng, IntVect::TheZeroVector(), period);
-
- rhofc.SumBoundary(period);
- MultiFab::Copy(*rho_cp[lev+1], rhofc, 0, 0, ncomp, 0);
+ WarpXSumGuardCells( *rho_cp[lev+1], rhofc, period, icomp, ncomp );
}
else if (use_filter) // but no buffer
{
@@ -896,8 +894,7 @@ WarpX::AddRhoFromFineLevelandSumBoundary(int lev, int icomp, int ncomp)
MultiFab rf(rho_cp[lev+1]->boxArray(), rho_cp[lev+1]->DistributionMap(), ncomp, ng);
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);
+ WarpXSumGuardCells( *rho_cp[lev+1], rf, period, icomp, ncomp );
}
else if (charge_buf[lev+1]) // but no filter
{
@@ -908,14 +905,14 @@ WarpX::AddRhoFromFineLevelandSumBoundary(int lev, int icomp, int ncomp)
ncomp,
charge_buf[lev+1]->nGrowVect(), IntVect::TheZeroVector(),
period);
- rho_cp[lev+1]->SumBoundary(icomp, ncomp, period);
+ WarpXSumGuardCells(*(rho_cp[lev+1]), period, icomp, ncomp);
}
else // no filter, no buffer
{
mf.ParallelAdd(*rho_cp[lev+1], icomp, 0, ncomp,
rho_cp[lev+1]->nGrowVect(), IntVect::TheZeroVector(),
period);
- rho_cp[lev+1]->SumBoundary(icomp, ncomp, period);
+ WarpXSumGuardCells(*(rho_cp[lev+1]), period, icomp, ncomp);
}
ApplyFilterandSumBoundaryRho(lev, PatchType::fine, icomp, ncomp);
MultiFab::Add(*rho_fp[lev], mf, 0, icomp, ncomp, 0);
diff --git a/Source/Parallelization/WarpXSumGuardCells.H b/Source/Parallelization/WarpXSumGuardCells.H
new file mode 100644
index 000000000..24ad1b80f
--- /dev/null
+++ b/Source/Parallelization/WarpXSumGuardCells.H
@@ -0,0 +1,61 @@
+#ifndef WARPX_SUM_GUARD_CELLS_H_
+#define WARPX_SUM_GUARD_CELLS_H_
+
+#include <AMReX_MultiFab.H>
+
+/* \brief Sum the values of `mf`, where the different boxes overlap
+ * (i.e. in the guard cells)
+ *
+ * This is typically called for the sources of the Maxwell equations (J/rho)
+ * after deposition from the macroparticles.
+ *
+ * - When WarpX is compiled with a finite-difference scheme: this only
+ * updates the *valid* cells of `mf`
+ * - When WarpX is compiled with a spectral scheme (WARPX_USE_PSATD): this
+ * updates both the *valid* cells and *guard* cells. (This is because a
+ * spectral solver requires the value of the sources over a large stencil.)
+ */
+void
+WarpXSumGuardCells(amrex::MultiFab& mf, const amrex::Periodicity& period,
+ const int icomp=0, const int ncomp=1){
+#ifdef WARPX_USE_PSATD
+ // Update both valid cells and guard cells
+ const amrex::IntVect n_updated_guards = mf.nGrowVect();
+#else
+ // Update only the valid cells
+ const amrex::IntVect n_updated_guards = amrex::IntVect::TheZeroVector();
+#endif
+ mf.SumBoundary(icomp, ncomp, n_updated_guards, period);
+}
+
+/* \brief Sum the values of `src` where the different boxes overlap
+ * (i.e. in the guard cells) and copy them into `dst`
+ *
+ * This is typically called for the sources of the Maxwell equations (J/rho)
+ * after deposition from the macroparticles + filtering.
+ *
+ * - When WarpX is compiled with a finite-difference scheme: this only
+ * updates the *valid* cells of `dst`
+ * - When WarpX is compiled with a spectral scheme (WARPX_USE_PSATD): this
+ * updates both the *valid* cells and *guard* cells. (This is because a
+ * spectral solver requires the value of the sources over a large stencil.)
+ *
+ * Note: `i_comp` is the component where the results will be stored in `dst`;
+ * The component from which we copy in `src` is always 0.
+ */
+void
+WarpXSumGuardCells(amrex::MultiFab& dst, amrex::MultiFab& src,
+ const amrex::Periodicity& period,
+ const int icomp=0, const int ncomp=1){
+#ifdef WARPX_USE_PSATD
+ // Update both valid cells and guard cells
+ const amrex::IntVect n_updated_guards = dst.nGrowVect();
+#else
+ // Update only the valid cells
+ const amrex::IntVect n_updated_guards = amrex::IntVect::TheZeroVector();
+#endif
+ src.SumBoundary(icomp, ncomp, n_updated_guards, period);
+ amrex::Copy( dst, src, 0, icomp, ncomp, n_updated_guards );
+}
+
+#endif // WARPX_SUM_GUARD_CELLS_H_
diff --git a/Source/Parser/WarpXParser.cpp b/Source/Parser/WarpXParser.cpp
index 8c800215f..3237086f2 100644
--- a/Source/Parser/WarpXParser.cpp
+++ b/Source/Parser/WarpXParser.cpp
@@ -1,4 +1,5 @@
+#include <algorithm>
#include "WarpXParser.H"
WarpXParser::WarpXParser (std::string const& func_body)
@@ -12,6 +13,8 @@ WarpXParser::define (std::string const& func_body)
clear();
m_expression = func_body;
+ m_expression.erase(std::remove(m_expression.begin(),m_expression.end(),'\n'),
+ m_expression.end());
std::string f = m_expression + "\n";
#ifdef _OPENMP
diff --git a/Source/Particles/Make.package b/Source/Particles/Make.package
index acbfe3390..f33095738 100644
--- a/Source/Particles/Make.package
+++ b/Source/Particles/Make.package
@@ -10,5 +10,7 @@ CEXE_headers += WarpXParticleContainer.H
CEXE_headers += RigidInjectedParticleContainer.H
CEXE_headers += PhysicalParticleContainer.H
+include $(WARPX_HOME)/Source/Particles/Pusher/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 b0968b0cc..869126fef 100644
--- a/Source/Particles/MultiParticleContainer.H
+++ b/Source/Particles/MultiParticleContainer.H
@@ -129,9 +129,7 @@ public:
void Checkpoint (const std::string& dir) const;
- void WritePlotFile( const std::string& dir,
- const amrex::Vector<int>& real_flags,
- const amrex::Vector<std::string>& real_names) const;
+ void WritePlotFile (const std::string& dir) const;
void Restart (const std::string& dir);
@@ -156,6 +154,10 @@ public:
int nSpecies() const {return nspecies;}
+ int nSpeciesBoostedFrameDiags() const {return nspecies_boosted_frame_diags;}
+ int mapSpeciesBoostedFrameDiags(int i) const {return map_species_boosted_frame_diags[i];}
+ int doBoostedFrameDiags() const {return do_boosted_frame_diags;}
+
int nSpeciesDepositOnMainGrid () const {
int r = 0;
for (int i : deposit_on_main_grid) {
@@ -169,17 +171,14 @@ public:
const amrex::Real z_old, const amrex::Real z_new,
const amrex::Real t_boost, const amrex::Real t_lab, const amrex::Real dt,
amrex::Vector<WarpXParticleContainer::DiagnosticParticleData>& parts) const;
-
- //
- // Parameters for the Cherenkov corrector in the FDTD solver.
- // Both stencils are calculated ar runtime.
- //
- // Number of coefficients for the stencil of the NCI corrector.
- // The stencil is applied in the z direction only.
- static constexpr int nstencilz_fdtd_nci_corr=5;
- amrex::Vector<amrex::Array<amrex::Real, nstencilz_fdtd_nci_corr> > fdtd_nci_stencilz_ex;
- amrex::Vector<amrex::Array<amrex::Real, nstencilz_fdtd_nci_corr> > fdtd_nci_stencilz_by;
+ // Inject particles during the simulation (for particles entering the
+ // simulation domain after some iterations, due to flowing plasma and/or
+ // moving window).
+ void ContinuousInjection(const amrex::RealBox& injection_box) const;
+ // Update injection position for continuously-injected species.
+ void UpdateContinuousInjectionPosition(amrex::Real dt) const;
+ int doContinuousInjection() const;
std::vector<std::string> GetSpeciesNames() const { return species_names; }
@@ -192,6 +191,8 @@ protected:
std::vector<std::string> species_names;
+ std::vector<std::string> lasers_names;
+
std::vector<int> deposit_on_main_grid;
std::vector<PCTypes> species_types;
@@ -205,7 +206,15 @@ private:
void ReadParameters ();
+ // Number of species dumped in BoostedFrameDiagnostics
+ int nspecies_boosted_frame_diags = 0;
+ // map_species_boosted_frame_diags[i] is the species ID in
+ // MultiParticleContainer for 0<i<nspecies_boosted_frame_diags
+ std::vector<int> map_species_boosted_frame_diags;
+ int do_boosted_frame_diags = 0;
+
// runtime parameters
- int nspecies = 1; // physical particles only. If WarpX::use_laser, nspecies+1 == allcontainers.size().
+ int nlasers = 0;
+ int nspecies = 1; // physical particles only. nspecies+nlasers == allcontainers.size().
};
#endif /*WARPX_ParticleContainer_H_*/
diff --git a/Source/Particles/MultiParticleContainer.cpp b/Source/Particles/MultiParticleContainer.cpp
index 1b644b543..9d39ec2f9 100644
--- a/Source/Particles/MultiParticleContainer.cpp
+++ b/Source/Particles/MultiParticleContainer.cpp
@@ -8,14 +8,11 @@
using namespace amrex;
-constexpr int MultiParticleContainer::nstencilz_fdtd_nci_corr;
-
MultiParticleContainer::MultiParticleContainer (AmrCore* amr_core)
{
ReadParameters();
- int n = WarpX::use_laser ? nspecies+1 : nspecies;
- allcontainers.resize(n);
+ allcontainers.resize(nspecies + nlasers);
for (int i = 0; i < nspecies; ++i) {
if (species_types[i] == PCTypes::Physical) {
allcontainers[i].reset(new PhysicalParticleContainer(amr_core, i, species_names[i]));
@@ -25,10 +22,46 @@ MultiParticleContainer::MultiParticleContainer (AmrCore* amr_core)
}
allcontainers[i]->deposit_on_main_grid = deposit_on_main_grid[i];
}
- if (WarpX::use_laser) {
- allcontainers[n-1].reset(new LaserParticleContainer(amr_core,n-1));
+
+ for (int i = nspecies; i < nspecies+nlasers; ++i) {
+ allcontainers[i].reset(new LaserParticleContainer(amr_core,i, lasers_names[i-nspecies]));
+ }
+
+ pc_tmp.reset(new PhysicalParticleContainer(amr_core));
+
+ // Compute the number of species for which lab-frame data is dumped
+ // nspecies_lab_frame_diags, and map their ID to MultiParticleContainer
+ // particle IDs in map_species_lab_diags.
+ map_species_boosted_frame_diags.resize(nspecies);
+ nspecies_boosted_frame_diags = 0;
+ for (int i=0; i<nspecies; i++){
+ auto& pc = allcontainers[i];
+ if (pc->do_boosted_frame_diags){
+ map_species_boosted_frame_diags[nspecies_boosted_frame_diags] = i;
+ do_boosted_frame_diags = 1;
+ nspecies_boosted_frame_diags += 1;
+ }
+ }
+
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ for (int i = 0; i < nspecies_boosted_frame_diags; ++i)
+ {
+ int is = map_species_boosted_frame_diags[i];
+ allcontainers[is]->AddRealComp("xold");
+ allcontainers[is]->AddRealComp("yold");
+ allcontainers[is]->AddRealComp("zold");
+ allcontainers[is]->AddRealComp("uxold");
+ allcontainers[is]->AddRealComp("uyold");
+ allcontainers[is]->AddRealComp("uzold");
+ }
+ pc_tmp->AddRealComp("xold");
+ pc_tmp->AddRealComp("yold");
+ pc_tmp->AddRealComp("zold");
+ pc_tmp->AddRealComp("uxold");
+ pc_tmp->AddRealComp("uyold");
+ pc_tmp->AddRealComp("uzold");
}
- pc_tmp.reset(new PhysicalParticleContainer(amr_core));
}
void
@@ -37,10 +70,10 @@ MultiParticleContainer::ReadParameters ()
static bool initialized = false;
if (!initialized)
{
- ParmParse pp("particles");
+ ParmParse pp("particles");
- pp.query("nspecies", nspecies);
- BL_ASSERT(nspecies >= 0);
+ pp.query("nspecies", nspecies);
+ BL_ASSERT(nspecies >= 0);
if (nspecies > 0) {
pp.getarr("species_names", species_names);
@@ -70,9 +103,19 @@ MultiParticleContainer::ReadParameters ()
}
}
}
- pp.query("use_fdtd_nci_corr", WarpX::use_fdtd_nci_corr);
- pp.query("l_lower_order_in_v", WarpX::l_lower_order_in_v);
- initialized = true;
+
+ pp.query("use_fdtd_nci_corr", WarpX::use_fdtd_nci_corr);
+ pp.query("l_lower_order_in_v", WarpX::l_lower_order_in_v);
+
+ ParmParse ppl("lasers");
+ ppl.query("nlasers", nlasers);
+ BL_ASSERT(nlasers >= 0);
+ if (nlasers > 0) {
+ ppl.getarr("names", lasers_names);
+ BL_ASSERT(lasers_names.size() == nlasers);
+ }
+
+ initialized = true;
}
}
@@ -80,7 +123,7 @@ void
MultiParticleContainer::AllocData ()
{
for (auto& pc : allcontainers) {
- pc->AllocData();
+ pc->AllocData();
}
pc_tmp->AllocData();
}
@@ -89,7 +132,7 @@ void
MultiParticleContainer::InitData ()
{
for (auto& pc : allcontainers) {
- pc->InitData();
+ pc->InitData();
}
pc_tmp->InitData();
}
@@ -101,7 +144,7 @@ MultiParticleContainer::FieldGatherES (const Vector<std::array<std::unique_ptr<M
const amrex::Vector<std::unique_ptr<amrex::FabArray<amrex::BaseFab<int> > > >& masks)
{
for (auto& pc : allcontainers) {
- pc->FieldGatherES(E, masks);
+ pc->FieldGatherES(E, masks);
}
}
@@ -119,7 +162,7 @@ MultiParticleContainer::EvolveES (const Vector<std::array<std::unique_ptr<MultiF
}
for (auto& pc : allcontainers) {
- pc->EvolveES(E, rho, t, dt);
+ pc->EvolveES(E, rho, t, dt);
}
for (unsigned i = 0; i < nlevs; i++) {
@@ -148,7 +191,7 @@ MultiParticleContainer::Evolve (int lev,
if (rho) rho->setVal(0.0);
for (auto& pc : allcontainers) {
pc->Evolve(lev, Ex, Ey, Ez, Bx, By, Bz, jx, jy, jz, cjx, cjy, cjz,
- rho, cEx, cEy, cEz, cBx, cBy, cBz, t, dt);
+ rho, cEx, cEy, cEz, cBx, cBy, cBz, t, dt);
}
}
@@ -156,7 +199,7 @@ void
MultiParticleContainer::PushXES (Real dt)
{
for (auto& pc : allcontainers) {
- pc->PushXES(dt);
+ pc->PushXES(dt);
}
}
@@ -172,7 +215,7 @@ DepositCharge (Vector<std::unique_ptr<MultiFab> >& rho, bool local)
}
for (unsigned i = 0, n = allcontainers.size(); i < n; ++i) {
- allcontainers[i]->DepositCharge(rho, true);
+ allcontainers[i]->DepositCharge(rho, true);
}
if (!local) {
@@ -201,7 +244,7 @@ MultiParticleContainer::FieldGather (int lev,
const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz)
{
for (auto& pc : allcontainers) {
- pc->FieldGather(lev, Ex, Ey, Ez, Bx, By, Bz);
+ pc->FieldGather(lev, Ex, Ey, Ez, Bx, By, Bz);
}
}
@@ -226,7 +269,7 @@ MultiParticleContainer::Evolve (int lev,
if (crho) crho->setVal(0.0);
for (auto& pc : allcontainers) {
pc->Evolve(lev, Ex, Ey, Ez, Bx, By, Bz, jx, jy, jz, cjx, cjy, cjz,
- rho, crho, cEx, cEy, cEz, cBx, cBy, cBz, t, dt);
+ rho, crho, cEx, cEy, cEz, cBx, cBy, cBz, t, dt);
}
}
@@ -234,7 +277,7 @@ void
MultiParticleContainer::PushX (Real dt)
{
for (auto& pc : allcontainers) {
- pc->PushX(dt);
+ pc->PushX(dt);
}
}
@@ -244,7 +287,7 @@ MultiParticleContainer::PushP (int lev, Real dt,
const MultiFab& Bx, const MultiFab& By, const MultiFab& Bz)
{
for (auto& pc : allcontainers) {
- pc->PushP(lev, dt, Ex, Ey, Ez, Bx, By, Bz);
+ pc->PushP(lev, dt, Ex, Ey, Ez, Bx, By, Bz);
}
}
@@ -253,12 +296,12 @@ MultiParticleContainer::GetChargeDensity (int lev, bool local)
{
std::unique_ptr<MultiFab> rho = allcontainers[0]->GetChargeDensity(lev, true);
for (unsigned i = 1, n = allcontainers.size(); i < n; ++i) {
- std::unique_ptr<MultiFab> rhoi = allcontainers[i]->GetChargeDensity(lev, true);
- MultiFab::Add(*rho, *rhoi, 0, 0, 1, rho->nGrow());
+ std::unique_ptr<MultiFab> rhoi = allcontainers[i]->GetChargeDensity(lev, true);
+ MultiFab::Add(*rho, *rhoi, 0, 0, 1, rho->nGrow());
}
if (!local) {
- const Geometry& gm = allcontainers[0]->Geom(lev);
- rho->SumBoundary(gm.periodicity());
+ const Geometry& gm = allcontainers[0]->Geom(lev);
+ rho->SumBoundary(gm.periodicity());
}
return rho;
}
@@ -267,7 +310,7 @@ void
MultiParticleContainer::SortParticlesByCell ()
{
for (auto& pc : allcontainers) {
- pc->SortParticlesByCell();
+ pc->SortParticlesByCell();
}
}
@@ -275,7 +318,7 @@ void
MultiParticleContainer::Redistribute ()
{
for (auto& pc : allcontainers) {
- pc->Redistribute();
+ pc->Redistribute();
}
}
@@ -283,7 +326,7 @@ void
MultiParticleContainer::RedistributeLocal (const int num_ghost)
{
for (auto& pc : allcontainers) {
- pc->Redistribute(0, 0, 0, num_ghost);
+ pc->Redistribute(0, 0, 0, num_ghost);
}
}
@@ -293,10 +336,10 @@ MultiParticleContainer::NumberOfParticlesInGrid(int lev) const
const bool only_valid=true, only_local=true;
Vector<long> r = allcontainers[0]->NumberOfParticlesInGrid(lev,only_valid,only_local);
for (unsigned i = 1, n = allcontainers.size(); i < n; ++i) {
- const auto& ri = allcontainers[i]->NumberOfParticlesInGrid(lev,only_valid,only_local);
- for (unsigned j=0, m=ri.size(); j<m; ++j) {
- r[j] += ri[j];
- }
+ const auto& ri = allcontainers[i]->NumberOfParticlesInGrid(lev,only_valid,only_local);
+ for (unsigned j=0, m=ri.size(); j<m; ++j) {
+ r[j] += ri[j];
+ }
}
ParallelDescriptor::ReduceLongSum(r.data(),r.size());
return r;
@@ -306,7 +349,7 @@ void
MultiParticleContainer::Increment (MultiFab& mf, int lev)
{
for (auto& pc : allcontainers) {
- pc->Increment(mf,lev);
+ pc->Increment(mf,lev);
}
}
@@ -314,7 +357,7 @@ void
MultiParticleContainer::SetParticleBoxArray (int lev, BoxArray& new_ba)
{
for (auto& pc : allcontainers) {
- pc->SetParticleBoxArray(lev,new_ba);
+ pc->SetParticleBoxArray(lev,new_ba);
}
}
@@ -322,7 +365,7 @@ void
MultiParticleContainer::SetParticleDistributionMap (int lev, DistributionMapping& new_dm)
{
for (auto& pc : allcontainers) {
- pc->SetParticleDistributionMap(lev,new_dm);
+ pc->SetParticleDistributionMap(lev,new_dm);
}
}
@@ -330,7 +373,7 @@ void
MultiParticleContainer::PostRestart ()
{
for (auto& pc : allcontainers) {
- pc->PostRestart();
+ pc->PostRestart();
}
pc_tmp->PostRestart();
}
@@ -346,16 +389,25 @@ MultiParticleContainer
BL_PROFILE("MultiParticleContainer::GetLabFrameData");
- for (int i = 0; i < nspecies; ++i)
- {
- WarpXParticleContainer* pc = allcontainers[i].get();
+ // Loop over particle species
+ for (int i = 0; i < nspecies_boosted_frame_diags; ++i){
+ int isp = map_species_boosted_frame_diags[i];
+ WarpXParticleContainer* pc = allcontainers[isp].get();
WarpXParticleContainer::DiagnosticParticles diagnostic_particles;
pc->GetParticleSlice(direction, z_old, z_new, t_boost, t_lab, dt, diagnostic_particles);
-
- for (int lev = 0; lev <= pc->finestLevel(); ++lev)
- {
- for (auto it = diagnostic_particles[lev].begin(); it != diagnostic_particles[lev].end(); ++it)
- {
+ // Here, diagnostic_particles[lev][index] is a WarpXParticleContainer::DiagnosticParticleData
+ // where "lev" is the AMR level and "index" is a [grid index][tile index] pair.
+
+ // Loop over AMR levels
+ for (int lev = 0; lev <= pc->finestLevel(); ++lev){
+ // Loop over [grid index][tile index] pairs
+ // and Fills parts[species number i] with particle data from all grids and
+ // tiles in diagnostic_particles. parts contains particles from all
+ // AMR levels indistinctly.
+ for (auto it = diagnostic_particles[lev].begin(); it != diagnostic_particles[lev].end(); ++it){
+ // it->first is the [grid index][tile index] key
+ // it->second is the corresponding
+ // WarpXParticleContainer::DiagnosticParticleData value
parts[i].GetRealData(DiagIdx::w).insert( parts[i].GetRealData(DiagIdx::w ).end(),
it->second.GetRealData(DiagIdx::w ).begin(),
it->second.GetRealData(DiagIdx::w ).end());
@@ -387,3 +439,48 @@ MultiParticleContainer
}
}
}
+
+/* \brief Continuous injection for particles initially outside of the domain.
+ * \param injection_box: Domain where new particles should be injected.
+ * Loop over all WarpXParticleContainer in MultiParticleContainer and
+ * calls virtual function ContinuousInjection.
+ */
+void
+MultiParticleContainer::ContinuousInjection(const RealBox& injection_box) const
+{
+ for (int i=0; i<nspecies+nlasers; i++){
+ auto& pc = allcontainers[i];
+ if (pc->do_continuous_injection){
+ pc->ContinuousInjection(injection_box);
+ }
+ }
+}
+
+/* \brief Update position of continuous injection parameters.
+ * \param dt: simulation time step (level 0)
+ * All classes inherited from WarpXParticleContainer do not have
+ * a position to update (PhysicalParticleContainer does not do anything).
+ */
+void
+MultiParticleContainer::UpdateContinuousInjectionPosition(Real dt) const
+{
+ for (int i=0; i<nspecies+nlasers; i++){
+ auto& pc = allcontainers[i];
+ if (pc->do_continuous_injection){
+ pc->UpdateContinuousInjectionPosition(dt);
+ }
+ }
+}
+
+int
+MultiParticleContainer::doContinuousInjection() const
+{
+ int warpx_do_continuous_injection = 0;
+ for (int i=0; i<nspecies+nlasers; i++){
+ auto& pc = allcontainers[i];
+ if (pc->do_continuous_injection){
+ warpx_do_continuous_injection = 1;
+ }
+ }
+ return warpx_do_continuous_injection;
+}
diff --git a/Source/Particles/PhysicalParticleContainer.H b/Source/Particles/PhysicalParticleContainer.H
index 362683879..bd8cfb47e 100644
--- a/Source/Particles/PhysicalParticleContainer.H
+++ b/Source/Particles/PhysicalParticleContainer.H
@@ -94,15 +94,18 @@ public:
void AddGaussianBeam(amrex::Real x_m, amrex::Real y_m, amrex::Real z_m,
amrex::Real x_rms, amrex::Real y_rms, amrex::Real z_rms,
- amrex::Real q_tot, long npart);
+ amrex::Real q_tot, long npart, int do_symmetrize);
+
+ void CheckAndAddParticle(amrex::Real x, amrex::Real y, amrex::Real z,
+ std::array<amrex::Real, 3> u, amrex::Real weight);
virtual void GetParticleSlice(const int direction, const amrex::Real z_old,
const amrex::Real z_new, const amrex::Real t_boost,
const amrex::Real t_lab, const amrex::Real dt,
DiagnosticParticles& diagnostic_particles) final;
- bool injected = false;
-
+ virtual void ConvertUnits (ConvertDirection convert_dir) override;
+
protected:
std::string species_name;
@@ -122,6 +125,9 @@ protected:
int GetRefineFac(const amrex::Real x, const amrex::Real y, const amrex::Real z);
std::unique_ptr<amrex::IArrayBox> m_refined_injection_mask = nullptr;
+ // Inject particles during the whole simulation
+ void ContinuousInjection(const amrex::RealBox& injection_box) override;
+
};
#endif
diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp
index e31d43204..1f517fccb 100644
--- a/Source/Particles/PhysicalParticleContainer.cpp
+++ b/Source/Particles/PhysicalParticleContainer.cpp
@@ -24,7 +24,7 @@ NumParticlesToAdd(const Box& overlap_box, const RealBox& overlap_realbox,
for (IntVect iv = overlap_box.smallEnd(); iv <= overlap_box.bigEnd(); overlap_box.next(iv))
{
int fac;
- if (injected) {
+ if (do_continuous_injection) {
#if ( AMREX_SPACEDIM == 3 )
Real x = overlap_corner[0] + (iv[0] + 0.5)*dx[0];
Real y = overlap_corner[1] + (iv[1] + 0.5)*dx[1];
@@ -81,6 +81,41 @@ PhysicalParticleContainer::PhysicalParticleContainer (AmrCore* amr_core, int isp
pp.query("do_backward_propagation", do_backward_propagation);
pp.query("do_splitting", do_splitting);
pp.query("split_type", split_type);
+ pp.query("do_continuous_injection", do_continuous_injection);
+ // Whether to plot back-transformed (lab-frame) diagnostics
+ // for this species.
+ pp.query("do_boosted_frame_diags", do_boosted_frame_diags);
+
+ pp.query("plot_species", plot_species);
+ int do_user_plot_vars;
+ do_user_plot_vars = pp.queryarr("plot_vars", plot_vars);
+ if (not do_user_plot_vars){
+ // By default, all particle variables are dumped to plotfiles,
+ // including {x,y,z,ux,uy,uz}old variables when running in a
+ // boosted frame
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags){
+ plot_flags.resize(PIdx::nattribs + 6, 1);
+ } else {
+ plot_flags.resize(PIdx::nattribs, 1);
+ }
+ } else {
+ // Set plot_flag to 0 for all attribs
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags){
+ plot_flags.resize(PIdx::nattribs + 6, 0);
+ } else {
+ plot_flags.resize(PIdx::nattribs, 0);
+ }
+ // If not none, set plot_flags values to 1 for elements in plot_vars.
+ if (plot_vars[0] != "none"){
+ for (const auto& var : plot_vars){
+ // Return error if var not in PIdx.
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ParticleStringNames::to_index.count(var),
+ "plot_vars argument not in ParticleStringNames");
+ plot_flags[ParticleStringNames::to_index.at(var)] = 1;
+ }
+ }
+ }
}
PhysicalParticleContainer::PhysicalParticleContainer (AmrCore* amr_core)
@@ -146,7 +181,8 @@ void PhysicalParticleContainer::MapParticletoBoostedFrame(Real& x, Real& y, Real
void
PhysicalParticleContainer::AddGaussianBeam(Real x_m, Real y_m, Real z_m,
Real x_rms, Real y_rms, Real z_rms,
- Real q_tot, long npart) {
+ Real q_tot, long npart,
+ int do_symmetrize) {
const Geometry& geom = m_gdb->Geom(0);
RealBox containing_bx = geom.ProbDomain();
@@ -156,13 +192,15 @@ PhysicalParticleContainer::AddGaussianBeam(Real x_m, Real y_m, Real z_m,
std::normal_distribution<double> disty(y_m, y_rms);
std::normal_distribution<double> distz(z_m, z_rms);
- std::array<Real,PIdx::nattribs> attribs;
- attribs.fill(0.0);
-
if (ParallelDescriptor::IOProcessor()) {
- std::array<Real, 3> u;
- Real weight;
- for (long i = 0; i < npart; ++i) {
+ std::array<Real, 3> u;
+ Real weight;
+ // If do_symmetrize, create 4x fewer particles, and
+ // Replicate each particle 4 times (x,y) (-x,y) (x,-y) (-x,-y)
+ if (do_symmetrize){
+ npart /= 4;
+ }
+ for (long i = 0; i < npart; ++i) {
#if ( AMREX_SPACEDIM == 3 | WARPX_RZ)
weight = q_tot/npart/charge;
Real x = distx(mt);
@@ -174,17 +212,27 @@ PhysicalParticleContainer::AddGaussianBeam(Real x_m, Real y_m, Real z_m,
Real y = 0.;
Real z = distz(mt);
#endif
- if (plasma_injector->insideBounds(x, y, z)) {
- plasma_injector->getMomentum(u, x, y, z);
- if (WarpX::gamma_boost > 1.) {
- MapParticletoBoostedFrame(x, y, z, u);
- }
- attribs[PIdx::ux] = u[0];
- attribs[PIdx::uy] = u[1];
- attribs[PIdx::uz] = u[2];
- attribs[PIdx::w ] = weight;
-
- AddOneParticle(0, 0, 0, x, y, z, attribs);
+ if (plasma_injector->insideBounds(x, y, z)) {
+ plasma_injector->getMomentum(u, x, y, z);
+ if (do_symmetrize){
+ std::array<Real, 3> u_tmp;
+ Real x_tmp, y_tmp;
+ // Add four particles to the beam:
+ // (x,ux,y,uy) (-x,-ux,y,uy) (x,ux,-y,-uy) (-x,-ux,-y,-uy)
+ for (int ix=0; ix<2; ix++){
+ for (int iy=0; iy<2; iy++){
+ u_tmp = u;
+ x_tmp = x*std::pow(-1,ix);
+ u_tmp[0] *= std::pow(-1,ix);
+ y_tmp = y*std::pow(-1,iy);
+ u_tmp[1] *= std::pow(-1,iy);
+ CheckAndAddParticle(x_tmp, y_tmp, z,
+ u_tmp, weight/4);
+ }
+ }
+ } else {
+ CheckAndAddParticle(x, y, z, u, weight);
+ }
}
}
}
@@ -192,6 +240,39 @@ PhysicalParticleContainer::AddGaussianBeam(Real x_m, Real y_m, Real z_m,
}
void
+PhysicalParticleContainer::CheckAndAddParticle(Real x, Real y, Real z,
+ std::array<Real, 3> u,
+ Real weight)
+{
+ std::array<Real,PIdx::nattribs> attribs;
+ attribs.fill(0.0);
+
+ // update attribs with input arguments
+ if (WarpX::gamma_boost > 1.) {
+ MapParticletoBoostedFrame(x, y, z, u);
+ }
+ attribs[PIdx::ux] = u[0];
+ attribs[PIdx::uy] = u[1];
+ attribs[PIdx::uz] = u[2];
+ attribs[PIdx::w ] = weight;
+
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ // need to create old values
+ auto& particle_tile = DefineAndReturnParticleTile(0, 0, 0);
+ particle_tile.push_back_real(particle_comps["xold"], x);
+ particle_tile.push_back_real(particle_comps["yold"], y);
+ particle_tile.push_back_real(particle_comps["zold"], z);
+
+ particle_tile.push_back_real(particle_comps["uxold"], u[0]);
+ particle_tile.push_back_real(particle_comps["uyold"], u[1]);
+ particle_tile.push_back_real(particle_comps["uzold"], u[2]);
+ }
+ // add particle
+ AddOneParticle(0, 0, 0, x, y, z, attribs);
+}
+
+void
PhysicalParticleContainer::AddParticles (int lev)
{
BL_PROFILE("PhysicalParticleContainer::AddParticles()");
@@ -216,7 +297,8 @@ PhysicalParticleContainer::AddParticles (int lev)
plasma_injector->y_rms,
plasma_injector->z_rms,
plasma_injector->q_tot,
- plasma_injector->npart);
+ plasma_injector->npart,
+ plasma_injector->do_symmetrize);
return;
@@ -349,7 +431,7 @@ PhysicalParticleContainer::AddPlasmaCPU (int lev, RealBox part_realbox)
for (IntVect iv = overlap_box.smallEnd(); iv <= overlap_box.bigEnd(); overlap_box.next(iv))
{
int fac;
- if (injected) {
+ if (do_continuous_injection) {
#if ( AMREX_SPACEDIM == 3 )
Real x = overlap_corner[0] + (iv[0] + 0.5)*dx[0];
Real y = overlap_corner[1] + (iv[1] + 0.5)*dx[1];
@@ -455,16 +537,18 @@ PhysicalParticleContainer::AddPlasmaCPU (int lev, RealBox part_realbox)
attribs[PIdx::ux] = u[0];
attribs[PIdx::uy] = u[1];
attribs[PIdx::uz] = u[2];
-
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- attribs[PIdx::xold] = x;
- attribs[PIdx::yold] = y;
- attribs[PIdx::zold] = z;
-
- attribs[PIdx::uxold] = u[0];
- attribs[PIdx::uyold] = u[1];
- attribs[PIdx::uzold] = u[2];
-#endif
+
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& particle_tile = DefineAndReturnParticleTile(lev, grid_id, tile_id);
+ particle_tile.push_back_real(particle_comps["xold"], x);
+ particle_tile.push_back_real(particle_comps["yold"], y);
+ particle_tile.push_back_real(particle_comps["zold"], z);
+
+ particle_tile.push_back_real(particle_comps["uxold"], u[0]);
+ particle_tile.push_back_real(particle_comps["uyold"], u[1]);
+ particle_tile.push_back_real(particle_comps["uzold"], u[2]);
+ }
AddOneParticle(lev, grid_id, tile_id, x, y, z, attribs);
}
@@ -588,7 +672,7 @@ PhysicalParticleContainer::AddPlasmaGPU (int lev, RealBox part_realbox)
for (IntVect iv = overlap_box.smallEnd(); iv <= overlap_box.bigEnd(); overlap_box.next(iv))
{
int fac;
- if (injected) {
+ if (do_continuous_injection) {
#if ( AMREX_SPACEDIM == 3 )
Real x = overlap_corner[0] + (iv[0] + 0.5)*dx[0];
Real y = overlap_corner[1] + (iv[1] + 0.5)*dx[1];
@@ -695,15 +779,18 @@ PhysicalParticleContainer::AddPlasmaGPU (int lev, RealBox part_realbox)
attribs[PIdx::uy] = u[1];
attribs[PIdx::uz] = u[2];
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- attribs[PIdx::xold] = x;
- attribs[PIdx::yold] = y;
- attribs[PIdx::zold] = z;
-
- attribs[PIdx::uxold] = u[0];
- attribs[PIdx::uyold] = u[1];
- attribs[PIdx::uzold] = u[2];
-#endif
+ // note - this will be slow on the GPU, need to revisit
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& particle_tile = DefineAndReturnParticleTile(lev, grid_id, tile_id);
+ particle_tile.push_back_real(particle_comps["xold"], x);
+ particle_tile.push_back_real(particle_comps["yold"], y);
+ particle_tile.push_back_real(particle_comps["zold"], z);
+
+ particle_tile.push_back_real(particle_comps["uxold"], u[0]);
+ particle_tile.push_back_real(particle_comps["uyold"], u[1]);
+ particle_tile.push_back_real(particle_comps["uzold"], u[2]);
+ }
ParticleType p;
p.id() = ParticleType::NextID();
@@ -783,7 +870,6 @@ FieldGatherES (const amrex::Vector<std::array<std::unique_ptr<amrex::MultiFab>,
const auto& particles = pti.GetArrayOfStructs();
int nstride = particles.dataShape().first;
const long np = pti.numParticles();
-
auto& attribs = pti.GetAttribs();
auto& Exp = attribs[PIdx::Ex];
auto& Eyp = attribs[PIdx::Ey];
@@ -973,9 +1059,6 @@ PhysicalParticleContainer::FieldGather (int lev,
{
const std::array<Real,3>& dx = WarpX::CellSize(lev);
- // WarpX assumes the same number of guard cells for Ex, Ey, Ez, Bx, By, Bz
- long ng = Ex.nGrow();
-
BL_ASSERT(OnSameGrids(lev,Ex));
MultiFab* cost = WarpX::getCosts(lev);
@@ -1084,8 +1167,9 @@ PhysicalParticleContainer::Evolve (int lev,
const std::array<Real,3>& dx = WarpX::CellSize(lev);
const std::array<Real,3>& cdx = WarpX::CellSize(std::max(lev-1,0));
- const auto& mypc = WarpX::GetInstance().GetPartContainer();
- const int nstencilz_fdtd_nci_corr = mypc.nstencilz_fdtd_nci_corr;
+ // Get instances of NCI Godfrey filters
+ const auto& nci_godfrey_filter_exeybz = WarpX::GetInstance().nci_godfrey_filter_exeybz;
+ const auto& nci_godfrey_filter_bxbyez = WarpX::GetInstance().nci_godfrey_filter_bxbyez;
BL_ASSERT(OnSameGrids(lev,jx));
@@ -1117,7 +1201,7 @@ PhysicalParticleContainer::Evolve (int lev,
{
Real wt = amrex::second();
- const Box& box = pti.validbox();
+ const Box& box = pti.validbox();
auto& attribs = pti.GetAttribs();
@@ -1134,7 +1218,7 @@ PhysicalParticleContainer::Evolve (int lev,
const long np = pti.numParticles();
- // Data on the grid
+ // Data on the grid
FArrayBox const* exfab = &(Ex[pti]);
FArrayBox const* eyfab = &(Ey[pti]);
FArrayBox const* ezfab = &(Ez[pti]);
@@ -1142,6 +1226,7 @@ PhysicalParticleContainer::Evolve (int lev,
FArrayBox const* byfab = &(By[pti]);
FArrayBox const* bzfab = &(Bz[pti]);
+ Elixir exeli, eyeli, ezeli, bxeli, byeli, bzeli;
if (WarpX::use_fdtd_nci_corr)
{
#if (AMREX_SPACEDIM == 2)
@@ -1153,54 +1238,43 @@ PhysicalParticleContainer::Evolve (int lev,
static_cast<int>(WarpX::noz)});
#endif
- // both 2d and 3d
+ // Filter Ex (Both 2D and 3D)
filtered_Ex.resize(amrex::convert(tbox,WarpX::Ex_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ex),
- BL_TO_FORTRAN_ANYD(filtered_Ex),
- BL_TO_FORTRAN_ANYD(Ex[pti]),
- mypc.fdtd_nci_stencilz_ex[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ // Safeguard for GPU
+ exeli = filtered_Ex.elixir();
+ // Apply filter on Ex, result stored in filtered_Ex
+ nci_godfrey_filter_exeybz[lev]->ApplyStencil(filtered_Ex, Ex[pti], filtered_Ex.box());
+ // Update exfab reference
exfab = &filtered_Ex;
+ // Filter Ez
filtered_Ez.resize(amrex::convert(tbox,WarpX::Ez_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ez),
- BL_TO_FORTRAN_ANYD(filtered_Ez),
- BL_TO_FORTRAN_ANYD(Ez[pti]),
- mypc.fdtd_nci_stencilz_by[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ ezeli = filtered_Ez.elixir();
+ nci_godfrey_filter_bxbyez[lev]->ApplyStencil(filtered_Ez, Ez[pti], filtered_Ez.box());
ezfab = &filtered_Ez;
+ // Filter By
filtered_By.resize(amrex::convert(tbox,WarpX::By_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_By),
- BL_TO_FORTRAN_ANYD(filtered_By),
- BL_TO_FORTRAN_ANYD(By[pti]),
- mypc.fdtd_nci_stencilz_by[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ byeli = filtered_By.elixir();
+ nci_godfrey_filter_bxbyez[lev]->ApplyStencil(filtered_By, By[pti], filtered_By.box());
byfab = &filtered_By;
-
#if (AMREX_SPACEDIM == 3)
+ // Filter Ey
filtered_Ey.resize(amrex::convert(tbox,WarpX::Ey_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ey),
- BL_TO_FORTRAN_ANYD(filtered_Ey),
- BL_TO_FORTRAN_ANYD(Ey[pti]),
- mypc.fdtd_nci_stencilz_ex[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ eyeli = filtered_Ey.elixir();
+ nci_godfrey_filter_exeybz[lev]->ApplyStencil(filtered_Ey, Ey[pti], filtered_Ey.box());
eyfab = &filtered_Ey;
+ // Filter Bx
filtered_Bx.resize(amrex::convert(tbox,WarpX::Bx_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Bx),
- BL_TO_FORTRAN_ANYD(filtered_Bx),
- BL_TO_FORTRAN_ANYD(Bx[pti]),
- mypc.fdtd_nci_stencilz_by[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ bxeli = filtered_Bx.elixir();
+ nci_godfrey_filter_bxbyez[lev]->ApplyStencil(filtered_Bx, Bx[pti], filtered_Bx.box());
bxfab = &filtered_Bx;
+ // Filter Bz
filtered_Bz.resize(amrex::convert(tbox,WarpX::Bz_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Bz),
- BL_TO_FORTRAN_ANYD(filtered_Bz),
- BL_TO_FORTRAN_ANYD(Bz[pti]),
- mypc.fdtd_nci_stencilz_ex[lev].data(),
- &nstencilz_fdtd_nci_corr);
+ bzeli = filtered_Bz.elixir();
+ nci_godfrey_filter_exeybz[lev]->ApplyStencil(filtered_Bz, Bz[pti], filtered_Bz.box());
bzfab = &filtered_Bz;
#endif
}
@@ -1376,53 +1450,43 @@ PhysicalParticleContainer::Evolve (int lev,
static_cast<int>(WarpX::noz)});
#endif
- // both 2d and 3d
+ // Filter Ex (both 2D and 3D)
filtered_Ex.resize(amrex::convert(tbox,WarpX::Ex_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ex),
- BL_TO_FORTRAN_ANYD(filtered_Ex),
- BL_TO_FORTRAN_ANYD((*cEx)[pti]),
- mypc.fdtd_nci_stencilz_ex[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ // Safeguard for GPU
+ exeli = filtered_Ex.elixir();
+ // Apply filter on Ex, result stored in filtered_Ex
+ nci_godfrey_filter_exeybz[lev-1]->ApplyStencil(filtered_Ex, (*cEx)[pti], filtered_Ex.box());
+ // Update exfab reference
cexfab = &filtered_Ex;
+ // Filter Ez
filtered_Ez.resize(amrex::convert(tbox,WarpX::Ez_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ez),
- BL_TO_FORTRAN_ANYD(filtered_Ez),
- BL_TO_FORTRAN_ANYD((*cEz)[pti]),
- mypc.fdtd_nci_stencilz_by[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ ezeli = filtered_Ez.elixir();
+ nci_godfrey_filter_bxbyez[lev-1]->ApplyStencil(filtered_Ez, (*cEz)[pti], filtered_Ez.box());
cezfab = &filtered_Ez;
+
+ // Filter By
filtered_By.resize(amrex::convert(tbox,WarpX::By_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_By),
- BL_TO_FORTRAN_ANYD(filtered_By),
- BL_TO_FORTRAN_ANYD((*cBy)[pti]),
- mypc.fdtd_nci_stencilz_by[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ byeli = filtered_By.elixir();
+ nci_godfrey_filter_bxbyez[lev-1]->ApplyStencil(filtered_By, (*cBy)[pti], filtered_By.box());
cbyfab = &filtered_By;
-
#if (AMREX_SPACEDIM == 3)
+ // Filter Ey
filtered_Ey.resize(amrex::convert(tbox,WarpX::Ey_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Ey),
- BL_TO_FORTRAN_ANYD(filtered_Ey),
- BL_TO_FORTRAN_ANYD((*cEy)[pti]),
- mypc.fdtd_nci_stencilz_ex[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ eyeli = filtered_Ey.elixir();
+ nci_godfrey_filter_exeybz[lev-1]->ApplyStencil(filtered_Ey, (*cEy)[pti], filtered_Ey.box());
ceyfab = &filtered_Ey;
+ // Filter Bx
filtered_Bx.resize(amrex::convert(tbox,WarpX::Bx_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Bx),
- BL_TO_FORTRAN_ANYD(filtered_Bx),
- BL_TO_FORTRAN_ANYD((*cBx)[pti]),
- mypc.fdtd_nci_stencilz_by[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ bxeli = filtered_Bx.elixir();
+ nci_godfrey_filter_bxbyez[lev-1]->ApplyStencil(filtered_Bx, (*cBx)[pti], filtered_Bx.box());
cbxfab = &filtered_Bx;
+ // Filter Bz
filtered_Bz.resize(amrex::convert(tbox,WarpX::Bz_nodal_flag));
- WRPX_PXR_GODFREY_FILTER(BL_TO_FORTRAN_BOX(filtered_Bz),
- BL_TO_FORTRAN_ANYD(filtered_Bz),
- BL_TO_FORTRAN_ANYD((*cBz)[pti]),
- mypc.fdtd_nci_stencilz_ex[lev-1].data(),
- &nstencilz_fdtd_nci_corr);
+ bzeli = filtered_Bz.elixir();
+ nci_godfrey_filter_exeybz[lev-1]->ApplyStencil(filtered_Bz, (*cBz)[pti], filtered_Bz.box());
cbzfab = &filtered_Bz;
#endif
}
@@ -1666,20 +1730,20 @@ PhysicalParticleContainer::PushPX(WarpXParIter& pti,
auto& Bzp = attribs[PIdx::Bz];
const long np = pti.numParticles();
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- auto& xpold = attribs[PIdx::xold];
- auto& ypold = attribs[PIdx::yold];
- auto& zpold = attribs[PIdx::zold];
- auto& uxpold = attribs[PIdx::uxold];
- auto& uypold = attribs[PIdx::uyold];
- auto& uzpold = attribs[PIdx::uzold];
-
- warpx_copy_attribs(&np, xp.dataPtr(), yp.dataPtr(), zp.dataPtr(),
- uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
- xpold.dataPtr(), ypold.dataPtr(), zpold.dataPtr(),
- uxpold.dataPtr(), uypold.dataPtr(), uzpold.dataPtr());
-
-#endif
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& xpold = pti.GetAttribs(particle_comps["xold"]);
+ auto& ypold = pti.GetAttribs(particle_comps["yold"]);
+ auto& zpold = pti.GetAttribs(particle_comps["zold"]);
+ auto& uxpold = pti.GetAttribs(particle_comps["uxold"]);
+ auto& uypold = pti.GetAttribs(particle_comps["uyold"]);
+ auto& uzpold = pti.GetAttribs(particle_comps["uzold"]);
+
+ warpx_copy_attribs(&np, xp.dataPtr(), yp.dataPtr(), zp.dataPtr(),
+ uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
+ xpold.dataPtr(), ypold.dataPtr(), zpold.dataPtr(),
+ uxpold.dataPtr(), uypold.dataPtr(), uzpold.dataPtr());
+ }
warpx_particle_pusher(&np,
xp.dataPtr(),
@@ -1801,7 +1865,6 @@ void PhysicalParticleContainer::GetParticleSlice(const int direction, const Real
{
BL_PROFILE("PhysicalParticleContainer::GetParticleSlice");
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
// Assume that the boost in the positive z direction.
#if (AMREX_SPACEDIM == 2)
AMREX_ALWAYS_ASSERT(direction == 1);
@@ -1812,6 +1875,8 @@ void PhysicalParticleContainer::GetParticleSlice(const int direction, const Real
// Note the the slice should always move in the negative boost direction.
AMREX_ALWAYS_ASSERT(z_new < z_old);
+ AMREX_ALWAYS_ASSERT(do_boosted_frame_diags == 1);
+
const int nlevs = std::max(0, finestLevel()+1);
// we figure out a box for coarse-grained rejection. If the RealBox corresponding to a
@@ -1864,12 +1929,12 @@ void PhysicalParticleContainer::GetParticleSlice(const int direction, const Real
auto& uyp_new = attribs[PIdx::uy ];
auto& uzp_new = attribs[PIdx::uz ];
- auto& xp_old = attribs[PIdx::xold ];
- auto& yp_old = attribs[PIdx::yold ];
- auto& zp_old = attribs[PIdx::zold ];
- auto& uxp_old = attribs[PIdx::uxold];
- auto& uyp_old = attribs[PIdx::uyold];
- auto& uzp_old = attribs[PIdx::uzold];
+ auto& xp_old = pti.GetAttribs(particle_comps["xold"]);
+ auto& yp_old = pti.GetAttribs(particle_comps["yold"]);
+ auto& zp_old = pti.GetAttribs(particle_comps["zold"]);
+ auto& uxp_old = pti.GetAttribs(particle_comps["uxold"]);
+ auto& uyp_old = pti.GetAttribs(particle_comps["uyold"]);
+ auto& uzp_old = pti.GetAttribs(particle_comps["uzold"]);
const long np = pti.numParticles();
@@ -1919,10 +1984,6 @@ void PhysicalParticleContainer::GetParticleSlice(const int direction, const Real
}
}
}
-#else
- AMREX_ALWAYS_ASSERT_WITH_MESSAGE( false ,
-"ERROR: WarpX must be compiled with STORE_OLD_PARTICLE_ATTRIBS=TRUE to use the back-transformed diagnostics");
-#endif
}
int PhysicalParticleContainer::GetRefineFac(const Real x, const Real y, const Real z)
@@ -1992,3 +2053,14 @@ int PhysicalParticleContainer::GetRefineFac(const Real x, const Real y, const Re
return ref_fac;
}
+
+/* \brief Inject particles during the simulation
+ * \param injection_box: domain where particles should be injected.
+ */
+void
+PhysicalParticleContainer::ContinuousInjection(const RealBox& injection_box)
+{
+ // Inject plasma on level 0. Paticles will be redistributed.
+ const int lev=0;
+ AddPlasma(lev, injection_box);
+}
diff --git a/Source/Particles/Pusher/GetAndSetPosition.H b/Source/Particles/Pusher/GetAndSetPosition.H
new file mode 100644
index 000000000..42c61343e
--- /dev/null
+++ b/Source/Particles/Pusher/GetAndSetPosition.H
@@ -0,0 +1,76 @@
+#ifndef WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
+#define WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
+
+#include <limits>
+#include <WarpXParticleContainer.H>
+#include <AMReX_REAL.H>
+
+#ifndef WARPX_RZ
+
+/* \brief Extract the particle's coordinates from the ParticleType struct `p`,
+ * and stores them in the variables `x`, `y`, `z`. */
+AMREX_GPU_HOST_DEVICE AMREX_INLINE
+void GetPosition(
+ amrex::Real& x, amrex::Real& y, amrex::Real& z,
+ const WarpXParticleContainer::ParticleType& p)
+{
+#if (AMREX_SPACEDIM==3)
+ x = p.pos(0);
+ y = p.pos(1);
+ z = p.pos(2);
+#else
+ x = p.pos(0);
+ y = std::numeric_limits<amrex::Real>::quiet_NaN();
+ z = p.pos(1);
+#endif
+}
+
+/* \brief Set the particle's coordinates in the ParticleType struct `p`,
+ * from their values in the variables `x`, `y`, `z`. */
+AMREX_GPU_HOST_DEVICE AMREX_INLINE
+void SetPosition(
+ WarpXParticleContainer::ParticleType& p,
+ const amrex::Real x, const amrex::Real y, const amrex::Real z)
+{
+#if (AMREX_SPACEDIM==3)
+ p.pos(0) = x;
+ p.pos(1) = y;
+ p.pos(2) = z;
+#else
+ p.pos(0) = x;
+ p.pos(1) = z;
+#endif
+}
+
+# else // if WARPX_RZ is True
+
+/* \brief Extract the particle's coordinates from `theta` and the attributes
+ * of the ParticleType struct `p` (which contains the radius),
+ * and store them in the variables `x`, `y`, `z` */
+AMREX_GPU_HOST_DEVICE AMREX_INLINE
+void GetCartesianPositionFromCylindrical(
+ amrex::Real& x, amrex::Real& y, amrex::Real& z,
+ const WarpXParticleContainer::ParticleType& p, const amrex::Real theta)
+{
+ const amrex::Real r = p.pos(0);
+ x = r*std::cos(theta);
+ y = r*std::sin(theta);
+ z = p.pos(1);
+}
+
+/* \brief Set the particle's cylindrical coordinates by setting `theta`
+ * and the attributes of the ParticleType struct `p` (which stores the radius),
+ * from the values of `x`, `y`, `z` */
+AMREX_GPU_HOST_DEVICE AMREX_INLINE
+void SetCylindricalPositionFromCartesian(
+ WarpXParticleContainer::ParticleType& p, amrex::Real& theta,
+ const amrex::Real x, const amrex::Real y, const amrex::Real z )
+{
+ theta = std::atan2(y, x);
+ p.pos(0) = std::sqrt(x*x + y*y);
+ p.pos(1) = z;
+}
+
+#endif // WARPX_RZ
+
+#endif // WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
diff --git a/Source/Particles/Pusher/Make.package b/Source/Particles/Pusher/Make.package
new file mode 100644
index 000000000..8c8e77905
--- /dev/null
+++ b/Source/Particles/Pusher/Make.package
@@ -0,0 +1,4 @@
+CEXE_headers += GetAndSetPosition.H
+CEXE_headers += UpdatePosition.H
+INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Particles/Pusher
+VPATH_LOCATIONS += $(WARPX_HOME)/Source/Particles/Pusher
diff --git a/Source/Particles/Pusher/UpdatePosition.H b/Source/Particles/Pusher/UpdatePosition.H
new file mode 100644
index 000000000..0a4f579f4
--- /dev/null
+++ b/Source/Particles/Pusher/UpdatePosition.H
@@ -0,0 +1,30 @@
+#ifndef WARPX_PARTICLES_PUSHER_UPDATEPOSITION_H_
+#define WARPX_PARTICLES_PUSHER_UPDATEPOSITION_H_
+
+#include <AMReX_FArrayBox.H>
+#include <WarpXConst.H>
+#include <AMReX_REAL.H>
+
+/* \brief Push the particle's positions over one timestep,
+ * given the value of its momenta `ux`, `uy`, `uz` */
+AMREX_GPU_HOST_DEVICE AMREX_INLINE
+void UpdatePosition(
+ amrex::Real& x, amrex::Real& y, amrex::Real& z,
+ const amrex::Real ux, const amrex::Real uy, const amrex::Real uz,
+ const amrex::Real dt )
+{
+
+ constexpr amrex::Real inv_c2 = 1./(PhysConst::c*PhysConst::c);
+
+ // Compute inverse Lorentz factor
+ const amrex::Real inv_gamma = 1./std::sqrt(1. + (ux*ux + uy*uy + uz*uz)*inv_c2);
+ // Update positions over one time step
+ x += ux * inv_gamma * dt;
+#if (AMREX_SPACEDIM == 3) || (defined WARPX_RZ) // RZ pushes particles in 3D
+ y += uy * inv_gamma * dt;
+#endif
+ z += uz * inv_gamma * dt;
+
+}
+
+#endif // WARPX_PARTICLES_PUSHER_UPDATEPOSITION_H_
diff --git a/Source/Particles/RigidInjectedParticleContainer.H b/Source/Particles/RigidInjectedParticleContainer.H
index d3a69f5b0..0b27a2f2f 100644
--- a/Source/Particles/RigidInjectedParticleContainer.H
+++ b/Source/Particles/RigidInjectedParticleContainer.H
@@ -57,6 +57,10 @@ public:
const amrex::MultiFab& By,
const amrex::MultiFab& Bz) override;
+ virtual void ReadHeader (std::istream& is) override;
+
+ virtual void WriteHeader (std::ostream& os) const override;
+
private:
// User input quantities
diff --git a/Source/Particles/RigidInjectedParticleContainer.cpp b/Source/Particles/RigidInjectedParticleContainer.cpp
index 3ee4d87e5..2a3e8dd0d 100644
--- a/Source/Particles/RigidInjectedParticleContainer.cpp
+++ b/Source/Particles/RigidInjectedParticleContainer.cpp
@@ -77,7 +77,6 @@ RigidInjectedParticleContainer::RemapParticles()
for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
{
-
auto& attribs = pti.GetAttribs();
auto& uxp = attribs[PIdx::ux];
auto& uyp = attribs[PIdx::uy];
@@ -225,20 +224,20 @@ RigidInjectedParticleContainer::PushPX(WarpXParIter& pti,
auto& Bzp = attribs[PIdx::Bz];
const long np = pti.numParticles();
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- auto& xpold = attribs[PIdx::xold];
- auto& ypold = attribs[PIdx::yold];
- auto& zpold = attribs[PIdx::zold];
- auto& uxpold = attribs[PIdx::uxold];
- auto& uypold = attribs[PIdx::uyold];
- auto& uzpold = attribs[PIdx::uzold];
-
- warpx_copy_attribs(&np, xp.dataPtr(), yp.dataPtr(), zp.dataPtr(),
- uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
- xpold.dataPtr(), ypold.dataPtr(), zpold.dataPtr(),
- uxpold.dataPtr(), uypold.dataPtr(), uzpold.dataPtr());
-
-#endif
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& xpold = pti.GetAttribs(particle_comps["xold"]);
+ auto& ypold = pti.GetAttribs(particle_comps["yold"]);
+ auto& zpold = pti.GetAttribs(particle_comps["zold"]);
+ auto& uxpold = pti.GetAttribs(particle_comps["uxold"]);
+ auto& uypold = pti.GetAttribs(particle_comps["uyold"]);
+ auto& uzpold = pti.GetAttribs(particle_comps["uzold"]);
+
+ warpx_copy_attribs(&np, xp.dataPtr(), yp.dataPtr(), zp.dataPtr(),
+ uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
+ xpold.dataPtr(), ypold.dataPtr(), zpold.dataPtr(),
+ uxpold.dataPtr(), uypold.dataPtr(), uzpold.dataPtr());
+ }
// Save the position and momenta, making copies
Cuda::ManagedDeviceVector<Real> xp_save, yp_save, zp_save;
diff --git a/Source/Particles/WarpXParticleContainer.H b/Source/Particles/WarpXParticleContainer.H
index 050060b47..1e3dfb2ae 100644
--- a/Source/Particles/WarpXParticleContainer.H
+++ b/Source/Particles/WarpXParticleContainer.H
@@ -6,6 +6,8 @@
#include <AMReX_Particles.H>
#include <AMReX_AmrCore.H>
+enum struct ConvertDirection{WarpX_to_SI, SI_to_WarpX};
+
struct PIdx
{
enum { // Particle Attributes stored in amrex::ParticleContainer's struct of array
@@ -14,9 +16,6 @@ struct PIdx
#ifdef WARPX_RZ
theta, // RZ needs all three position components
#endif
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- xold, yold, zold, uxold, uyold, uzold,
-#endif
nattribs
};
};
@@ -42,15 +41,7 @@ namespace ParticleStringNames
{"Ez", PIdx::Ez },
{"Bx", PIdx::Bx },
{"By", PIdx::By },
- {"Bz", PIdx::Bz },
-#ifdef WARPX_STORE_OLD_PARTICLE_ATTRIBS
- {"xold", PIdx::xold },
- {"yold", PIdx::yold },
- {"zold", PIdx::zold },
- {"uxold", PIdx::uxold},
- {"uyold", PIdx::uyold},
- {"uzold", PIdx::uzold},
-#endif
+ {"Bz", PIdx::Bz }
};
}
@@ -70,7 +61,6 @@ public:
const amrex::Cuda::ManagedDeviceVector<amrex::Real>& y,
const amrex::Cuda::ManagedDeviceVector<amrex::Real>& z);
#endif
-
const std::array<RealVector, PIdx::nattribs>& GetAttribs () const {
return GetStructOfArrays().GetRealData();
}
@@ -96,7 +86,13 @@ class WarpXParticleContainer
public:
friend MultiParticleContainer;
+ // amrex::StructOfArrays with DiagIdx::nattribs amrex::Real components
+ // and 0 int components for the particle data.
using DiagnosticParticleData = amrex::StructOfArrays<DiagIdx::nattribs, 0>;
+ // DiagnosticParticles is a vector, with one element per MR level.
+ // DiagnosticParticles[lev] is typically a key-value pair where the key is
+ // a pair [grid_index, tile_index], and the value is the corresponding
+ // DiagnosticParticleData (see above) on this tile.
using DiagnosticParticles = amrex::Vector<std::map<std::pair<int, int>, DiagnosticParticleData> >;
WarpXParticleContainer (amrex::AmrCore* amr_core, int ispecies);
@@ -194,7 +190,18 @@ public:
int thread_num,
int lev,
amrex::Real dt );
-
+
+ // If particles start outside of the domain, ContinuousInjection
+ // makes sure that they are initialized when they enter the domain, and
+ // NOT before. Virtual function, overriden by derived classes.
+ // Current status:
+ // PhysicalParticleContainer: implemented.
+ // LaserParticleContainer: implemented.
+ // RigidInjectedParticleContainer: not implemented.
+ virtual void ContinuousInjection(const amrex::RealBox& injection_box) {}
+ // Update optional sub-class-specific injection location.
+ virtual void UpdateContinuousInjectionPosition(amrex::Real dt) {}
+
///
/// This returns the total charge for all the particles in this ParticleContainer.
/// This is needed when solving Poisson's equation with periodic boundary conditions.
@@ -218,9 +225,11 @@ public:
amrex::Real x, amrex::Real y, amrex::Real z,
std::array<amrex::Real,PIdx::nattribs>& attribs);
- void ReadHeader (std::istream& is);
+ virtual void ReadHeader (std::istream& is);
+
+ virtual void WriteHeader (std::ostream& os) const;
- void WriteHeader (std::ostream& os) const;
+ virtual void ConvertUnits (ConvertDirection convert_dir){};
static void ReadParameters ();
@@ -231,8 +240,27 @@ public:
// split along axes (0) or diagonals (1)
int split_type = 0;
+ using amrex::ParticleContainer<0, 0, PIdx::nattribs>::AddRealComp;
+ using amrex::ParticleContainer<0, 0, PIdx::nattribs>::AddIntComp;
+
+ void AddRealComp (const std::string& name, bool comm=true)
+ {
+ particle_comps[name] = NumRealComps();
+ AddRealComp(comm);
+ }
+
+ void AddIntComp (const std::string& name, bool comm=true)
+ {
+ particle_comps[name] = NumIntComps();
+ AddIntComp(comm);
+ }
+
+ int DoBoostedFrameDiags () const { return do_boosted_frame_diags; }
+
protected:
+ std::map<std::string, int> particle_comps;
+
int species_id;
amrex::Real charge;
@@ -242,6 +270,14 @@ protected:
static int do_not_push;
+ // Whether to allow particles outside of the simulation domain to be
+ // initialized when they enter the domain.
+ // This is currently required because continuous injection does not
+ // support all features allowed by direct injection.
+ int do_continuous_injection = 0;
+
+ int do_boosted_frame_diags = 1;
+
amrex::Vector<amrex::FArrayBox> local_rho;
amrex::Vector<amrex::FArrayBox> local_jx;
amrex::Vector<amrex::FArrayBox> local_jy;
@@ -249,9 +285,19 @@ protected:
amrex::Vector<amrex::Cuda::ManagedDeviceVector<amrex::Real> > m_xp, m_yp, m_zp, m_giv;
+ // Whether to dump particle quantities.
+ // If true, particle position is always dumped.
+ int plot_species = 1;
+ // For all particle attribs (execept position), whether or not
+ // to dump to file.
+ amrex::Vector<int> plot_flags;
+ // list of names of attributes to dump.
+ amrex::Vector<std::string> plot_vars;
+
private:
virtual void particlePostLocate(ParticleType& p, const amrex::ParticleLocData& pld,
const int lev) override;
+
};
#endif
diff --git a/Source/Particles/WarpXParticleContainer.cpp b/Source/Particles/WarpXParticleContainer.cpp
index c52e0a6d0..43d7999d1 100644
--- a/Source/Particles/WarpXParticleContainer.cpp
+++ b/Source/Particles/WarpXParticleContainer.cpp
@@ -7,6 +7,10 @@
#include <WarpX_f.H>
#include <WarpX.H>
+// Import low-level single-particle kernels
+#include <GetAndSetPosition.H>
+#include <UpdatePosition.H>
+
using namespace amrex;
int WarpXParticleContainer::do_not_push = 0;
@@ -63,6 +67,32 @@ WarpXParticleContainer::WarpXParticleContainer (AmrCore* amr_core, int ispecies)
SetParticleSize();
ReadParameters();
+ // build up the map of string names to particle component numbers
+ particle_comps["w"] = PIdx::w;
+ particle_comps["ux"] = PIdx::ux;
+ particle_comps["uy"] = PIdx::uy;
+ particle_comps["uz"] = PIdx::uz;
+ particle_comps["Ex"] = PIdx::Ex;
+ particle_comps["Ey"] = PIdx::Ey;
+ particle_comps["Ez"] = PIdx::Ez;
+ particle_comps["Bx"] = PIdx::Bx;
+ particle_comps["By"] = PIdx::By;
+ particle_comps["Bz"] = PIdx::Bz;
+#ifdef WARPX_RZ
+ particle_comps["theta"] = PIdx::theta;
+#endif
+
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ particle_comps["xold"] = PIdx::nattribs;
+ particle_comps["yold"] = PIdx::nattribs+1;
+ particle_comps["zold"] = PIdx::nattribs+2;
+ particle_comps["uxold"] = PIdx::nattribs+3;
+ particle_comps["uyold"] = PIdx::nattribs+4;
+ particle_comps["uzold"] = PIdx::nattribs+5;
+
+ }
+
// Initialize temporary local arrays for charge/current deposition
int num_threads = 1;
#ifdef _OPENMP
@@ -148,7 +178,7 @@ WarpXParticleContainer::AddNParticles (int lev,
int n, const Real* x, const Real* y, const Real* z,
const Real* vx, const Real* vy, const Real* vz,
int nattr, const Real* attr, int uniqueparticles, int id)
-{
+{
BL_ASSERT(nattr == 1);
const Real* weight = attr;
@@ -204,6 +234,15 @@ WarpXParticleContainer::AddNParticles (int lev,
#endif
p.pos(1) = z[i];
#endif
+
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& ptile = DefineAndReturnParticleTile(0, 0, 0);
+ ptile.push_back_real(particle_comps["xold"], x[i]);
+ ptile.push_back_real(particle_comps["yold"], y[i]);
+ ptile.push_back_real(particle_comps["zold"], z[i]);
+ }
+
particle_tile.push_back(p);
}
@@ -214,6 +253,14 @@ WarpXParticleContainer::AddNParticles (int lev,
particle_tile.push_back_real(PIdx::uy, vy + ibegin, vy + iend);
particle_tile.push_back_real(PIdx::uz, vz + ibegin, vz + iend);
+ if (WarpX::do_boosted_frame_diagnostic && do_boosted_frame_diags)
+ {
+ auto& ptile = DefineAndReturnParticleTile(0, 0, 0);
+ ptile.push_back_real(particle_comps["uxold"], vx + ibegin, vx + iend);
+ ptile.push_back_real(particle_comps["uyold"], vy + ibegin, vy + iend);
+ ptile.push_back_real(particle_comps["uzold"], vz + ibegin, vz + iend);
+ }
+
for (int comp = PIdx::uz+1; comp < PIdx::nattribs; ++comp)
{
#ifdef WARPX_RZ
@@ -259,7 +306,7 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti,
// WarpX assumes the same number of guard cells for Jx, Jy, Jz
long ngJ = jx.nGrow();
- bool j_is_nodal = jx.is_nodal() and jy.is_nodal() and jz.is_nodal();
+ int j_is_nodal = jx.is_nodal() and jy.is_nodal() and jz.is_nodal();
// Deposit charge for particles that are not in the current buffers
if (np_current > 0)
@@ -284,7 +331,7 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti,
jx_ptr = local_jx[thread_num].dataPtr();
jy_ptr = local_jy[thread_num].dataPtr();
jz_ptr = local_jz[thread_num].dataPtr();
-
+
local_jx[thread_num].setVal(0.0);
local_jy[thread_num].setVal(0.0);
local_jz[thread_num].setVal(0.0);
@@ -295,95 +342,32 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti,
#endif
BL_PROFILE_VAR_START(blp_pxr_cd);
- if (j_is_nodal) {
- const Real* p_wp = wp.dataPtr();
- const Real* p_gaminv = m_giv[thread_num].dataPtr();
- const Real* p_uxp = uxp.dataPtr();
- const Real* p_uyp = uyp.dataPtr();
- const Real* p_uzp = uzp.dataPtr();
- AsyncArray<Real> wptmp_aa(np_current);
- Real* const wptmp = wptmp_aa.data();
- const Box& tile_box = pti.tilebox();
-#if (AMREX_SPACEDIM == 3)
- const long nx = tile_box.length(0);
- const long ny = tile_box.length(1);
- const long nz = tile_box.length(2);
-#else
- const long nx = tile_box.length(0);
- const long ny = 0;
- const long nz = tile_box.length(1);
-#endif
- amrex::ParallelFor (np_current, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uxp[ip];
- });
- warpx_charge_deposition(jx_ptr, &np_current,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- wptmp,
- &this->charge,
- &xyzmin[0], &xyzmin[1], &xyzmin[2],
- &dx[0], &dx[1], &dx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- amrex::ParallelFor (np_current, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uyp[ip];
- });
- warpx_charge_deposition(jy_ptr, &np_current,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- wptmp,
- &this->charge,
- &xyzmin[0], &xyzmin[1], &xyzmin[2],
- &dx[0], &dx[1], &dx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- amrex::ParallelFor (np_current, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uzp[ip];
- });
- warpx_charge_deposition(jz_ptr, &np_current,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- wptmp,
- &this->charge,
- &xyzmin[0], &xyzmin[1], &xyzmin[2],
- &dx[0], &dx[1], &dx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- } else {
- warpx_current_deposition(
- jx_ptr, &ngJ, jxntot.getVect(),
- jy_ptr, &ngJ, jyntot.getVect(),
- jz_ptr, &ngJ, jzntot.getVect(),
- &np_current,
- m_xp[thread_num].dataPtr(),
- m_yp[thread_num].dataPtr(),
- m_zp[thread_num].dataPtr(),
- uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
- m_giv[thread_num].dataPtr(),
- wp.dataPtr(), &this->charge,
- &xyzmin[0], &xyzmin[1], &xyzmin[2],
- &dt, &dx[0], &dx[1], &dx[2],
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect,&WarpX::current_deposition_algo);
+ warpx_current_deposition(
+ jx_ptr, &ngJ, jxntot.getVect(),
+ jy_ptr, &ngJ, jyntot.getVect(),
+ jz_ptr, &ngJ, jzntot.getVect(),
+ &np_current,
+ m_xp[thread_num].dataPtr(),
+ m_yp[thread_num].dataPtr(),
+ m_zp[thread_num].dataPtr(),
+ uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
+ m_giv[thread_num].dataPtr(),
+ wp.dataPtr(), &this->charge,
+ &xyzmin[0], &xyzmin[1], &xyzmin[2],
+ &dt, &dx[0], &dx[1], &dx[2],
+ &WarpX::nox,&WarpX::noy,&WarpX::noz, &j_is_nodal,
+ &lvect,&WarpX::current_deposition_algo);
#ifdef WARPX_RZ
- warpx_current_deposition_rz_volume_scaling(
+ warpx_current_deposition_rz_volume_scaling(
jx_ptr, &ngJ, jxntot.getVect(),
jy_ptr, &ngJ, jyntot.getVect(),
jz_ptr, &ngJ, jzntot.getVect(),
&xyzmin[0], &dx[0]);
#endif
- }
-
BL_PROFILE_VAR_STOP(blp_pxr_cd);
-#ifndef AMREX_USE_GPU
+#ifndef AMREX_USE_GPU
BL_PROFILE_VAR_START(blp_accumulate);
jx[pti].atomicAdd(local_jx[thread_num], tbx, tbx, 0, 0, 1);
@@ -434,95 +418,33 @@ WarpXParticleContainer::DepositCurrent(WarpXParIter& pti,
auto jyntot = local_jy[thread_num].length();
auto jzntot = local_jz[thread_num].length();
#endif
-
+
long ncrse = np - np_current;
BL_PROFILE_VAR_START(blp_pxr_cd);
- if (j_is_nodal) {
- const Real* p_wp = wp.dataPtr() + np_current;
- const Real* p_gaminv = m_giv[thread_num].dataPtr() + np_current;
- const Real* p_uxp = uxp.dataPtr() + np_current;
- const Real* p_uyp = uyp.dataPtr() + np_current;
- const Real* p_uzp = uzp.dataPtr() + np_current;
- AsyncArray<Real> wptmp_aa(ncrse);
- Real* const wptmp = wptmp_aa.data();
- const Box& tile_box = pti.tilebox();
-#if (AMREX_SPACEDIM == 3)
- const long nx = tile_box.length(0);
- const long ny = tile_box.length(1);
- const long nz = tile_box.length(2);
-#else
- const long nx = tile_box.length(0);
- const long ny = 0;
- const long nz = tile_box.length(1);
-#endif
- amrex::ParallelFor (ncrse, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uxp[ip];
- });
- warpx_charge_deposition(jx_ptr, &ncrse,
- m_xp[thread_num].dataPtr() +np_current,
- m_yp[thread_num].dataPtr() +np_current,
- m_zp[thread_num].dataPtr() +np_current,
- wptmp,
- &this->charge,
- &cxyzmin_tile[0], &cxyzmin_tile[1], &cxyzmin_tile[2],
- &cdx[0], &cdx[1], &cdx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- amrex::ParallelFor (ncrse, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uyp[ip];
- });
- warpx_charge_deposition(jy_ptr, &ncrse,
- m_xp[thread_num].dataPtr() +np_current,
- m_yp[thread_num].dataPtr() +np_current,
- m_zp[thread_num].dataPtr() +np_current,
- wptmp,
- &this->charge,
- &cxyzmin_tile[0], &cxyzmin_tile[1], &cxyzmin_tile[2],
- &cdx[0], &cdx[1], &cdx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- amrex::ParallelFor (ncrse, [=] AMREX_GPU_DEVICE (long ip) {
- wptmp[ip] = p_wp[ip] * p_gaminv[ip] * p_uzp[ip];
- });
- warpx_charge_deposition(jz_ptr, &ncrse,
- m_xp[thread_num].dataPtr() +np_current,
- m_yp[thread_num].dataPtr() +np_current,
- m_zp[thread_num].dataPtr() +np_current,
- wptmp,
- &this->charge,
- &cxyzmin_tile[0], &cxyzmin_tile[1], &cxyzmin_tile[2],
- &cdx[0], &cdx[1], &cdx[2], &nx, &ny, &nz,
- &ngJ, &ngJ, &ngJ,
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect, &WarpX::current_deposition_algo);
- } else {
- warpx_current_deposition(
- jx_ptr, &ngJ, jxntot.getVect(),
- jy_ptr, &ngJ, jyntot.getVect(),
- jz_ptr, &ngJ, jzntot.getVect(),
- &ncrse,
- m_xp[thread_num].dataPtr() +np_current,
- m_yp[thread_num].dataPtr() +np_current,
- m_zp[thread_num].dataPtr() +np_current,
- uxp.dataPtr()+np_current,
- uyp.dataPtr()+np_current,
- uzp.dataPtr()+np_current,
- m_giv[thread_num].dataPtr()+np_current,
- wp.dataPtr()+np_current, &this->charge,
- &cxyzmin_tile[0], &cxyzmin_tile[1], &cxyzmin_tile[2],
- &dt, &cdx[0], &cdx[1], &cdx[2],
- &WarpX::nox,&WarpX::noy,&WarpX::noz,
- &lvect,&WarpX::current_deposition_algo);
+ warpx_current_deposition(
+ jx_ptr, &ngJ, jxntot.getVect(),
+ jy_ptr, &ngJ, jyntot.getVect(),
+ jz_ptr, &ngJ, jzntot.getVect(),
+ &ncrse,
+ m_xp[thread_num].dataPtr() +np_current,
+ m_yp[thread_num].dataPtr() +np_current,
+ m_zp[thread_num].dataPtr() +np_current,
+ uxp.dataPtr()+np_current,
+ uyp.dataPtr()+np_current,
+ uzp.dataPtr()+np_current,
+ m_giv[thread_num].dataPtr()+np_current,
+ wp.dataPtr()+np_current, &this->charge,
+ &cxyzmin_tile[0], &cxyzmin_tile[1], &cxyzmin_tile[2],
+ &dt, &cdx[0], &cdx[1], &cdx[2],
+ &WarpX::nox,&WarpX::noy,&WarpX::noz, &j_is_nodal,
+ &lvect,&WarpX::current_deposition_algo);
#ifdef WARPX_RZ
- warpx_current_deposition_rz_volume_scaling(
+ warpx_current_deposition_rz_volume_scaling(
jx_ptr, &ngJ, jxntot.getVect(),
jy_ptr, &ngJ, jyntot.getVect(),
jz_ptr, &ngJ, jzntot.getVect(),
&xyzmin[0], &dx[0]);
#endif
- }
BL_PROFILE_VAR_STOP(blp_pxr_cd);
@@ -565,7 +487,7 @@ WarpXParticleContainer::DepositCharge ( WarpXParIter& pti, RealVector& wp,
const std::array<Real, 3>& xyzmin = xyzmin_tile;
#ifdef AMREX_USE_GPU
- data_ptr = (*rhomf)[pti].dataPtr();
+ data_ptr = (*rhomf)[pti].dataPtr(icomp);
auto rholen = (*rhomf)[pti].length();
#else
tile_box.grow(ngRho);
@@ -598,9 +520,14 @@ WarpXParticleContainer::DepositCharge ( WarpXParIter& pti, RealVector& wp,
&ngRho, &ngRho, &ngRho,
&WarpX::nox,&WarpX::noy,&WarpX::noz,
&lvect, &WarpX::charge_deposition_algo);
+#ifdef WARPX_RZ
+ warpx_charge_deposition_rz_volume_scaling(
+ data_ptr, &ngRho, rholen.getVect(),
+ &xyzmin[0], &dx[0]);
+#endif
BL_PROFILE_VAR_STOP(blp_pxr_chd);
-#ifndef AMREX_USE_GPU
+#ifndef AMREX_USE_GPU
BL_PROFILE_VAR_START(blp_accumulate);
(*rhomf)[pti].atomicAdd(local_rho[thread_num], tile_box, tile_box, 0, icomp, 1);
@@ -617,7 +544,7 @@ WarpXParticleContainer::DepositCharge ( WarpXParIter& pti, RealVector& wp,
const std::array<Real,3>& cxyzmin_tile = WarpX::LowerCorner(ctilebox, lev-1);
#ifdef AMREX_USE_GPU
- data_ptr = (*crhomf)[pti].dataPtr();
+ data_ptr = (*crhomf)[pti].dataPtr(icomp);
auto rholen = (*crhomf)[pti].length();
#else
tile_box = amrex::convert(ctilebox, IntVect::TheUnitVector());
@@ -653,9 +580,14 @@ WarpXParticleContainer::DepositCharge ( WarpXParIter& pti, RealVector& wp,
&ngRho, &ngRho, &ngRho,
&WarpX::nox,&WarpX::noy,&WarpX::noz,
&lvect, &WarpX::charge_deposition_algo);
+#ifdef WARPX_RZ
+ warpx_charge_deposition_rz_volume_scaling(
+ data_ptr, &ngRho, rholen.getVect(),
+ &cxyzmin_tile[0], &cdx[0]);
+#endif
BL_PROFILE_VAR_STOP(blp_pxr_chd);
-#ifndef AMREX_USE_GPU
+#ifndef AMREX_USE_GPU
BL_PROFILE_VAR_START(blp_accumulate);
(*crhomf)[pti].atomicAdd(local_rho[thread_num], tile_box, tile_box, 0, icomp, 1);
@@ -680,7 +612,6 @@ WarpXParticleContainer::DepositCharge (Vector<std::unique_ptr<MultiFab> >& rho,
const auto& gm = m_gdb->Geom(lev);
const auto& ba = m_gdb->ParticleBoxArray(lev);
- const auto& dm = m_gdb->DistributionMap(lev);
const Real* dx = gm.CellSize();
const Real* plo = gm.ProbLo();
@@ -750,36 +681,36 @@ WarpXParticleContainer::GetChargeDensity (int lev, bool local)
#ifdef _OPENMP
#pragma omp parallel
-#endif
{
+#endif
Cuda::ManagedDeviceVector<Real> xp, yp, zp;
- FArrayBox local_rho;
+#ifdef _OPENMP
+ FArrayBox rho_loc;
+#endif
for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
{
- const Box& box = pti.validbox();
-
auto& wp = pti.GetAttribs(PIdx::w);
const long np = pti.numParticles();
pti.GetPosition(xp, yp, zp);
- const std::array<Real,3>& xyzmin_tile = WarpX::LowerCorner(pti.tilebox(), lev);
- const std::array<Real,3>& xyzmin_grid = WarpX::LowerCorner(box, lev);
-
// Data on the grid
Real* data_ptr;
FArrayBox& rhofab = (*rho)[pti];
#ifdef _OPENMP
+ const std::array<Real,3>& xyzmin_tile = WarpX::LowerCorner(pti.tilebox(), lev);
Box tile_box = convert(pti.tilebox(), IntVect::TheUnitVector());
const std::array<Real, 3>& xyzmin = xyzmin_tile;
tile_box.grow(ng);
- local_rho.resize(tile_box);
- local_rho = 0.0;
- data_ptr = local_rho.dataPtr();
- auto rholen = local_rho.length();
+ rho_loc.resize(tile_box);
+ rho_loc = 0.0;
+ data_ptr = rho_loc.dataPtr();
+ auto rholen = rho_loc.length();
#else
+ const Box& box = pti.validbox();
+ const std::array<Real,3>& xyzmin_grid = WarpX::LowerCorner(box, lev);
const std::array<Real, 3>& xyzmin = xyzmin_grid;
data_ptr = rhofab.dataPtr();
auto rholen = rhofab.length();
@@ -809,12 +740,17 @@ WarpXParticleContainer::GetChargeDensity (int lev, bool local)
&dx[0], &dx[1], &dx[2], &nx, &ny, &nz,
&nxg, &nyg, &nzg, &WarpX::nox,&WarpX::noy,&WarpX::noz,
&lvect, &WarpX::charge_deposition_algo);
+#ifdef WARPX_RZ
+ long ngRho = WarpX::nox;
+ warpx_charge_deposition_rz_volume_scaling(
+ data_ptr, &ngRho, rholen.getVect(),
+ &xyzmin[0], &dx[0]);
+#endif
#ifdef _OPENMP
- rhofab.atomicAdd(local_rho);
-#endif
+ rhofab.atomicAdd(rho_loc);
}
-
+#endif
}
if (!local) rho->SumBoundary(gm.periodicity());
@@ -964,8 +900,6 @@ void
WarpXParticleContainer::PushX (int lev, Real dt)
{
BL_PROFILE("WPC::PushX()");
- BL_PROFILE_VAR_NS("WPC::PushX::Copy", blp_copy);
- BL_PROFILE_VAR_NS("WPC:PushX::Push", blp_pxr_pp);
if (do_not_push) return;
@@ -975,47 +909,42 @@ WarpXParticleContainer::PushX (int lev, Real dt)
#pragma omp parallel
#endif
{
- Cuda::ManagedDeviceVector<Real> xp, yp, zp, giv;
for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
{
Real wt = amrex::second();
- auto& attribs = pti.GetAttribs();
-
- auto& uxp = attribs[PIdx::ux];
- auto& uyp = attribs[PIdx::uy];
- auto& uzp = attribs[PIdx::uz];
-
- const long np = pti.numParticles();
-
- giv.resize(np);
-
- //
- // copy data from particle container to temp arrays
- //
- BL_PROFILE_VAR_START(blp_copy);
- pti.GetPosition(xp, yp, zp);
- BL_PROFILE_VAR_STOP(blp_copy);
-
//
// Particle Push
//
- BL_PROFILE_VAR_START(blp_pxr_pp);
- warpx_particle_pusher_positions(&np,
- xp.dataPtr(),
- yp.dataPtr(),
- zp.dataPtr(),
- uxp.dataPtr(), uyp.dataPtr(), uzp.dataPtr(),
- giv.dataPtr(), &dt);
- BL_PROFILE_VAR_STOP(blp_pxr_pp);
-
- //
- // copy particle data back
- //
- BL_PROFILE_VAR_START(blp_copy);
- pti.SetPosition(xp, yp, zp);
- BL_PROFILE_VAR_STOP(blp_copy);
+ // Extract pointers to particle position and momenta, for this particle tile
+ // - positions are stored as an array of struct, in `ParticleType`
+ ParticleType * AMREX_RESTRICT pstructs = &(pti.GetArrayOfStructs()[0]);
+ // - momenta are stored as a struct of array, in `attribs`
+ auto& attribs = pti.GetAttribs();
+ Real* AMREX_RESTRICT ux = attribs[PIdx::ux].dataPtr();
+ Real* AMREX_RESTRICT uy = attribs[PIdx::uy].dataPtr();
+ Real* AMREX_RESTRICT uz = attribs[PIdx::uz].dataPtr();
+#ifdef WARPX_RZ
+ Real* AMREX_RESTRICT theta = attribs[PIdx::theta].dataPtr();
+#endif
+ // Loop over the particles and update their position
+ amrex::ParallelFor( pti.numParticles(),
+ [=] AMREX_GPU_DEVICE (long i) {
+ ParticleType& p = pstructs[i]; // Particle object that gets updated
+ Real x, y, z; // Temporary variables
+#ifndef WARPX_RZ
+ GetPosition( x, y, z, p ); // Initialize x, y, z
+ UpdatePosition( x, y, z, ux[i], uy[i], uz[i], dt);
+ SetPosition( p, x, y, z ); // Update the object p
+#else
+ // For WARPX_RZ, the particles are still pushed in 3D Cartesian
+ GetCartesianPositionFromCylindrical( x, y, z, p, theta[i] );
+ UpdatePosition( x, y, z, ux[i], uy[i], uz[i], dt);
+ SetCylindricalPositionFromCartesian( p, theta[i], x, y, z );
+#endif
+ }
+ );
if (cost) {
const Box& tbx = pti.tilebox();
@@ -1031,15 +960,15 @@ WarpXParticleContainer::PushX (int lev, Real dt)
}
// This function is called in Redistribute, just after locate
-void
-WarpXParticleContainer::particlePostLocate(ParticleType& p,
+void
+WarpXParticleContainer::particlePostLocate(ParticleType& p,
const ParticleLocData& pld,
const int lev)
{
// Tag particle if goes to higher level.
// It will be split later in the loop
- if (pld.m_lev == lev+1
- and p.m_idata.id != NoSplitParticleID
+ if (pld.m_lev == lev+1
+ and p.m_idata.id != NoSplitParticleID
and p.m_idata.id >= 0)
{
p.m_idata.id = DoSplitParticleID;
diff --git a/Source/Python/Make.package b/Source/Python/Make.package
index 71bd4ebe8..746257abf 100644
--- a/Source/Python/Make.package
+++ b/Source/Python/Make.package
@@ -1,7 +1,7 @@
-ifeq ($(USE_PYTHON_MAIN),TRUE)
- CEXE_sources += WarpXWrappers.cpp
- CEXE_headers += WarpXWrappers.h
-endif
+#ifeq ($(USE_PYTHON_MAIN),TRUE)
+# CEXE_sources += WarpXWrappers.cpp
+# CEXE_headers += WarpXWrappers.h
+#endif
CEXE_sources += WarpXWrappers.cpp
CEXE_sources += WarpX_py.cpp
CEXE_headers += WarpXWrappers.h
diff --git a/Source/Python/WarpXWrappers.cpp b/Source/Python/WarpXWrappers.cpp
index 16d7cd841..3c1a930b3 100644
--- a/Source/Python/WarpXWrappers.cpp
+++ b/Source/Python/WarpXWrappers.cpp
@@ -89,7 +89,7 @@ extern "C"
void amrex_finalize (int finalize_mpi)
{
- amrex::Finalize(finalize_mpi);
+ amrex::Finalize();
}
void warpx_init ()
diff --git a/Source/Utils/Make.package b/Source/Utils/Make.package
index d8e2d2dab..cd335dbcf 100644
--- a/Source/Utils/Make.package
+++ b/Source/Utils/Make.package
@@ -4,6 +4,9 @@ CEXE_sources += WarpXTagging.cpp
CEXE_sources += WarpXUtil.cpp
CEXE_headers += WarpXConst.H
CEXE_headers += WarpXUtil.H
+CEXE_headers += WarpXAlgorithmSelection.H
+CEXE_sources += WarpXAlgorithmSelection.cpp
+CEXE_headers += NCIGodfreyTables.H
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Utils
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Utils
diff --git a/Source/Utils/NCIGodfreyTables.H b/Source/Utils/NCIGodfreyTables.H
new file mode 100644
index 000000000..8cb105aa0
--- /dev/null
+++ b/Source/Utils/NCIGodfreyTables.H
@@ -0,0 +1,224 @@
+#include <AMReX_AmrCore.H>
+
+#ifndef WARPX_GODFREY_COEFF_TABLE_H_
+#define WARPX_GODFREY_COEFF_TABLE_H_
+
+// Table width. This is related to the stencil length
+const int tab_width = 4;
+// table length. Each line correspond to 1 value of cdtodz
+// (here 101 values).
+const int tab_length = 101;
+
+// Table of coefficient for Ex, Ey abd Bz
+// We typically interpolate between two lines
+const amrex::Real table_nci_godfrey_Ex_Ey_Bz[tab_length][tab_width]{
+ -2.47536,2.04288,-0.598163,0.0314711,
+ -2.47536,2.04288,-0.598163,0.0314711,
+ -2.47545,2.04309,-0.598307,0.0315029,
+ -2.4756,2.04342,-0.598549,0.0315558,
+ -2.47581,2.0439,-0.598886,0.0316298,
+ -2.47608,2.0445,-0.59932,0.031725,
+ -2.47641,2.04525,-0.59985,0.0318412,
+ -2.4768,2.04612,-0.600477,0.0319785,
+ -2.47725,2.04714,-0.6012,0.0321367,
+ -2.47776,2.04829,-0.602019,0.0323158,
+ -2.47833,2.04957,-0.602934,0.0325158,
+ -2.47896,2.05099,-0.603944,0.0327364,
+ -2.47965,2.05254,-0.605051,0.0329777,
+ -2.4804,2.05423,-0.606253,0.0332396,
+ -2.48121,2.05606,-0.60755,0.0335218,
+ -2.48208,2.05802,-0.608942,0.0338243,
+ -2.48301,2.06012,-0.610429,0.0341469,
+ -2.48401,2.06235,-0.61201,0.0344895,
+ -2.48506,2.06471,-0.613685,0.0348519,
+ -2.48618,2.06721,-0.615453,0.0352339,
+ -2.48735,2.06984,-0.617314,0.0356353,
+ -2.48859,2.07261,-0.619268,0.0360559,
+ -2.48988,2.0755,-0.621312,0.0364954,
+ -2.49123,2.07853,-0.623447,0.0369536,
+ -2.49265,2.08169,-0.625672,0.0374302,
+ -2.49412,2.08498,-0.627986,0.0379248,
+ -2.49565,2.0884,-0.630386,0.0384372,
+ -2.49724,2.09194,-0.632873,0.0389669,
+ -2.49888,2.09561,-0.635443,0.0395135,
+ -2.50058,2.09939,-0.638096,0.0400766,
+ -2.50234,2.1033,-0.640829,0.0406557,
+ -2.50415,2.10732,-0.64364,0.0412502,
+ -2.50601,2.11145,-0.646526,0.0418594,
+ -2.50791,2.1157,-0.649485,0.0424828,
+ -2.50987,2.12004,-0.652512,0.0431196,
+ -2.51187,2.12448,-0.655604,0.0437688,
+ -2.51392,2.12901,-0.658756,0.0444297,
+ -2.516,2.13363,-0.661964,0.0451011,
+ -2.51812,2.13832,-0.665221,0.0457818,
+ -2.52027,2.14308,-0.668521,0.0464705,
+ -2.52244,2.14789,-0.671856,0.0471658,
+ -2.52464,2.15274,-0.675218,0.0478658,
+ -2.52684,2.15762,-0.678596,0.0485687,
+ -2.52906,2.16251,-0.68198,0.0492723,
+ -2.53126,2.16738,-0.685355,0.049974,
+ -2.53345,2.17222,-0.688706,0.0506708,
+ -2.53561,2.177,-0.692015,0.0513594,
+ -2.53773,2.18168,-0.69526,0.0520359,
+ -2.53978,2.18623,-0.698416,0.0526955,
+ -2.54175,2.19059,-0.701452,0.053333,
+ -2.5436,2.19471,-0.704331,0.0539417,
+ -2.54531,2.19852,-0.70701,0.0545141,
+ -2.54683,2.20193,-0.709433,0.0550409,
+ -2.5481,2.20483,-0.711533,0.0555106,
+ -2.54906,2.20709,-0.713224,0.0559094,
+ -2.54963,2.20852,-0.714397,0.0562198,
+ -2.54968,2.20888,-0.714907,0.0564196,
+ -2.54905,2.20785,-0.714562,0.0564797,
+ -2.54751,2.20496,-0.713094,0.0563618,
+ -2.54472,2.19955,-0.710118,0.0560124,
+ -2.54014,2.19058,-0.705048,0.0553544,
+ -2.53286,2.1763,-0.69693,0.0542684,
+ -2.52115,2.15344,-0.684027,0.05255,
+ -2.50098,2.11466,-0.66255,0.0497817,
+ -2.45797,2.03459,-0.620099,0.0446889,
+ -2.28371,1.72254,-0.465905,0.0283268,
+ -2.4885,2.04899,-0.599292,0.0390466,
+ -2.1433,1.36735,-0.220924,-0.00215633,
+ -2.4943,2.07019,-0.610552,0.035166,
+ -2.84529,2.77303,-1.00018,0.0724884,
+ -2.72242,2.51888,-0.847226,0.0509964,
+ -2.65633,2.3744,-0.750392,0.0326366,
+ -2.59601,2.23412,-0.646421,0.00868027,
+ -2.51477,2.0369,-0.491066,-0.0306397,
+ -2.35935,1.65155,-0.178971,-0.112713,
+ -1.84315,0.361693,0.876104,-0.393844,
+ -2.65422,2.39262,-0.789663,0.0516265,
+ -3.46529,4.42354,-2.45543,0.497097,
+ -3.15747,3.65311,-1.824,0.328432,
+ -3.04694,3.37613,-1.59668,0.267631,
+ -2.99205,3.23814,-1.48302,0.237103,
+ -2.96075,3.15894,-1.41733,0.219317,
+ -2.94172,3.11028,-1.37649,0.20811,
+ -2.92994,3.07962,-1.35025,0.200755,
+ -2.92283,3.06054,-1.33338,0.195859,
+ -2.91894,3.04938,-1.3229,0.192637,
+ -2.91736,3.04394,-1.31702,0.190612,
+ -2.91753,3.04278,-1.31456,0.189477,
+ -2.91905,3.04494,-1.31475,0.189026,
+ -2.92165,3.04973,-1.31705,0.189117,
+ -2.92512,3.05667,-1.32105,0.189646,
+ -2.92933,3.06539,-1.32646,0.190538,
+ -2.93416,3.07562,-1.33308,0.191735,
+ -2.93952,3.08715,-1.34072,0.193194,
+ -2.94535,3.09982,-1.34925,0.194881,
+ -2.95159,3.11349,-1.35858,0.196769,
+ -2.9582,3.12805,-1.36861,0.198838,
+ -2.96514,3.14342,-1.37929,0.201068,
+ -2.97239,3.15953,-1.39055,0.203448,
+ -2.97991,3.17632,-1.40234,0.205964,
+ -2.98769,3.19374,-1.41463,0.208607
+ };
+
+// Table of coefficient for Bx, By and Ez
+// We typically interpolate between two lines
+const amrex::Real table_nci_godfrey_Bx_By_Ez[tab_length][tab_width]{
+ -2.80862,2.80104,-1.14615,0.154077,
+ -2.80862,2.80104,-1.14615,0.154077,
+ -2.80851,2.80078,-1.14595,0.154027,
+ -2.80832,2.80034,-1.14561,0.153945,
+ -2.80807,2.79973,-1.14514,0.153829,
+ -2.80774,2.79894,-1.14454,0.15368,
+ -2.80733,2.79798,-1.1438,0.153498,
+ -2.80685,2.79685,-1.14292,0.153284,
+ -2.8063,2.79554,-1.14192,0.153036,
+ -2.80568,2.79405,-1.14077,0.152756,
+ -2.80498,2.79239,-1.1395,0.152443,
+ -2.80421,2.79056,-1.13809,0.152098,
+ -2.80337,2.78856,-1.13656,0.151721,
+ -2.80246,2.78638,-1.13488,0.151312,
+ -2.80147,2.78404,-1.13308,0.150871,
+ -2.80041,2.78152,-1.13115,0.150397,
+ -2.79927,2.77882,-1.12908,0.149893,
+ -2.79807,2.77596,-1.12689,0.149356,
+ -2.79679,2.77292,-1.12456,0.148789,
+ -2.79543,2.76972,-1.12211,0.14819,
+ -2.79401,2.76634,-1.11953,0.14756,
+ -2.79251,2.76279,-1.11681,0.1469,
+ -2.79094,2.75907,-1.11397,0.146208,
+ -2.78929,2.75517,-1.111,0.145486,
+ -2.78757,2.7511,-1.10789,0.144733,
+ -2.78578,2.74686,-1.10466,0.14395,
+ -2.78391,2.74245,-1.1013,0.143137,
+ -2.78196,2.73786,-1.09781,0.142293,
+ -2.77994,2.73309,-1.09419,0.141419,
+ -2.77784,2.72814,-1.09043,0.140514,
+ -2.77566,2.72301,-1.08654,0.139578,
+ -2.7734,2.7177,-1.08252,0.138612,
+ -2.77106,2.7122,-1.07836,0.137614,
+ -2.76864,2.70651,-1.07406,0.136586,
+ -2.76613,2.70062,-1.06962,0.135525,
+ -2.76353,2.69453,-1.06503,0.134432,
+ -2.76084,2.68824,-1.0603,0.133307,
+ -2.75806,2.68173,-1.05541,0.132148,
+ -2.75518,2.675,-1.05037,0.130954,
+ -2.75219,2.66804,-1.04516,0.129725,
+ -2.7491,2.66084,-1.03978,0.12846,
+ -2.7459,2.65339,-1.03423,0.127156,
+ -2.74257,2.64566,-1.02848,0.125813,
+ -2.73912,2.63765,-1.02254,0.124428,
+ -2.73552,2.62934,-1.01638,0.122999,
+ -2.73178,2.62069,-1.01,0.121523,
+ -2.72787,2.61169,-1.00337,0.119996,
+ -2.72379,2.6023,-0.996479,0.118417,
+ -2.71951,2.59248,-0.989294,0.116778,
+ -2.71501,2.58218,-0.981786,0.115076,
+ -2.71026,2.57135,-0.97392,0.113303,
+ -2.70524,2.55991,-0.965651,0.111453,
+ -2.69989,2.54778,-0.956922,0.109514,
+ -2.69416,2.53484,-0.947666,0.107476,
+ -2.68799,2.52096,-0.937795,0.105324,
+ -2.68129,2.50596,-0.927197,0.103039,
+ -2.67394,2.48959,-0.915724,0.100597,
+ -2.66578,2.47153,-0.903179,0.097968,
+ -2.65657,2.4513,-0.889283,0.0951084,
+ -2.64598,2.42824,-0.873638,0.0919592,
+ -2.63347,2.40127,-0.855632,0.0884325,
+ -2.61813,2.36864,-0.834261,0.0843898,
+ -2.59821,2.32701,-0.807691,0.0795876,
+ -2.56971,2.26887,-0.77188,0.0735132,
+ -2.51823,2.16823,-0.713448,0.0645399,
+ -2.33537,1.8294,-0.533852,0.0409941,
+ -2.53143,2.14818,-0.670502,0.053982,
+ -2.17737,1.43641,-0.259095,0.00101255,
+ -2.51929,2.12931,-0.654743,0.0452381,
+ -2.86122,2.82221,-1.05039,0.0894636,
+ -2.72908,2.54506,-0.87834,0.0626188,
+ -2.6536,2.37954,-0.7665,0.0409117,
+ -2.58374,2.21923,-0.649738,0.0146791,
+ -2.49284,2.00346,-0.48457,-0.0255348,
+ -2.32762,1.60337,-0.1698,-0.105287,
+ -1.80149,0.316787,0.855414,-0.369652,
+ -2.60242,2.28418,-0.721378,0.040091,
+ -3.40335,4.25157,-2.29817,0.449834,
+ -3.0852,3.47341,-1.67791,0.28982,
+ -2.9642,3.17856,-1.44399,0.229852,
+ -2.89872,3.01966,-1.31861,0.197945,
+ -2.85668,2.91811,-1.23894,0.17783,
+ -2.82679,2.84621,-1.18287,0.163785,
+ -2.80401,2.79167,-1.14058,0.153278,
+ -2.78577,2.74819,-1.10706,0.145015,
+ -2.77061,2.7122,-1.07946,0.138267,
+ -2.75764,2.68152,-1.05606,0.132589,
+ -2.74627,2.65475,-1.03575,0.127695,
+ -2.73612,2.63093,-1.01777,0.123395,
+ -2.72692,2.6094,-1.00159,0.119553,
+ -2.71846,2.58968,-0.986841,0.116074,
+ -2.71061,2.57142,-0.973239,0.112887,
+ -2.70323,2.55434,-0.960573,0.109937,
+ -2.69626,2.53824,-0.948678,0.107185,
+ -2.68962,2.52294,-0.937429,0.104598,
+ -2.68327,2.50833,-0.926722,0.102151,
+ -2.67714,2.4943,-0.916477,0.0998223,
+ -2.67122,2.48076,-0.906627,0.0975966,
+ -2.66546,2.46764,-0.897118,0.0954599,
+ -2.65985,2.45489,-0.887903,0.0934011,
+ -2.65437,2.44244,-0.878945,0.0914107
+ };
+
+#endif // #ifndef WARPX_GODFREY_COEFF_TABLE_H_
diff --git a/Source/Utils/WarpXAlgorithmSelection.H b/Source/Utils/WarpXAlgorithmSelection.H
new file mode 100644
index 000000000..3fb23698a
--- /dev/null
+++ b/Source/Utils/WarpXAlgorithmSelection.H
@@ -0,0 +1,57 @@
+#ifndef UTILS_WARPXALGORITHMSELECTION_H_
+#define UTILS_WARPXALGORITHMSELECTION_H_
+
+#include <AMReX_ParmParse.H>
+#include <string>
+
+struct MaxwellSolverAlgo {
+ // These numbers corresponds to the algorithm code in WarpX's
+ // `warpx_push_bvec` and `warpx_push_evec_f`
+ enum {
+ Yee = 0,
+ CKC = 1
+ };
+};
+
+struct ParticlePusherAlgo {
+ // These numbers correspond to the algorithm code in WarpX's
+ // `warpx_particle_pusher`
+ enum {
+ Boris = 0,
+ Vay = 1
+ };
+};
+
+struct CurrentDepositionAlgo {
+ enum {
+ // These numbers corresponds to the algorithm code in PICSAR's
+ // `depose_jxjyjz_generic` and `depose_jxjyjz_generic_2d`
+ Direct = 3,
+ DirectVectorized = 2,
+ EsirkepovNonOptimized = 1,
+ Esirkepov = 0
+ };
+};
+
+struct ChargeDepositionAlgo {
+ // These numbers corresponds to the algorithm code in WarpX's
+ // `warpx_charge_deposition` function
+ enum {
+ Vectorized = 0,
+ Standard = 1
+ };
+};
+
+struct GatheringAlgo {
+ // These numbers corresponds to the algorithm code in PICSAR's
+ // `geteb3d_energy_conserving_generic` function
+ enum {
+ Vectorized = 0,
+ Standard = 1
+ };
+};
+
+int
+GetAlgorithmInteger( amrex::ParmParse& pp, const char* pp_search_key );
+
+#endif // UTILS_WARPXALGORITHMSELECTION_H_
diff --git a/Source/Utils/WarpXAlgorithmSelection.cpp b/Source/Utils/WarpXAlgorithmSelection.cpp
new file mode 100644
index 000000000..2c8038ccd
--- /dev/null
+++ b/Source/Utils/WarpXAlgorithmSelection.cpp
@@ -0,0 +1,95 @@
+#include <WarpXAlgorithmSelection.H>
+#include <map>
+#include <algorithm>
+#include <cstring>
+
+// Define dictionary with correspondance between user-input strings,
+// and corresponding integer for use inside the code (e.g. in PICSAR).
+
+const std::map<std::string, int> maxwell_solver_algo_to_int = {
+ {"yee", MaxwellSolverAlgo::Yee },
+#ifndef WARPX_RZ // Not available in RZ
+ {"ckc", MaxwellSolverAlgo::CKC },
+#endif
+ {"default", MaxwellSolverAlgo::Yee }
+};
+
+const std::map<std::string, int> particle_pusher_algo_to_int = {
+ {"boris", ParticlePusherAlgo::Boris },
+ {"vay", ParticlePusherAlgo::Vay },
+ {"default", ParticlePusherAlgo::Boris }
+};
+
+const std::map<std::string, int> current_deposition_algo_to_int = {
+ {"esirkepov", CurrentDepositionAlgo::Esirkepov },
+ {"direct", CurrentDepositionAlgo::Direct },
+#if (!defined AMREX_USE_GPU)&&(AMREX_SPACEDIM == 3) // Only available on CPU and 3D
+ {"direct-vectorized", CurrentDepositionAlgo::DirectVectorized },
+#endif
+ {"default", CurrentDepositionAlgo::Esirkepov }
+};
+
+const std::map<std::string, int> charge_deposition_algo_to_int = {
+ {"standard", ChargeDepositionAlgo::Standard },
+#if (!defined AMREX_USE_GPU)&&(AMREX_SPACEDIM == 3) // Only available on CPU and 3D
+ {"vectorized", ChargeDepositionAlgo::Vectorized },
+ {"default", ChargeDepositionAlgo::Vectorized }
+#else
+ {"default", ChargeDepositionAlgo::Standard }
+#endif
+};
+
+const std::map<std::string, int> gathering_algo_to_int = {
+ {"standard", GatheringAlgo::Standard },
+#ifndef AMREX_USE_GPU // Only available on CPU
+ {"vectorized", GatheringAlgo::Vectorized },
+ {"default", GatheringAlgo::Vectorized }
+#else
+ {"default", GatheringAlgo::Standard }
+#endif
+};
+
+
+int
+GetAlgorithmInteger( amrex::ParmParse& pp, const char* pp_search_key ){
+
+ // Read user input ; use "default" if it is not found
+ std::string algo = "default";
+ pp.query( pp_search_key, algo );
+ // Convert to lower case
+ std::transform(algo.begin(), algo.end(), algo.begin(), ::tolower);
+
+ // Pick the right dictionary
+ std::map<std::string, int> algo_to_int;
+ if (0 == std::strcmp(pp_search_key, "maxwell_fdtd_solver")) {
+ algo_to_int = maxwell_solver_algo_to_int;
+ } else if (0 == std::strcmp(pp_search_key, "particle_pusher")) {
+ algo_to_int = particle_pusher_algo_to_int;
+ } else if (0 == std::strcmp(pp_search_key, "current_deposition")) {
+ algo_to_int = current_deposition_algo_to_int;
+ } else if (0 == std::strcmp(pp_search_key, "charge_deposition")) {
+ algo_to_int = charge_deposition_algo_to_int;
+ } else if (0 == std::strcmp(pp_search_key, "field_gathering")) {
+ algo_to_int = gathering_algo_to_int;
+ } else {
+ std::string pp_search_string = pp_search_key;
+ amrex::Abort("Unknown algorithm type: " + pp_search_string);
+ }
+
+ // Check if the user-input is a valid key for the dictionary
+ if (algo_to_int.count(algo) == 0){
+ // Not a valid key ; print error message
+ std::string pp_search_string = pp_search_key;
+ std::string error_message = "Invalid string for algo." + pp_search_string
+ + ": " + algo + ".\nThe valid values are:\n";
+ for ( const auto &valid_pair : algo_to_int ) {
+ if (valid_pair.first != "default"){
+ error_message += " - " + valid_pair.first + "\n";
+ }
+ }
+ amrex::Abort(error_message);
+ }
+
+ // If the input is a valid key, return the value
+ return algo_to_int[algo];
+}
diff --git a/Source/Utils/WarpXMovingWindow.cpp b/Source/Utils/WarpXMovingWindow.cpp
index 05e171f22..ae781f9aa 100644
--- a/Source/Utils/WarpXMovingWindow.cpp
+++ b/Source/Utils/WarpXMovingWindow.cpp
@@ -5,21 +5,21 @@
using namespace amrex;
void
-WarpX::UpdatePlasmaInjectionPosition (Real dt)
+WarpX::UpdatePlasmaInjectionPosition (Real a_dt)
{
int dir = moving_window_dir;
// Continuously inject plasma in new cells (by default only on level 0)
- if (WarpX::do_plasma_injection and (WarpX::gamma_boost > 1)){
+ if (WarpX::warpx_do_continuous_injection and (WarpX::gamma_boost > 1)){
// In boosted-frame simulations, the plasma has moved since the last
// call to this function, and injection position needs to be updated
current_injection_position -= WarpX::beta_boost *
#if ( AMREX_SPACEDIM == 3 )
- WarpX::boost_direction[dir] * PhysConst::c * dt;
+ WarpX::boost_direction[dir] * PhysConst::c * a_dt;
#elif ( AMREX_SPACEDIM == 2 )
// In 2D, dir=0 corresponds to x and dir=1 corresponds to z
// This needs to be converted in order to index `boost_direction`
// which has 3 components, for both 2D and 3D simulations.
- WarpX::boost_direction[2*dir] * PhysConst::c * dt;
+ WarpX::boost_direction[2*dir] * PhysConst::c * a_dt;
#endif
}
}
@@ -33,7 +33,16 @@ WarpX::MoveWindow (bool move_j)
// and of the plasma injection
moving_window_x += moving_window_v * dt[0];
int dir = moving_window_dir;
+
+ // Update warpx.current_injection_position
+ // PhysicalParticleContainer uses this injection position
UpdatePlasmaInjectionPosition( dt[0] );
+ if (WarpX::warpx_do_continuous_injection){
+ // Update injection position for WarpXParticleContainer in mypc.
+ // Nothing to do for PhysicalParticleContainers
+ // For LaserParticleContainer, need to update the antenna position.
+ mypc->UpdateContinuousInjectionPosition( dt[0] );
+ }
// compute the number of cells to shift on the base level
Real new_lo[AMREX_SPACEDIM];
@@ -53,8 +62,28 @@ WarpX::MoveWindow (bool move_j)
}
new_lo[dir] = current_lo[dir] + num_shift_base * cdx[dir];
new_hi[dir] = current_hi[dir] + num_shift_base * cdx[dir];
- RealBox new_box(new_lo, new_hi);
- Geometry::ProbDomain(new_box);
+
+ ResetProbDomain(RealBox(new_lo, new_hi));
+
+ // Moving slice coordinates - lo and hi - with moving window //
+ // slice box is modified only if slice diagnostics is initialized in input //
+ if ( slice_plot_int > 0 )
+ {
+ Real new_slice_lo[AMREX_SPACEDIM];
+ Real new_slice_hi[AMREX_SPACEDIM];
+ const Real* current_slice_lo = slice_realbox.lo();
+ const Real* current_slice_hi = slice_realbox.hi();
+ for ( int i = 0; i < AMREX_SPACEDIM; i++) {
+ new_slice_lo[i] = current_slice_lo[i];
+ new_slice_hi[i] = current_slice_hi[i];
+ }
+ int num_shift_base_slice = static_cast<int> ((moving_window_x -
+ current_slice_lo[dir]) / cdx[dir]);
+ new_slice_lo[dir] = current_slice_lo[dir] + num_shift_base_slice*cdx[dir];
+ new_slice_hi[dir] = current_slice_hi[dir] + num_shift_base_slice*cdx[dir];
+ slice_realbox.setLo(new_slice_lo);
+ slice_realbox.setHi(new_slice_hi);
+ }
int num_shift = num_shift_base;
int num_shift_crse = num_shift;
@@ -134,7 +163,7 @@ WarpX::MoveWindow (bool move_j)
}
// Continuously inject plasma in new cells (by default only on level 0)
- if (WarpX::do_plasma_injection) {
+ if (WarpX::warpx_do_continuous_injection) {
const int lev = 0;
@@ -162,15 +191,11 @@ WarpX::MoveWindow (bool move_j)
particleBox.setLo( dir, new_injection_position );
particleBox.setHi( dir, current_injection_position );
}
- // Perform the injection of new particles in particleBox
+
if (particleBox.ok() and (current_injection_position != new_injection_position)){
- for (int i = 0; i < num_injected_species; ++i) {
- int ispecies = injected_plasma_species[i];
- WarpXParticleContainer& pc = mypc->GetParticleContainer(ispecies);
- auto& ppc = dynamic_cast<PhysicalParticleContainer&>(pc);
- ppc.AddPlasma(lev, particleBox);
- }
- // Update the injection position
+ // Performs continuous injection of all WarpXParticleContainer
+ // in mypc.
+ mypc->ContinuousInjection(particleBox);
current_injection_position = new_injection_position;
}
}
@@ -249,3 +274,14 @@ WarpX::shiftMF (MultiFab& mf, const Geometry& geom, int num_shift, int dir)
});
}
}
+
+void
+WarpX::ResetProbDomain (const RealBox& rb)
+{
+ Geometry::ResetDefaultProbDomain(rb);
+ for (int lev = 0; lev <= max_level; ++lev) {
+ Geometry g = Geom(lev);
+ g.ProbDomain(rb);
+ SetGeometry(lev, g);
+ }
+}
diff --git a/Source/Utils/WarpXTagging.cpp b/Source/Utils/WarpXTagging.cpp
index 21acbefdc..8ea3211a3 100644
--- a/Source/Utils/WarpXTagging.cpp
+++ b/Source/Utils/WarpXTagging.cpp
@@ -9,7 +9,7 @@ using namespace amrex;
void
WarpX::ErrorEst (int lev, TagBoxArray& tags, Real time, int /*ngrow*/)
{
- const Real* problo = Geometry::ProbLo();
+ const Real* problo = Geom(lev).ProbLo();
const Real* dx = Geom(lev).CellSize();
#ifdef _OPENMP
diff --git a/Source/Utils/WarpXUtil.H b/Source/Utils/WarpXUtil.H
index a973c2283..39fded8e8 100644
--- a/Source/Utils/WarpXUtil.H
+++ b/Source/Utils/WarpXUtil.H
@@ -1,7 +1,11 @@
#include <AMReX_REAL.H>
#include <AMReX_Vector.H>
+#include <AMReX_MultiFab.H>
void ReadBoostedFrameParameters(amrex::Real& gamma_boost, amrex::Real& beta_boost,
amrex::Vector<int>& boost_direction);
void ConvertLabParamsToBoost();
+
+void NullifyMF(amrex::MultiFab& mf, int lev, amrex::Real zmin,
+ amrex::Real zmax);
diff --git a/Source/Utils/WarpXUtil.cpp b/Source/Utils/WarpXUtil.cpp
index 4a884330a..a5ea6d75a 100644
--- a/Source/Utils/WarpXUtil.cpp
+++ b/Source/Utils/WarpXUtil.cpp
@@ -3,6 +3,7 @@
#include <WarpXUtil.H>
#include <WarpXConst.H>
#include <AMReX_ParmParse.H>
+#include <WarpX.H>
using namespace amrex;
@@ -95,3 +96,43 @@ void ConvertLabParamsToBoost()
pp_wpx.addarr("fine_tag_hi", fine_tag_hi);
}
}
+
+/* \brief Function that sets the value of MultiFab MF to zero for z between
+ * zmin and zmax.
+ */
+void NullifyMF(amrex::MultiFab& mf, int lev, amrex::Real zmin, amrex::Real zmax){
+ BL_PROFILE("WarpX::NullifyMF()");
+#ifdef _OPENMP
+#pragma omp parallel if (Gpu::notInLaunchRegion())
+#endif
+ for(amrex::MFIter mfi(mf, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi){
+ const amrex::Box& bx = mfi.tilebox();
+ // Get box lower and upper physical z bound, and dz
+ const amrex::Real zmin_box = WarpX::LowerCorner(bx, lev)[2];
+ const amrex::Real zmax_box = WarpX::UpperCorner(bx, lev)[2];
+ amrex::Real dz = WarpX::CellSize(lev)[2];
+ // Get box lower index in the z direction
+#if (AMREX_SPACEDIM==3)
+ const int lo_ind = bx.loVect()[2];
+#else
+ const int lo_ind = bx.loVect()[1];
+#endif
+ // Check if box intersect with [zmin, zmax]
+ if ( (zmax>zmin_box && zmin<=zmax_box) ){
+ Array4<Real> arr = mf[mfi].array();
+ // Set field to 0 between zmin and zmax
+ ParallelFor(bx,
+ [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept{
+#if (AMREX_SPACEDIM==3)
+ const Real z_gridpoint = zmin_box+(k-lo_ind)*dz;
+#else
+ const Real z_gridpoint = zmin_box+(j-lo_ind)*dz;
+#endif
+ if ( (z_gridpoint >= zmin) && (z_gridpoint < zmax) ) {
+ arr(i,j,k) = 0.;
+ };
+ }
+ );
+ }
+ }
+}
diff --git a/Source/WarpX.H b/Source/WarpX.H
index d21e36b40..2580c5320 100644
--- a/Source/WarpX.H
+++ b/Source/WarpX.H
@@ -23,6 +23,7 @@
#include <PML.H>
#include <BoostedFrameDiagnostic.H>
#include <BilinearFilter.H>
+#include <NCIGodfreyFilter.H>
#ifdef WARPX_USE_PSATD
#include <fftw3.h>
@@ -94,12 +95,12 @@ public:
static bool use_fdtd_nci_corr;
static int l_lower_order_in_v;
- static bool use_laser;
static bool use_filter;
static bool serialize_ics;
// Back transformation diagnostic
static bool do_boosted_frame_diagnostic;
+ static std::string lab_data_directory;
static int num_snapshots_lab;
static amrex::Real dt_snapshots_lab;
static bool do_boosted_frame_fields;
@@ -109,6 +110,8 @@ public:
static amrex::Real gamma_boost;
static amrex::Real beta_boost;
static amrex::Vector<int> boost_direction;
+ static amrex::Real zmax_plasma_to_compute_max_step;
+ static int do_compute_max_step_from_zmax;
static bool do_dynamic_scheduling;
static bool refine_plasma;
@@ -144,11 +147,24 @@ public:
static amrex::IntVect filter_npass_each_dir;
BilinearFilter bilinear_filter;
+ amrex::Vector< std::unique_ptr<NCIGodfreyFilter> > nci_godfrey_filter_exeybz;
+ amrex::Vector< std::unique_ptr<NCIGodfreyFilter> > nci_godfrey_filter_bxbyez;
+
+ static int num_mirrors;
+ amrex::Vector<amrex::Real> mirror_z;
+ amrex::Vector<amrex::Real> mirror_z_width;
+ amrex::Vector<int> mirror_z_npoints;
+
+ void applyMirrors(amrex::Real time);
void ComputeDt ();
+ // Compute max_step automatically for simulations in a boosted frame.
+ void computeMaxStepBoostAccelerator(amrex::Geometry geom);
int MoveWindow (bool move_j);
void UpdatePlasmaInjectionPosition (amrex::Real dt);
+ void ResetProbDomain (const amrex::RealBox& rb);
+
void EvolveE ( amrex::Real dt);
void EvolveE (int lev, amrex::Real dt);
void EvolveB ( amrex::Real dt);
@@ -229,6 +245,12 @@ public:
static int do_moving_window;
static int moving_window_dir;
+ // slice generation //
+ void InitializeSliceMultiFabs ();
+ void SliceGenerationForDiagnostics ();
+ void WriteSlicePlotFile () const;
+ void ClearSliceMultiFabs ();
+
protected:
//! Tagging cells for refinement
@@ -470,10 +492,10 @@ private:
amrex::Real current_injection_position = 0;
// Plasma injection parameters
- int do_plasma_injection = 0;
+ int warpx_do_continuous_injection = 0;
int num_injected_species = -1;
amrex::Vector<int> injected_plasma_species;
-
+
int do_electrostatic = 0;
int n_buffer = 4;
amrex::Real const_dt = 0.5e-11;
@@ -509,6 +531,9 @@ private:
bool dump_plotfiles = true;
bool dump_openpmd = false;
#endif
+ bool plot_E_field = true;
+ bool plot_B_field = true;
+ bool plot_J_field = true;
bool plot_part_per_cell = true;
bool plot_part_per_grid = false;
bool plot_part_per_proc = false;
@@ -537,8 +562,16 @@ private:
bool is_synchronized = true;
- amrex::Vector<std::string> particle_plot_vars;
- amrex::Vector<int> particle_plot_flags;
+ //Slice Parameters
+ int slice_max_grid_size;
+ int slice_plot_int = -1;
+ amrex::RealBox slice_realbox;
+ amrex::IntVect slice_cr_ratio;
+ amrex::Vector< std::unique_ptr<amrex::MultiFab> > F_slice;
+ amrex::Vector< std::unique_ptr<amrex::MultiFab> > rho_slice;
+ amrex::Vector<std::array< std::unique_ptr<amrex::MultiFab>, 3 > > current_slice;
+ amrex::Vector<std::array< std::unique_ptr<amrex::MultiFab>, 3 > > Efield_slice;
+ amrex::Vector<std::array< std::unique_ptr<amrex::MultiFab>, 3 > > Bfield_slice;
#ifdef WARPX_USE_PSATD
// Store fields in real space on the dual grid (i.e. the grid for the FFT push of the fields)
diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp
index 98d6edadf..c2cf97f30 100644
--- a/Source/WarpX.cpp
+++ b/Source/WarpX.cpp
@@ -17,6 +17,7 @@
#include <WarpXConst.H>
#include <WarpXWrappers.h>
#include <WarpXUtil.H>
+#include <WarpXAlgorithmSelection.H>
#ifdef BL_USE_SENSEI_INSITU
#include <AMReX_AmrMeshInSituBridge.H>
@@ -32,12 +33,14 @@ int WarpX::moving_window_dir = -1;
Real WarpX::gamma_boost = 1.;
Real WarpX::beta_boost = 0.;
Vector<int> WarpX::boost_direction = {0,0,0};
+int WarpX::do_compute_max_step_from_zmax = 0;
+Real WarpX::zmax_plasma_to_compute_max_step = 0.;
-long WarpX::current_deposition_algo = 3;
-long WarpX::charge_deposition_algo = 0;
-long WarpX::field_gathering_algo = 1;
-long WarpX::particle_pusher_algo = 0;
-int WarpX::maxwell_fdtd_solver_id = 0;
+long WarpX::current_deposition_algo;
+long WarpX::charge_deposition_algo;
+long WarpX::field_gathering_algo;
+long WarpX::particle_pusher_algo;
+int WarpX::maxwell_fdtd_solver_id;
long WarpX::nox = 1;
long WarpX::noy = 1;
@@ -46,14 +49,16 @@ long WarpX::noz = 1;
bool WarpX::use_fdtd_nci_corr = false;
int WarpX::l_lower_order_in_v = true;
-bool WarpX::use_laser = false;
bool WarpX::use_filter = false;
bool WarpX::serialize_ics = false;
bool WarpX::refine_plasma = false;
+int WarpX::num_mirrors = 0;
+
int WarpX::sort_int = -1;
bool WarpX::do_boosted_frame_diagnostic = false;
+std::string WarpX::lab_data_directory = "lab_frame_data";
int WarpX::num_snapshots_lab = std::numeric_limits<int>::lowest();
Real WarpX::dt_snapshots_lab = std::numeric_limits<Real>::lowest();
bool WarpX::do_boosted_frame_fields = true;
@@ -144,15 +149,17 @@ WarpX::WarpX ()
// Particle Container
mypc = std::unique_ptr<MultiParticleContainer> (new MultiParticleContainer(this));
-
- if (do_plasma_injection) {
- for (int i = 0; i < num_injected_species; ++i) {
- int ispecies = injected_plasma_species[i];
- WarpXParticleContainer& pc = mypc->GetParticleContainer(ispecies);
- auto& ppc = dynamic_cast<PhysicalParticleContainer&>(pc);
- ppc.injected = true;
+ warpx_do_continuous_injection = mypc->doContinuousInjection();
+ if (warpx_do_continuous_injection){
+ 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);
}
}
+ do_boosted_frame_particles = mypc->doBoostedFrameDiags();
Efield_aux.resize(nlevs_max);
Bfield_aux.resize(nlevs_max);
@@ -222,6 +229,11 @@ WarpX::WarpX ()
#ifdef BL_USE_SENSEI_INSITU
insitu_bridge = nullptr;
#endif
+
+ // NCI Godfrey filters can have different stencils
+ // at different levels (the stencil depends on c*dt/dz)
+ nci_godfrey_filter_exeybz.resize(nlevs_max);
+ nci_godfrey_filter_bxbyez.resize(nlevs_max);
}
WarpX::~WarpX ()
@@ -270,6 +282,12 @@ WarpX::ReadParameters ()
ReadBoostedFrameParameters(gamma_boost, beta_boost, boost_direction);
+ // pp.query returns 1 if argument zmax_plasma_to_compute_max_step is
+ // specified by the user, 0 otherwise.
+ do_compute_max_step_from_zmax =
+ pp.query("zmax_plasma_to_compute_max_step",
+ zmax_plasma_to_compute_max_step);
+
pp.queryarr("B_external", B_external);
pp.query("do_moving_window", do_moving_window);
@@ -299,27 +317,14 @@ WarpX::ReadParameters ()
moving_window_v *= PhysConst::c;
}
- 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.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.");
+ pp.query("lab_data_directory", lab_data_directory);
+
std::string s;
pp.get("boost_direction", s);
AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"),
@@ -330,8 +335,6 @@ WarpX::ReadParameters ()
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.");
@@ -345,7 +348,6 @@ WarpX::ReadParameters ()
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);
@@ -357,6 +359,16 @@ WarpX::ReadParameters ()
filter_npass_each_dir[2] = parse_filter_npass_each_dir[2];
#endif
+ pp.query("num_mirrors", num_mirrors);
+ if (num_mirrors>0){
+ mirror_z.resize(num_mirrors);
+ pp.getarr("mirror_z", mirror_z, 0, num_mirrors);
+ mirror_z_width.resize(num_mirrors);
+ pp.getarr("mirror_z_width", mirror_z_width, 0, num_mirrors);
+ mirror_z_npoints.resize(num_mirrors);
+ pp.getarr("mirror_z_npoints", mirror_z_npoints, 0, num_mirrors);
+ }
+
pp.query("serialize_ics", serialize_ics);
pp.query("refine_plasma", refine_plasma);
pp.query("do_dive_cleaning", do_dive_cleaning);
@@ -375,6 +387,10 @@ WarpX::ReadParameters ()
if (ParallelDescriptor::NProcs() == 1) {
plot_proc_number = false;
}
+ // Fields to dump into plotfiles
+ pp.query("plot_E_field" , plot_E_field);
+ pp.query("plot_B_field" , plot_B_field);
+ pp.query("plot_J_field" , plot_J_field);
pp.query("plot_part_per_cell", plot_part_per_cell);
pp.query("plot_part_per_grid", plot_part_per_grid);
pp.query("plot_part_per_proc", plot_part_per_proc);
@@ -384,6 +400,7 @@ WarpX::ReadParameters ()
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++){
@@ -397,8 +414,8 @@ WarpX::ReadParameters ()
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_dive_cleaning,
"plot_F only works if warpx.do_dive_cleaning = 1");
}
+ pp.query("plot_finepatch", plot_finepatch);
if (maxLevel() > 0) {
- pp.query("plot_finepatch", plot_finepatch);
pp.query("plot_crsepatch", plot_crsepatch);
}
@@ -432,25 +449,6 @@ WarpX::ReadParameters ()
fine_tag_hi = RealVect{hi};
}
- // select which particle comps to write
- {
- pp.queryarr("particle_plot_vars", particle_plot_vars);
-
- if (particle_plot_vars.size() == 0)
- {
- particle_plot_flags.resize(PIdx::nattribs, 1);
- }
- else
- {
- particle_plot_flags.resize(PIdx::nattribs, 0);
-
- for (const auto& var : particle_plot_vars)
- {
- particle_plot_flags[ParticleStringNames::to_index.at(var)] = 1;
- }
- }
- }
-
pp.query("load_balance_int", load_balance_int);
pp.query("load_balance_with_sfc", load_balance_with_sfc);
pp.query("load_balance_knapsack_factor", load_balance_knapsack_factor);
@@ -484,29 +482,12 @@ WarpX::ReadParameters ()
}
{
- ParmParse pp("algo");
- pp.query("current_deposition", current_deposition_algo);
- pp.query("charge_deposition", charge_deposition_algo);
- pp.query("field_gathering", field_gathering_algo);
- pp.query("particle_pusher", particle_pusher_algo);
- std::string s_solver = "";
- pp.query("maxwell_fdtd_solver", s_solver);
- std::transform(s_solver.begin(),
- s_solver.end(),
- s_solver.begin(),
- ::tolower);
- // if maxwell_fdtd_solver is specified, set the value
- // of maxwell_fdtd_solver_id accordingly.
- // Otherwise keep the default value maxwell_fdtd_solver_id=0
- if (s_solver != "") {
- if (s_solver == "yee") {
- maxwell_fdtd_solver_id = 0;
- } else if (s_solver == "ckc") {
- maxwell_fdtd_solver_id = 1;
- } else {
- amrex::Abort("Unknown FDTD Solver type " + s_solver);
- }
- }
+ ParmParse pp("algo");
+ current_deposition_algo = GetAlgorithmInteger(pp, "current_deposition");
+ charge_deposition_algo = GetAlgorithmInteger(pp, "charge_deposition");
+ field_gathering_algo = GetAlgorithmInteger(pp, "field_gathering");
+ particle_pusher_algo = GetAlgorithmInteger(pp, "particle_pusher");
+ maxwell_fdtd_solver_id = GetAlgorithmInteger(pp, "maxwell_fdtd_solver");
}
#ifdef WARPX_USE_PSATD
@@ -535,6 +516,34 @@ WarpX::ReadParameters ()
pp.query("config", insitu_config);
pp.query("pin_mesh", insitu_pin_mesh);
}
+
+ // for slice generation //
+ {
+ ParmParse pp("slice");
+ amrex::Vector<Real> slice_lo(AMREX_SPACEDIM);
+ amrex::Vector<Real> slice_hi(AMREX_SPACEDIM);
+ Vector<int> slice_crse_ratio(AMREX_SPACEDIM);
+ // set default slice_crse_ratio //
+ for (int idim=0; idim < AMREX_SPACEDIM; ++idim )
+ {
+ slice_crse_ratio[idim] = 1;
+ }
+ pp.queryarr("dom_lo",slice_lo,0,AMREX_SPACEDIM);
+ pp.queryarr("dom_hi",slice_hi,0,AMREX_SPACEDIM);
+ pp.queryarr("coarsening_ratio",slice_crse_ratio,0,AMREX_SPACEDIM);
+ pp.query("plot_int",slice_plot_int);
+ slice_realbox.setLo(slice_lo);
+ slice_realbox.setHi(slice_hi);
+ slice_cr_ratio = IntVect(AMREX_D_DECL(1,1,1));
+ for (int idim = 0; idim < AMREX_SPACEDIM; ++idim)
+ {
+ if (slice_crse_ratio[idim] > 1 ) {
+ slice_cr_ratio[idim] = slice_crse_ratio[idim];
+ }
+ }
+
+ }
+
}
// This is a virtual function.
@@ -636,7 +645,7 @@ WarpX::AllocLevelData (int lev, const BoxArray& ba, const DistributionMapping& d
int ngz_nonci = (ngz_tmp % 2) ? ngz_tmp+1 : ngz_tmp; // Always even number
int ngz;
if (WarpX::use_fdtd_nci_corr) {
- int ng = ngz_tmp + (mypc->nstencilz_fdtd_nci_corr-1);
+ int ng = ngz_tmp + NCIGodfreyFilter::stencil_width;
ngz = (ng % 2) ? ng+1 : ng;
} else {
ngz = ngz_nonci;
@@ -841,8 +850,6 @@ WarpX::AllocLevelMFs (int lev, const BoxArray& ba, const DistributionMapping& dm
if (load_balance_int > 0) {
costs[lev].reset(new MultiFab(ba, dm, 1, 0));
}
-
-
}
std::array<Real,3>
@@ -963,12 +970,19 @@ WarpX::ComputeDivE (MultiFab& divE, int dcomp,
for (MFIter mfi(divE, true); mfi.isValid(); ++mfi)
{
const Box& bx = mfi.tilebox();
+#ifdef WARPX_RZ
+ const Real xmin = GetInstance().Geom(0).ProbLo(0);
+#endif
WRPX_COMPUTE_DIVE(bx.loVect(), bx.hiVect(),
BL_TO_FORTRAN_N_ANYD(divE[mfi],dcomp),
BL_TO_FORTRAN_ANYD((*E[0])[mfi]),
BL_TO_FORTRAN_ANYD((*E[1])[mfi]),
BL_TO_FORTRAN_ANYD((*E[2])[mfi]),
- dx.data());
+ dx.data()
+#ifdef WARPX_RZ
+ ,&xmin
+#endif
+ );
}
}
@@ -983,19 +997,25 @@ WarpX::ComputeDivE (MultiFab& divE, int dcomp,
for (MFIter mfi(divE, true); mfi.isValid(); ++mfi)
{
Box bx = mfi.growntilebox(ngrow);
+#ifdef WARPX_RZ
+ const Real xmin = GetInstance().Geom(0).ProbLo(0);
+#endif
WRPX_COMPUTE_DIVE(bx.loVect(), bx.hiVect(),
BL_TO_FORTRAN_N_ANYD(divE[mfi],dcomp),
BL_TO_FORTRAN_ANYD((*E[0])[mfi]),
BL_TO_FORTRAN_ANYD((*E[1])[mfi]),
BL_TO_FORTRAN_ANYD((*E[2])[mfi]),
- dx.data());
+ dx.data()
+#ifdef WARPX_RZ
+ ,&xmin
+#endif
+ );
}
}
void
WarpX::BuildBufferMasks ()
{
- int ngbuffer = std::max(n_field_gather_buffer, n_current_deposition_buffer);
for (int lev = 1; lev <= maxLevel(); ++lev)
{
for (int ipass = 0; ipass < 2; ++ipass)