aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Edoardo Zoni <59625522+EZoni@users.noreply.github.com> 2023-06-30 12:09:13 -0700
committerGravatar GitHub <noreply@github.com> 2023-06-30 19:09:13 +0000
commit1a55de802493eef4c515be0e198e4ddb23e5cda9 (patch)
treee7938d009a51a144f46195bf649649ace96dfb58
parent5baa09ceadc6291f67839c7842fd1756edfc1186 (diff)
downloadWarpX-1a55de802493eef4c515be0e198e4ddb23e5cda9.tar.gz
WarpX-1a55de802493eef4c515be0e198e4ddb23e5cda9.tar.zst
WarpX-1a55de802493eef4c515be0e198e4ddb23e5cda9.zip
Continuous injection of moving plasma (#3958)
* Continuous injection of moving plasma * Fix const correctness * Fix bugs in calculation of v_bulk * Fix restart * Use range-based for loops where possible * Apply suggestions from code review * Fix bug related to managed memory * Apply suggestions from code review * Exclude case with `moving_window_v = 0` * Add to WarpXParticleContainer virtual function that returns pointer to plasma injector * Add to WarpXParticleContainer member variable for current injection position * Fix bugs * Fix bug: use continue instead of return
-rw-r--r--Source/Diagnostics/FlushFormats/FlushFormatPlotfile.cpp7
-rw-r--r--Source/Diagnostics/WarpXIO.cpp8
-rw-r--r--Source/Initialization/PlasmaInjector.H4
-rw-r--r--Source/Initialization/PlasmaInjector.cpp8
-rw-r--r--Source/Particles/PhysicalParticleContainer.H5
-rw-r--r--Source/Particles/PhysicalParticleContainer.cpp9
-rw-r--r--Source/Particles/WarpXParticleContainer.H13
-rw-r--r--Source/Utils/WarpXMovingWindow.cpp179
-rw-r--r--Source/WarpX.H2
-rw-r--r--Source/WarpX.cpp23
10 files changed, 186 insertions, 72 deletions
diff --git a/Source/Diagnostics/FlushFormats/FlushFormatPlotfile.cpp b/Source/Diagnostics/FlushFormats/FlushFormatPlotfile.cpp
index 3ea631292..28033b3ac 100644
--- a/Source/Diagnostics/FlushFormats/FlushFormatPlotfile.cpp
+++ b/Source/Diagnostics/FlushFormats/FlushFormatPlotfile.cpp
@@ -302,7 +302,12 @@ FlushFormatPlotfile::WriteWarpXHeader(
warpx.GetPartContainer().WriteHeader(HeaderFile);
- HeaderFile << warpx.getcurrent_injection_position() << "\n";
+ MultiParticleContainer& mypc = warpx.GetPartContainer();
+ const int n_species = mypc.nSpecies();
+ for (int i=0; i<n_species; i++)
+ {
+ HeaderFile << mypc.GetParticleContainer(i).m_current_injection_position << "\n";
+ }
HeaderFile << warpx.getdo_moving_window() << "\n";
diff --git a/Source/Diagnostics/WarpXIO.cpp b/Source/Diagnostics/WarpXIO.cpp
index 36f875659..aeaf85304 100644
--- a/Source/Diagnostics/WarpXIO.cpp
+++ b/Source/Diagnostics/WarpXIO.cpp
@@ -211,8 +211,12 @@ WarpX::InitFromCheckpoint ()
}
mypc->ReadHeader(is);
- is >> current_injection_position;
- GotoNextLine(is);
+ const int n_species = mypc->nSpecies();
+ for (int i=0; i<n_species; i++)
+ {
+ is >> mypc->GetParticleContainer(i).m_current_injection_position;
+ GotoNextLine(is);
+ }
int do_moving_window_before_restart;
is >> do_moving_window_before_restart;
diff --git a/Source/Initialization/PlasmaInjector.H b/Source/Initialization/PlasmaInjector.H
index 0f33aa062..1c2fc453d 100644
--- a/Source/Initialization/PlasmaInjector.H
+++ b/Source/Initialization/PlasmaInjector.H
@@ -133,8 +133,10 @@ public:
InjectorPosition* getInjectorPosition ();
InjectorDensity* getInjectorDensity ();
+
InjectorFlux* getInjectorFlux ();
- InjectorMomentum* getInjectorMomentum ();
+ InjectorMomentum* getInjectorMomentumDevice ();
+ InjectorMomentum* getInjectorMomentumHost ();
protected:
diff --git a/Source/Initialization/PlasmaInjector.cpp b/Source/Initialization/PlasmaInjector.cpp
index 865e531e7..1ed868647 100644
--- a/Source/Initialization/PlasmaInjector.cpp
+++ b/Source/Initialization/PlasmaInjector.cpp
@@ -775,7 +775,13 @@ PlasmaInjector::getInjectorFlux ()
}
InjectorMomentum*
-PlasmaInjector::getInjectorMomentum ()
+PlasmaInjector::getInjectorMomentumDevice ()
{
return d_inj_mom;
}
+
+InjectorMomentum*
+PlasmaInjector::getInjectorMomentumHost ()
+{
+ return h_inj_mom.get();
+}
diff --git a/Source/Particles/PhysicalParticleContainer.H b/Source/Particles/PhysicalParticleContainer.H
index 4a9beeec2..24a1b94d3 100644
--- a/Source/Particles/PhysicalParticleContainer.H
+++ b/Source/Particles/PhysicalParticleContainer.H
@@ -66,6 +66,11 @@ public:
virtual void InitIonizationModule () override;
+ /*
+ * \brief Returns a pointer to the plasma injector.
+ */
+ virtual PlasmaInjector* GetPlasmaInjector () override;
+
/**
* \brief Evolve is the central function PhysicalParticleContainer that
* advances plasma particles for a time dt (typically one timestep).
diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp
index 0793094ff..8dff41c05 100644
--- a/Source/Particles/PhysicalParticleContainer.cpp
+++ b/Source/Particles/PhysicalParticleContainer.cpp
@@ -926,7 +926,7 @@ PhysicalParticleContainer::AddPlasma (int lev, RealBox part_realbox)
InjectorPosition* inj_pos = plasma_injector->getInjectorPosition();
InjectorDensity* inj_rho = plasma_injector->getInjectorDensity();
- InjectorMomentum* inj_mom = plasma_injector->getInjectorMomentum();
+ InjectorMomentum* inj_mom = plasma_injector->getInjectorMomentumDevice();
const Real gamma_boost = WarpX::gamma_boost;
const Real beta_boost = WarpX::beta_boost;
const Real t = WarpX::GetInstance().gett_new(lev);
@@ -1476,7 +1476,7 @@ PhysicalParticleContainer::AddPlasmaFlux (amrex::Real dt)
InjectorPosition* inj_pos = plasma_injector->getInjectorPosition();
InjectorFlux* inj_flux = plasma_injector->getInjectorFlux();
- InjectorMomentum* inj_mom = plasma_injector->getInjectorMomentum();
+ InjectorMomentum* inj_mom = plasma_injector->getInjectorMomentumDevice();
constexpr int level_zero = 0;
const amrex::Real t = WarpX::GetInstance().gett_new(level_zero);
@@ -2922,6 +2922,11 @@ PhysicalParticleContainer::getIonizationFunc (const WarpXParIter& pti,
ion_atomic_number);
}
+PlasmaInjector* PhysicalParticleContainer::GetPlasmaInjector ()
+{
+ return plasma_injector.get();
+}
+
void PhysicalParticleContainer::resample (const int timestep)
{
// In heavily load imbalanced simulations, MPI processes with few particles will spend most of
diff --git a/Source/Particles/WarpXParticleContainer.H b/Source/Particles/WarpXParticleContainer.H
index ffeead6f1..6e0d3f4f9 100644
--- a/Source/Particles/WarpXParticleContainer.H
+++ b/Source/Particles/WarpXParticleContainer.H
@@ -13,6 +13,7 @@
#include "WarpXParticleContainer_fwd.H"
#include "Evolve/WarpXDtType.H"
+#include "Initialization/PlasmaInjector.H"
#include "Particles/ParticleBoundaries.H"
#include "SpeciesPhysicalProperties.H"
@@ -121,6 +122,12 @@ public:
virtual void InitIonizationModule () {}
+ /*
+ * \brief Virtual function that returns a pointer to the plasma injector,
+ * for derived classes that define one (PhysicalParticleContainer).
+ */
+ virtual PlasmaInjector* GetPlasmaInjector () { return nullptr; }
+
/**
* Evolve is the central WarpXParticleContainer function that advances
* particles for a time dt (typically one timestep). It is a pure virtual
@@ -241,10 +248,13 @@ public:
virtual void ContinuousInjection(const amrex::RealBox& /*injection_box*/) {}
// Update optional sub-class-specific injection location.
virtual void UpdateContinuousInjectionPosition(amrex::Real /*dt*/) {}
+ bool doContinuousInjection() const {return do_continuous_injection;}
// Inject a continuous flux of particles from a defined plane
virtual void ContinuousFluxInjection(amrex::Real /*t*/, amrex::Real /*dt*/) {}
+ int getSpeciesId() const {return species_id;}
+
///
/// This returns the total charge for all the particles in this ParticleContainer.
/// This is needed when solving Poisson's equation with periodic boundary conditions.
@@ -306,6 +316,9 @@ public:
int self_fields_max_iters = 200;
int self_fields_verbosity = 2;
+ //! Current injection position
+ amrex::Real m_current_injection_position;
+
// split along diagonals (0) or axes (1)
int split_type = 0;
diff --git a/Source/Utils/WarpXMovingWindow.cpp b/Source/Utils/WarpXMovingWindow.cpp
index 7e7985b98..cef4764b1 100644
--- a/Source/Utils/WarpXMovingWindow.cpp
+++ b/Source/Utils/WarpXMovingWindow.cpp
@@ -56,25 +56,81 @@ void
WarpX::UpdatePlasmaInjectionPosition (amrex::Real a_dt)
{
const int dir = moving_window_dir;
- // Continuously inject plasma in new cells (by default only on level 0)
- 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 *
+
+ // Loop over species
+ const int n_species = mypc->nSpecies();
+ for (int i=0; i<n_species; i++)
+ {
+ WarpXParticleContainer& pc = mypc->GetParticleContainer(i);
+
+ // Continuously inject plasma in new cells (by default only on level 0)
+ if (pc.doContinuousInjection())
+ {
+ PlasmaInjector* plasma_injector = pc.GetPlasmaInjector();
+ if (plasma_injector == nullptr) continue;
+
+ // Get bulk momentum and velocity of plasma
+ amrex::XDim3 u_bulk = amrex::XDim3{0._rt, 0._rt, 0._rt};
+ amrex::Real v_bulk = 0._rt;
+ if (dir == 0)
+ {
+ // dir=0 is z in 1D, x in 2D, x in 3D
+#if defined(WARPX_DIM_1D_Z)
+ u_bulk = plasma_injector->getInjectorMomentumHost()->getBulkMomentum(0._rt, 0._rt, pc.m_current_injection_position);
+ v_bulk = PhysConst::c * u_bulk.z / std::sqrt(1._rt + u_bulk.z*u_bulk.z);
+#else // 2D, 3D
+ u_bulk = plasma_injector->getInjectorMomentumHost()->getBulkMomentum(pc.m_current_injection_position, 0._rt, 0._rt);
+ v_bulk = PhysConst::c * u_bulk.x / std::sqrt(1._rt + u_bulk.x*u_bulk.x);
+#endif
+ }
+ else if (dir == 1)
+ {
+ // dir=1 is nothing in 1D, z in 2D, y in 3D
+ // (we do not expect to enter this code block in 1D)
+#if defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
+ u_bulk = plasma_injector->getInjectorMomentumHost()->getBulkMomentum(0._rt, 0._rt, pc.m_current_injection_position);
+ v_bulk = PhysConst::c * u_bulk.z / std::sqrt(1._rt + u_bulk.z*u_bulk.z);
+#else // 3D
+ u_bulk = plasma_injector->getInjectorMomentumHost()->getBulkMomentum(0._rt, pc.m_current_injection_position, 0._rt);
+ v_bulk = PhysConst::c * u_bulk.y / std::sqrt(1._rt + u_bulk.y*u_bulk.y);
+#endif
+ }
+ else if (dir == 2)
+ {
+ // dir=2 is nothing in 1D, nothing in 2D, z in 3D
+ // (we do not expect to enter this code block in 1D and 2D)
+ u_bulk = plasma_injector->getInjectorMomentumHost()->getBulkMomentum(0._rt, 0._rt, pc.m_current_injection_position);
+ v_bulk = PhysConst::c * u_bulk.z / std::sqrt(1._rt + u_bulk.z*u_bulk.z);
+ }
+
+ // In boosted-frame simulations, the plasma has moved since the last
+ // call to this function, and injection position needs to be updated.
+ // Note that the bulk velocity v, obtained from getBulkMomentum, is
+ // transformed to the boosted frame velocity v' via the formula
+ // v' = (v-c*beta)/(1-v*beta/c)
+ if (WarpX::gamma_boost > 1._rt)
+ {
+ v_bulk = (v_bulk - PhysConst::c*WarpX::beta_boost)
+ / (1._rt - v_bulk*WarpX::beta_boost/PhysConst::c);
#if defined(WARPX_DIM_3D)
- WarpX::boost_direction[dir] * PhysConst::c * a_dt;
+ v_bulk *= WarpX::boost_direction[dir];
#elif defined(WARPX_DIM_XZ) || defined(WARPX_DIM_RZ)
- // 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 * a_dt;
+ // In 2D, dir=0 corresponds to x and dir=1 corresponds to z.
+ // This needs to be converted to access boost_direction,
+ // which has always 3 components.
+ v_bulk *= WarpX::boost_direction[2*dir];
#elif defined(WARPX_DIM_1D_Z)
- // In 1D, dir=0 corresponds to z
- // This needs to be converted in order to index `boost_direction`
- // which has 3 components, for 1D, 2D, and 3D simulations.
- WarpX::boost_direction[2] * PhysConst::c * a_dt;
- amrex::ignore_unused(dir);
+ // In 1D, dir=0 corresponds to z.
+ // This needs to be converted to access boost_direction,
+ // which has always 3 components.
+ v_bulk *= WarpX::boost_direction[2];
+ amrex::ignore_unused(dir);
#endif
+ }
+
+ // Update current injection position
+ pc.m_current_injection_position += v_bulk * a_dt;
+ }
}
}
@@ -96,15 +152,13 @@ WarpX::MoveWindow (const int step, bool move_j)
moving_window_x += (moving_window_v - WarpX::beta_boost * PhysConst::c)/(1 - moving_window_v * WarpX::beta_boost / PhysConst::c) * dt[0];
const int dir = moving_window_dir;
- // Update warpx.current_injection_position
+ // 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] );
- }
+ // Update injection position for WarpXParticleContainer in mypc,
+ // nothing to do for PhysicalParticleContainer,
+ // need to update the antenna position for LaserParticleContainer.
+ mypc->UpdateContinuousInjectionPosition( dt[0] );
// compute the number of cells to shift on the base level
amrex::Real new_lo[AMREX_SPACEDIM];
@@ -312,41 +366,54 @@ WarpX::MoveWindow (const int step, bool move_j)
}
}
- // Continuously inject plasma in new cells (by default only on level 0)
- if (WarpX::warpx_do_continuous_injection) {
-
- const int lev = 0;
-
- // particleBox encloses the cells where we generate particles
- // (only injects particles in an integer number of cells,
- // for correct particle spacing)
- amrex::RealBox particleBox = geom[lev].ProbDomain();
- amrex::Real new_injection_position;
- if (moving_window_v >= 0){
- // Forward-moving window
- const amrex::Real dx = geom[lev].CellSize(dir);
- new_injection_position = current_injection_position +
- std::floor( (geom[lev].ProbHi(dir) - current_injection_position)/dx ) * dx;
- } else {
- // Backward-moving window
- const amrex::Real dx = geom[lev].CellSize(dir);
- new_injection_position = current_injection_position -
- std::floor( (current_injection_position - geom[lev].ProbLo(dir))/dx) * dx;
- }
- // Modify the corresponding bounds of the particleBox
- if (moving_window_v >= 0) {
- particleBox.setLo( dir, current_injection_position );
- particleBox.setHi( dir, new_injection_position );
- } else {
- particleBox.setLo( dir, new_injection_position );
- particleBox.setHi( dir, current_injection_position );
- }
+ // Loop over species
+ const int n_species = mypc->nSpecies();
+ for (int i=0; i<n_species; i++)
+ {
+ WarpXParticleContainer& pc = mypc->GetParticleContainer(i);
+
+ // Continuously inject plasma in new cells (by default only on level 0)
+ if (pc.doContinuousInjection())
+ {
+ const int lev = 0;
+
+ // particleBox encloses the cells where we generate particles
+ // (only injects particles in an integer number of cells,
+ // for correct particle spacing)
+ amrex::RealBox particleBox = geom[lev].ProbDomain();
+ amrex::Real new_injection_position = pc.m_current_injection_position;
+ if (moving_window_v > 0._rt)
+ {
+ // Forward-moving window
+ const amrex::Real dx = geom[lev].CellSize(dir);
+ new_injection_position = pc.m_current_injection_position +
+ std::floor( (geom[lev].ProbHi(dir) - pc.m_current_injection_position)/dx ) * dx;
+ }
+ else if (moving_window_v < 0._rt)
+ {
+ // Backward-moving window
+ const amrex::Real dx = geom[lev].CellSize(dir);
+ new_injection_position = pc.m_current_injection_position -
+ std::floor( (pc.m_current_injection_position - geom[lev].ProbLo(dir))/dx) * dx;
+ }
+ // Modify the corresponding bounds of the particleBox
+ if (moving_window_v > 0._rt)
+ {
+ particleBox.setLo( dir, pc.m_current_injection_position );
+ particleBox.setHi( dir, new_injection_position );
+ }
+ else if (moving_window_v < 0._rt)
+ {
+ particleBox.setLo( dir, new_injection_position );
+ particleBox.setHi( dir, pc.m_current_injection_position );
+ }
- if (particleBox.ok() and (current_injection_position != new_injection_position)){
- // Performs continuous injection of all WarpXParticleContainer
- // in mypc.
- mypc->ContinuousInjection(particleBox);
- current_injection_position = new_injection_position;
+ if (particleBox.ok() and (pc.m_current_injection_position != new_injection_position)){
+ // Performs continuous injection of all WarpXParticleContainer
+ // in mypc.
+ pc.ContinuousInjection(particleBox);
+ pc.m_current_injection_position = new_injection_position;
+ }
}
}
diff --git a/Source/WarpX.H b/Source/WarpX.H
index fb5e403f4..dbe922812 100644
--- a/Source/WarpX.H
+++ b/Source/WarpX.H
@@ -868,7 +868,6 @@ public:
amrex::Real getdt (int lev) const {return dt[lev];}
int getdo_moving_window() const {return do_moving_window;}
amrex::Real getmoving_window_x() const {return moving_window_x;}
- amrex::Real getcurrent_injection_position () const {return current_injection_position;}
bool getis_synchronized() const {return is_synchronized;}
int maxStep () const {return max_step;}
@@ -1470,7 +1469,6 @@ private:
amrex::Real v_particle_pml;
amrex::Real moving_window_x = std::numeric_limits<amrex::Real>::max();
- amrex::Real current_injection_position = 0;
// Plasma injection parameters
int warpx_do_continuous_injection = 0;
diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp
index 17601175b..fc37ccc65 100644
--- a/Source/WarpX.cpp
+++ b/Source/WarpX.cpp
@@ -279,16 +279,25 @@ WarpX::WarpX ()
t_old.resize(nlevs_max, std::numeric_limits<Real>::lowest());
dt.resize(nlevs_max, std::numeric_limits<Real>::max());
- // Particle Container
+ // Loop over species and set current injection position per species
mypc = std::make_unique<MultiParticleContainer>(this);
- warpx_do_continuous_injection = mypc->doContinuousInjection();
- if (warpx_do_continuous_injection){
- if (moving_window_v >= 0){
+ const int n_species = mypc->nSpecies();
+ for (int i=0; i<n_species; i++)
+ {
+ WarpXParticleContainer& pc = mypc->GetParticleContainer(i);
+
+ // Storing injection position for all species, regardless of whether
+ // they are continuously injected, since it makes looping over the
+ // elements of current_injection_position easier elsewhere in the code.
+ if (moving_window_v > 0._rt)
+ {
// Inject particles continuously from the right end of the box
- current_injection_position = geom[0].ProbHi(moving_window_dir);
- } else {
+ pc.m_current_injection_position = geom[0].ProbHi(moving_window_dir);
+ }
+ else if (moving_window_v < 0._rt)
+ {
// Inject particles continuously from the left end of the box
- current_injection_position = geom[0].ProbLo(moving_window_dir);
+ pc.m_current_injection_position = geom[0].ProbLo(moving_window_dir);
}
}