aboutsummaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/BoundaryConditions/PML.H8
-rw-r--r--Source/BoundaryConditions/PML.cpp8
-rw-r--r--Source/BoundaryConditions/PML_current.H7
-rw-r--r--Source/BoundaryConditions/WarpXEvolvePML.cpp7
-rw-r--r--Source/BoundaryConditions/WarpX_PML_kernels.H7
-rw-r--r--Source/Diagnostics/BackTransformedDiagnostic.H7
-rw-r--r--Source/Diagnostics/BackTransformedDiagnostic.cpp9
-rw-r--r--Source/Diagnostics/ElectrostaticIO.cpp7
-rw-r--r--Source/Diagnostics/FieldIO.H7
-rw-r--r--Source/Diagnostics/FieldIO.cpp215
-rw-r--r--Source/Diagnostics/Make.package2
-rw-r--r--Source/Diagnostics/ParticleIO.cpp8
-rw-r--r--Source/Diagnostics/ReducedDiags/FieldEnergy.H36
-rw-r--r--Source/Diagnostics/ReducedDiags/FieldEnergy.cpp139
-rw-r--r--Source/Diagnostics/ReducedDiags/Make.package14
-rw-r--r--Source/Diagnostics/ReducedDiags/MultiReducedDiags.H47
-rw-r--r--Source/Diagnostics/ReducedDiags/MultiReducedDiags.cpp94
-rw-r--r--Source/Diagnostics/ReducedDiags/ParticleEnergy.H37
-rw-r--r--Source/Diagnostics/ReducedDiags/ParticleEnergy.cpp166
-rw-r--r--Source/Diagnostics/ReducedDiags/ReducedDiags.H59
-rw-r--r--Source/Diagnostics/ReducedDiags/ReducedDiags.cpp92
-rw-r--r--Source/Diagnostics/SliceDiagnostic.H6
-rw-r--r--Source/Diagnostics/SliceDiagnostic.cpp41
-rw-r--r--Source/Diagnostics/WarpXIO.cpp86
-rw-r--r--Source/Diagnostics/WarpXOpenPMD.H42
-rw-r--r--Source/Diagnostics/WarpXOpenPMD.cpp543
-rw-r--r--Source/Diagnostics/requirements.txt8
-rw-r--r--Source/Evolve/WarpXDtType.H6
-rw-r--r--Source/Evolve/WarpXEvolveEM.cpp164
-rw-r--r--Source/Evolve/WarpXEvolveES.cpp12
-rw-r--r--Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridFFTData.H6
-rw-r--r--Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridSpectralSolver.cpp7
-rw-r--r--Source/FieldSolver/PicsarHybridSpectralSolver/picsar_hybrid_spectral.F907
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.H6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.cpp6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H7
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.H7
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp7
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralKSpace.H7
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp14
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.H6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.cpp6
-rw-r--r--Source/FieldSolver/SpectralSolver/WarpX_ComplexForFFT.H6
-rw-r--r--Source/FieldSolver/WarpXPushFieldsEM.cpp8
-rw-r--r--Source/FieldSolver/WarpX_FDTD.H6
-rw-r--r--Source/FieldSolver/WarpX_K.H6
-rw-r--r--Source/Filter/BilinearFilter.H7
-rw-r--r--Source/Filter/BilinearFilter.cpp7
-rw-r--r--Source/Filter/Filter.H6
-rw-r--r--Source/Filter/Filter.cpp7
-rw-r--r--Source/Filter/NCIGodfreyFilter.H6
-rw-r--r--Source/Filter/NCIGodfreyFilter.cpp8
-rw-r--r--Source/FortranInterface/WarpX_f.F9051
-rw-r--r--Source/FortranInterface/WarpX_f.H12
-rw-r--r--Source/Initialization/CustomDensityProb.H6
-rw-r--r--Source/Initialization/CustomMomentumProb.H6
-rw-r--r--Source/Initialization/InitSpaceChargeField.cpp6
-rw-r--r--Source/Initialization/InjectorDensity.H7
-rw-r--r--Source/Initialization/InjectorDensity.cpp11
-rw-r--r--Source/Initialization/InjectorMomentum.H7
-rw-r--r--Source/Initialization/InjectorMomentum.cpp11
-rw-r--r--Source/Initialization/InjectorPosition.H7
-rw-r--r--Source/Initialization/PlasmaInjector.H8
-rw-r--r--Source/Initialization/PlasmaInjector.cpp65
-rw-r--r--Source/Initialization/WarpXInitData.cpp277
-rw-r--r--Source/Laser/LaserParticleContainer.H8
-rw-r--r--Source/Laser/LaserParticleContainer.cpp39
-rw-r--r--Source/Laser/LaserProfiles.H201
-rw-r--r--Source/Laser/LaserProfilesImpl/LaserProfileFieldFunction.cpp8
-rw-r--r--Source/Laser/LaserProfilesImpl/LaserProfileFromTXYEFile.cpp485
-rw-r--r--Source/Laser/LaserProfilesImpl/LaserProfileGaussian.cpp9
-rw-r--r--Source/Laser/LaserProfilesImpl/LaserProfileHarris.cpp8
-rw-r--r--Source/Laser/LaserProfilesImpl/Make.package1
-rw-r--r--Source/Parallelization/GuardCellManager.H82
-rw-r--r--Source/Parallelization/GuardCellManager.cpp177
-rw-r--r--Source/Parallelization/InterpolateCurrentFineToCoarse.H6
-rw-r--r--Source/Parallelization/InterpolateDensityFineToCoarse.H2
-rw-r--r--Source/Parallelization/Make.package2
-rw-r--r--Source/Parallelization/WarpXComm.H6
-rw-r--r--Source/Parallelization/WarpXComm.cpp107
-rw-r--r--Source/Parallelization/WarpXComm_K.H6
-rw-r--r--Source/Parallelization/WarpXRegrid.cpp8
-rw-r--r--Source/Parallelization/WarpXSumGuardCells.H7
-rw-r--r--Source/Parser/GpuParser.H21
-rw-r--r--Source/Parser/GpuParser.cpp11
-rw-r--r--Source/Parser/Make.package1
-rw-r--r--Source/Parser/WarpXParser.H6
-rw-r--r--Source/Parser/WarpXParser.cpp6
-rw-r--r--Source/Parser/WarpXParserWrapper.H41
-rw-r--r--Source/Parser/wp_parser_c.h2
-rw-r--r--Source/Particles/Collision/CollisionType.H6
-rw-r--r--Source/Particles/Collision/CollisionType.cpp26
-rw-r--r--Source/Particles/Collision/ComputeTemperature.H6
-rw-r--r--Source/Particles/Collision/ElasticCollisionPerez.H6
-rw-r--r--Source/Particles/Collision/ShuffleFisherYates.H6
-rw-r--r--Source/Particles/Collision/UpdateMomentumPerezElastic.H6
-rwxr-xr-xSource/Particles/Deposition/ChargeDeposition.H7
-rw-r--r--Source/Particles/Deposition/CurrentDeposition.H7
-rw-r--r--Source/Particles/Gather/FieldGather.H7
-rw-r--r--Source/Particles/MultiParticleContainer.H35
-rw-r--r--Source/Particles/MultiParticleContainer.cpp105
-rw-r--r--Source/Particles/ParticleCreation/CopyParticle.H6
-rw-r--r--Source/Particles/ParticleCreation/ElementaryProcess.H7
-rw-r--r--Source/Particles/ParticleCreation/TransformParticle.H6
-rw-r--r--Source/Particles/PhotonParticleContainer.H7
-rw-r--r--Source/Particles/PhotonParticleContainer.cpp7
-rw-r--r--Source/Particles/PhysicalParticleContainer.H30
-rw-r--r--Source/Particles/PhysicalParticleContainer.cpp132
-rw-r--r--Source/Particles/Pusher/GetAndSetPosition.H7
-rw-r--r--Source/Particles/Pusher/UpdateMomentumBoris.H7
-rw-r--r--Source/Particles/Pusher/UpdateMomentumBorisWithRadiationReaction.H6
-rw-r--r--Source/Particles/Pusher/UpdateMomentumHigueraCary.H6
-rw-r--r--Source/Particles/Pusher/UpdateMomentumVay.H7
-rw-r--r--Source/Particles/Pusher/UpdatePosition.H7
-rw-r--r--Source/Particles/Pusher/UpdatePositionPhoton.H7
-rw-r--r--Source/Particles/RigidInjectedParticleContainer.H7
-rw-r--r--Source/Particles/RigidInjectedParticleContainer.cpp16
-rw-r--r--Source/Particles/ShapeFactors.H6
-rw-r--r--Source/Particles/Sorting/Partition.cpp6
-rw-r--r--Source/Particles/Sorting/SortingUtils.H40
-rw-r--r--Source/Particles/WarpXParticleContainer.H22
-rw-r--r--Source/Particles/WarpXParticleContainer.cpp45
-rw-r--r--Source/Particles/interpolate_cic.F906
-rw-r--r--Source/Particles/push_particles_ES.F90116
-rw-r--r--Source/Python/WarpXWrappers.cpp21
-rw-r--r--Source/Python/WarpXWrappers.h9
-rw-r--r--Source/Python/WarpX_py.H7
-rw-r--r--Source/Python/WarpX_py.cpp7
-rw-r--r--Source/QED/BreitWheelerDummyTable.H6
-rw-r--r--Source/QED/BreitWheelerEngineInnards.H6
-rw-r--r--Source/QED/BreitWheelerEngineTableBuilder.H6
-rw-r--r--Source/QED/BreitWheelerEngineTableBuilder.cpp6
-rw-r--r--Source/QED/BreitWheelerEngineWrapper.H6
-rw-r--r--Source/QED/BreitWheelerEngineWrapper.cpp6
-rw-r--r--Source/QED/QedChiFunctions.H6
-rw-r--r--Source/QED/QedTableParserHelperFunctions.H6
-rw-r--r--Source/QED/QedWrapperCommons.H6
-rw-r--r--Source/QED/QuantumSyncDummyTable.H6
-rw-r--r--Source/QED/QuantumSyncEngineInnards.H6
-rw-r--r--Source/QED/QuantumSyncEngineTableBuilder.H6
-rw-r--r--Source/QED/QuantumSyncEngineTableBuilder.cpp6
-rw-r--r--Source/QED/QuantumSyncEngineWrapper.H6
-rw-r--r--Source/QED/QuantumSyncEngineWrapper.cpp6
-rw-r--r--Source/Utils/IonizationEnergiesTable.H6
-rw-r--r--Source/Utils/NCIGodfreyTables.H6
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.H7
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.cpp8
-rw-r--r--Source/Utils/WarpXConst.H7
-rw-r--r--Source/Utils/WarpXMovingWindow.cpp129
-rw-r--r--Source/Utils/WarpXTagging.cpp7
-rw-r--r--Source/Utils/WarpXUtil.H117
-rw-r--r--Source/Utils/WarpXUtil.cpp50
-rw-r--r--Source/Utils/WarpX_Complex.H21
-rw-r--r--Source/Utils/atomic_data.txt6
-rw-r--r--Source/Utils/utils_ES.F906
-rw-r--r--Source/Utils/write_atomic_data_cpp.py8
-rw-r--r--Source/WarpX.H167
-rw-r--r--Source/WarpX.cpp203
-rw-r--r--Source/main.cpp8
161 files changed, 4526 insertions, 860 deletions
diff --git a/Source/BoundaryConditions/PML.H b/Source/BoundaryConditions/PML.H
index 5ab84439f..b8ed0ff7a 100644
--- a/Source/BoundaryConditions/PML.H
+++ b/Source/BoundaryConditions/PML.H
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Aurore Blelly, Axel Huebl
+ * Maxence Thevenet, Remi Lehe, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <array>
#ifndef WARPX_PML_H_
diff --git a/Source/BoundaryConditions/PML.cpp b/Source/BoundaryConditions/PML.cpp
index 51439430d..3f2acc6a8 100644
--- a/Source/BoundaryConditions/PML.cpp
+++ b/Source/BoundaryConditions/PML.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Aurore Blelly, Axel Huebl
+ * Maxence Thevenet, Remi Lehe, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <PML.H>
#include <WarpX.H>
#include <WarpXConst.H>
diff --git a/Source/BoundaryConditions/PML_current.H b/Source/BoundaryConditions/PML_current.H
index fa5bbf3f9..1d0249d56 100644
--- a/Source/BoundaryConditions/PML_current.H
+++ b/Source/BoundaryConditions/PML_current.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Aurore Blelly, Axel Huebl, Maxence Thevenet
+ * Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef PML_CURRENT_H_
#define PML_CURRENT_H_
diff --git a/Source/BoundaryConditions/WarpXEvolvePML.cpp b/Source/BoundaryConditions/WarpXEvolvePML.cpp
index bd29d1b65..0e3665c86 100644
--- a/Source/BoundaryConditions/WarpXEvolvePML.cpp
+++ b/Source/BoundaryConditions/WarpXEvolvePML.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Aurore Blelly, Axel Huebl, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <cmath>
#include <limits>
diff --git a/Source/BoundaryConditions/WarpX_PML_kernels.H b/Source/BoundaryConditions/WarpX_PML_kernels.H
index 89fdb4911..8a573c4b9 100644
--- a/Source/BoundaryConditions/WarpX_PML_kernels.H
+++ b/Source/BoundaryConditions/WarpX_PML_kernels.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Remi Lehe, Revathi Jambunathan, Revathi Jambunathan
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PML_KERNELS_H_
#define WARPX_PML_KERNELS_H_
diff --git a/Source/Diagnostics/BackTransformedDiagnostic.H b/Source/Diagnostics/BackTransformedDiagnostic.H
index 5621d48c6..0d36c97d9 100644
--- a/Source/Diagnostics/BackTransformedDiagnostic.H
+++ b/Source/Diagnostics/BackTransformedDiagnostic.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, Maxence Thevenet
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_BackTransformedDiagnostic_H_
#define WARPX_BackTransformedDiagnostic_H_
diff --git a/Source/Diagnostics/BackTransformedDiagnostic.cpp b/Source/Diagnostics/BackTransformedDiagnostic.cpp
index 452828f02..0f45c9f42 100644
--- a/Source/Diagnostics/BackTransformedDiagnostic.cpp
+++ b/Source/Diagnostics/BackTransformedDiagnostic.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, Maxence Thevenet
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <AMReX_MultiFabUtil.H>
#include <AMReX_MultiFabUtil_C.H>
@@ -559,7 +566,7 @@ BackTransformedDiagnostic(Real zmin_lab, Real zmax_lab, Real v_window_lab,
std::vector<std::string> user_fields_to_dump;
ParmParse pp("warpx");
bool do_user_fields;
- do_user_fields = pp.queryarr("boosted_frame_diag_fields",
+ do_user_fields = pp.queryarr("back_transformed_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.
diff --git a/Source/Diagnostics/ElectrostaticIO.cpp b/Source/Diagnostics/ElectrostaticIO.cpp
index 332638cff..8fb90ae4c 100644
--- a/Source/Diagnostics/ElectrostaticIO.cpp
+++ b/Source/Diagnostics/ElectrostaticIO.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Bizzozero
+ * Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpX_f.H>
diff --git a/Source/Diagnostics/FieldIO.H b/Source/Diagnostics/FieldIO.H
index 7cdc9b710..193fe8bd5 100644
--- a/Source/Diagnostics/FieldIO.H
+++ b/Source/Diagnostics/FieldIO.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, David Grote, Igor Andriyash
+ * Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_FielIO_H_
#define WARPX_FielIO_H_
diff --git a/Source/Diagnostics/FieldIO.cpp b/Source/Diagnostics/FieldIO.cpp
index e1bb8cb54..26545ea04 100644
--- a/Source/Diagnostics/FieldIO.cpp
+++ b/Source/Diagnostics/FieldIO.cpp
@@ -1,8 +1,16 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, David Grote
+ * Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <FieldIO.H>
#ifdef WARPX_USE_OPENPMD
-#include <openPMD/openPMD.hpp>
+# include <openPMD/openPMD.hpp>
#endif
#include <AMReX_FillPatchUtil_F.H>
@@ -352,6 +360,27 @@ AverageAndPackVectorField( MultiFab& mf_avg,
}
}
+/** \brief Takes all of the components of the three fields and
+ * averages and packs them into the MultiFab mf_avg.
+ */
+void
+AverageAndPackVectorFieldComponents (MultiFab& mf_avg,
+ const std::array< std::unique_ptr<MultiFab>, 3 >& vector_field,
+ const DistributionMapping& dm,
+ int& dcomp, const int ngrow )
+{
+ if (vector_field[0]->nComp() > 1) {
+ std::array<std::unique_ptr<MultiFab>,3> vector_field_component;
+ for (int icomp=0 ; icomp < vector_field[0]->nComp() ; icomp++) {
+ vector_field_component[0].reset(new MultiFab(*vector_field[0], amrex::make_alias, icomp, 1));
+ vector_field_component[1].reset(new MultiFab(*vector_field[1], amrex::make_alias, icomp, 1));
+ vector_field_component[2].reset(new MultiFab(*vector_field[2], amrex::make_alias, icomp, 1));
+ AverageAndPackVectorField(mf_avg, vector_field_component, dm, dcomp, ngrow);
+ dcomp += 3;
+ }
+ }
+}
+
/** \brief Take a MultiFab `scalar_field`
* averages it to the cell center, and stores the
* resulting MultiFab in mf_avg (in the components dcomp)
@@ -378,6 +407,74 @@ AverageAndPackScalarField( MultiFab& mf_avg,
}
}
+/** \brief Takes the specified component of the scalar and
+ * averages and packs it into the MultiFab mf_avg.
+ */
+void
+AverageAndPackScalarFieldComponent (MultiFab& mf_avg,
+ const MultiFab& scalar_field,
+ const int icomp,
+ const int dcomp, const int ngrow )
+{
+ MultiFab scalar_field_component(scalar_field, amrex::make_alias, icomp, 1);
+ AverageAndPackScalarField(mf_avg, scalar_field_component, dcomp, ngrow);
+}
+
+/** \brief Generate mode variable name
+ */
+std::string
+ComponentName(std::string fieldname, int mode, std::string type)
+{
+ if (type == "real") {
+ return fieldname + "_" + std::to_string(mode) + "_" + "real";
+ } else if (type == "imag") {
+ return fieldname + "_" + std::to_string(mode) + "_" + "imag";
+ } else {
+ AMREX_ALWAYS_ASSERT( false );
+ }
+ // This should never be done
+ return "";
+}
+
+/* \brief Copy vector field component data into the MultiFab that will be written out
+ */
+void
+CopyVectorFieldComponentsToMultiFab (int lev, amrex::Vector<MultiFab>& mf_avg, MultiFab& mf_tmp,
+ int icomp, int& dcomp, int ngrow,
+ std::string fieldname, Vector<std::string>& varnames)
+{
+ if (mf_tmp.nComp() > 3) {
+ if (lev==0) varnames.push_back(ComponentName(fieldname, 0, "real"));
+ MultiFab::Copy( mf_avg[lev], mf_tmp, 3+icomp, dcomp++, 1, ngrow);
+ int const nmodes = mf_tmp.nComp()/6;
+ for (int mode=1 ; mode < nmodes ; mode++) {
+ if (lev==0) varnames.push_back(ComponentName(fieldname, mode, "real"));
+ MultiFab::Copy( mf_avg[lev], mf_tmp, 3*2*mode+icomp, dcomp++, 1, ngrow);
+ if (lev==0) varnames.push_back(ComponentName(fieldname, mode, "imag"));
+ MultiFab::Copy( mf_avg[lev], mf_tmp, 3*2*mode+3+icomp, dcomp++, 1, ngrow);
+ }
+ }
+}
+
+/* \brief Copy scalar field component data into the MultiFab that will be written out
+ */
+void
+CopyScalarFieldComponentsToMultiFab (int lev, amrex::Vector<MultiFab>& mf_avg, MultiFab& mf_tmp,
+ int& dcomp, int ngrow, int n_rz_azimuthal_modes,
+ std::string fieldname, Vector<std::string>& varnames)
+{
+ if (n_rz_azimuthal_modes > 1) {
+ if (lev==0) varnames.push_back(ComponentName(fieldname, 0, "real"));
+ AverageAndPackScalarFieldComponent(mf_avg[lev], mf_tmp, 0, dcomp++, ngrow);
+ for (int mode=1 ; mode < n_rz_azimuthal_modes ; mode++) {
+ if (lev==0) varnames.push_back(ComponentName(fieldname, mode, "real"));
+ AverageAndPackScalarFieldComponent(mf_avg[lev], mf_tmp, 2*mode-1, dcomp++, ngrow);
+ if (lev==0) varnames.push_back(ComponentName(fieldname, mode, "imag"));
+ AverageAndPackScalarFieldComponent(mf_avg[lev], mf_tmp, 2*mode , dcomp++, ngrow);
+ }
+ }
+}
+
/** \brief Add variable names to the list.
*/
void
@@ -387,6 +484,15 @@ AddToVarNames (Vector<std::string>& varnames,
for(auto coord:coords) varnames.push_back(name+coord+suffix);
}
+/** \brief Add RZ variable names to the list.
+ */
+void
+AddToVarNamesRZ (Vector<std::string>& varnames,
+ std::string name, std::string suffix) {
+ auto coords = {"r", "theta", "z"};
+ for(auto coord:coords) varnames.push_back(name+coord+suffix);
+}
+
/** \brief Write the different fields that are meant for output,
* into the vector of MultiFab `mf_avg` (one MultiFab per level)
* after averaging them to the cell centers.
@@ -396,11 +502,28 @@ 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 = fields_to_plot.size()
+ int ncomp = fields_to_plot.size()
+ static_cast<int>(plot_finepatch)*6
+ static_cast<int>(plot_crsepatch)*6
+ static_cast<int>(costs[0] != nullptr and plot_costs);
+ // Add in the RZ modes
+ if (n_rz_azimuthal_modes > 1) {
+ for (std::string field : fields_to_plot) {
+ if (is_in_vector({"Ex", "Ey", "Ez", "Bx", "By", "Bz", "jx", "jy", "jz", "rho", "F"}, {field})) {
+ ncomp += 2*n_rz_azimuthal_modes - 1;
+ }
+ }
+ if (plot_finepatch) {
+ ncomp += 6*(2*n_rz_azimuthal_modes - 1);
+ }
+ }
+
+ int nvecs = 3;
+ if (n_rz_azimuthal_modes > 1) {
+ nvecs += 3*(2*n_rz_azimuthal_modes - 1);
+ }
+
// Loop over levels of refinement
for (int lev = 0; lev <= finest_level; ++lev)
{
@@ -413,19 +536,25 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
// Build mf_tmp_E is at least one component of E is requested
if (is_in_vector(fields_to_plot, {"Ex", "Ey", "Ez"} )){
// Allocate temp MultiFab with 3 components
- mf_tmp_E = MultiFab(grids[lev], dmap[lev], 3, ngrow);
+ mf_tmp_E = MultiFab(grids[lev], dmap[lev], nvecs, ngrow);
// Fill MultiFab mf_tmp_E with averaged E
AverageAndPackVectorField(mf_tmp_E, Efield_aux[lev], dmap[lev], 0, ngrow);
+ int dcomp = 3;
+ AverageAndPackVectorFieldComponents(mf_tmp_E, Efield_aux[lev], dmap[lev], dcomp, ngrow);
}
// Same for B
if (is_in_vector(fields_to_plot, {"Bx", "By", "Bz"} )){
- mf_tmp_B = MultiFab(grids[lev], dmap[lev], 3, ngrow);
+ mf_tmp_B = MultiFab(grids[lev], dmap[lev], nvecs, ngrow);
AverageAndPackVectorField(mf_tmp_B, Bfield_aux[lev], dmap[lev], 0, ngrow);
+ int dcomp = 3;
+ AverageAndPackVectorFieldComponents(mf_tmp_B, Bfield_aux[lev], dmap[lev], dcomp, ngrow);
}
// Same for J
if (is_in_vector(fields_to_plot, {"jx", "jy", "jz"} )){
- mf_tmp_J = MultiFab(grids[lev], dmap[lev], 3, ngrow);
+ mf_tmp_J = MultiFab(grids[lev], dmap[lev], nvecs, ngrow);
AverageAndPackVectorField(mf_tmp_J, current_fp[lev], dmap[lev], 0, ngrow);
+ int dcomp = 3;
+ AverageAndPackVectorFieldComponents(mf_tmp_J, current_fp[lev], dmap[lev], dcomp, ngrow);
}
int dcomp;
@@ -433,37 +562,51 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
// mf_avg[lev] add the corresponding names to `varnames`.
// plot_fine_patch and plot_coarse_patch are treated separately
// (after this for loop).
- for (dcomp=0; dcomp<fields_to_plot.size(); dcomp++){
- std::string fieldname = fields_to_plot[dcomp];
+ dcomp = 0;
+ for (int ifield=0; ifield<fields_to_plot.size(); ifield++){
+ std::string fieldname = fields_to_plot[ifield];
if(lev==0) varnames.push_back(fieldname);
if (fieldname == "Ex"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_E, 0, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_E, 0, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_E, 0, dcomp, ngrow, "Er", varnames);
} else if (fieldname == "Ey"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_E, 1, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_E, 1, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_E, 1, dcomp, ngrow, "Etheta", varnames);
} else if (fieldname == "Ez"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_E, 2, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_E, 2, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_E, 2, dcomp, ngrow, "Ez", varnames);
} else if (fieldname == "Bx"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_B, 0, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_B, 0, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_B, 0, dcomp, ngrow, "Br", varnames);
} else if (fieldname == "By"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_B, 1, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_B, 1, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_B, 1, dcomp, ngrow, "Btheta", varnames);
} else if (fieldname == "Bz"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_B, 2, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_B, 2, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_B, 2, dcomp, ngrow, "Bz", varnames);
} else if (fieldname == "jx"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_J, 0, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_J, 0, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_J, 0, dcomp, ngrow, "jr", varnames);
} else if (fieldname == "jy"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_J, 1, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_J, 1, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_J, 1, dcomp, ngrow, "jtheta", varnames);
} else if (fieldname == "jz"){
- MultiFab::Copy( mf_avg[lev], mf_tmp_J, 2, dcomp, 1, ngrow);
+ MultiFab::Copy( mf_avg[lev], mf_tmp_J, 2, dcomp++, 1, ngrow);
+ CopyVectorFieldComponentsToMultiFab(lev, mf_avg, mf_tmp_J, 2, dcomp, ngrow, "jz", varnames);
} else if (fieldname == "rho"){
- AverageAndPackScalarField( mf_avg[lev], *rho_fp[lev], dcomp, ngrow );
+ AverageAndPackScalarField( mf_avg[lev], *rho_fp[lev], dcomp++, ngrow );
+ CopyScalarFieldComponentsToMultiFab(lev, mf_avg, *rho_fp[lev], dcomp, ngrow, n_rz_azimuthal_modes,
+ fieldname, varnames);
} else if (fieldname == "F"){
- AverageAndPackScalarField( mf_avg[lev], *F_fp[lev], dcomp, ngrow);
+ AverageAndPackScalarField( mf_avg[lev], *F_fp[lev], dcomp++, ngrow );
+ CopyScalarFieldComponentsToMultiFab(lev, mf_avg, *F_fp[lev], dcomp, ngrow, n_rz_azimuthal_modes,
+ fieldname, varnames);
} else if (fieldname == "part_per_cell") {
MultiFab temp_dat(grids[lev],mf_avg[lev].DistributionMap(),1,0);
temp_dat.setVal(0);
// MultiFab containing number of particles in each cell
mypc->Increment(temp_dat, lev);
- AverageAndPackScalarField( mf_avg[lev], temp_dat, dcomp, ngrow );
+ AverageAndPackScalarField( mf_avg[lev], temp_dat, dcomp++, ngrow );
} else if (fieldname == "part_per_grid"){
const Vector<long>& npart_in_grid = mypc->NumberOfParticlesInGrid(lev);
// MultiFab containing number of particles per grid
@@ -473,7 +616,7 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
#endif
for (MFIter mfi(mf_avg[lev]); mfi.isValid(); ++mfi) {
(mf_avg[lev])[mfi].setVal(static_cast<Real>(npart_in_grid[mfi.index()]),
- dcomp);
+ dcomp++);
}
} else if (fieldname == "part_per_proc"){
const Vector<long>& npart_in_grid = mypc->NumberOfParticlesInGrid(lev);
@@ -486,7 +629,7 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
for (MFIter mfi(mf_avg[lev]); mfi.isValid(); ++mfi) {
n_per_proc += npart_in_grid[mfi.index()];
}
- mf_avg[lev].setVal(static_cast<Real>(n_per_proc), dcomp,1);
+ mf_avg[lev].setVal(static_cast<Real>(n_per_proc), dcomp++,1);
} else if (fieldname == "proc_number"){
// MultiFab containing the Processor ID
#ifdef _OPENMP
@@ -494,11 +637,11 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
#endif
for (MFIter mfi(mf_avg[lev]); mfi.isValid(); ++mfi) {
(mf_avg[lev])[mfi].setVal(static_cast<Real>(ParallelDescriptor::MyProc()),
- dcomp);
+ dcomp++);
}
} else if (fieldname == "divB"){
if (do_nodal) amrex::Abort("TODO: do_nodal && plot divb");
- ComputeDivB(mf_avg[lev], dcomp,
+ ComputeDivB(mf_avg[lev], dcomp++,
{Bfield_aux[lev][0].get(),
Bfield_aux[lev][1].get(),
Bfield_aux[lev][2].get()},
@@ -512,7 +655,7 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
Efield_aux[lev][1].get(),
Efield_aux[lev][2].get()},
WarpX::CellSize(lev) );
- AverageAndPackScalarField( mf_avg[lev], dive, dcomp, ngrow );
+ AverageAndPackScalarField( mf_avg[lev], dive, dcomp++, ngrow );
} else {
amrex::Abort("unknown field in fields_to_plot: " + fieldname);
}
@@ -520,11 +663,31 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
if (plot_finepatch)
{
AverageAndPackVectorField( mf_avg[lev], Efield_fp[lev], dmap[lev], dcomp, ngrow );
- if (lev == 0) AddToVarNames(varnames, "E", "_fp");
dcomp += 3;
+ AverageAndPackVectorFieldComponents(mf_avg[lev], Efield_fp[lev], dmap[lev], dcomp, ngrow);
+ if (lev == 0) {
+ AddToVarNames(varnames, "E", "_fp");
+ if (n_rz_azimuthal_modes > 1) {
+ AddToVarNamesRZ(varnames, "E", ComponentName("_fp", 0, "real"));
+ for (int mode=1 ; mode < n_rz_azimuthal_modes ; mode++) {
+ AddToVarNamesRZ(varnames, "E", ComponentName("_fp", mode, "real"));
+ AddToVarNamesRZ(varnames, "E", ComponentName("_fp", mode, "imag"));
+ }
+ }
+ }
AverageAndPackVectorField( mf_avg[lev], Bfield_fp[lev], dmap[lev], dcomp, ngrow );
- if (lev == 0) AddToVarNames(varnames, "B", "_fp");
dcomp += 3;
+ AverageAndPackVectorFieldComponents(mf_avg[lev], Bfield_fp[lev], dmap[lev], dcomp, ngrow);
+ if (lev == 0) {
+ AddToVarNames(varnames, "B", "_fp");
+ if (n_rz_azimuthal_modes > 1) {
+ AddToVarNamesRZ(varnames, "B", ComponentName("_fp", 0, "real"));
+ for (int mode=1 ; mode < n_rz_azimuthal_modes ; mode++) {
+ AddToVarNamesRZ(varnames, "B", ComponentName("_fp", mode, "real"));
+ AddToVarNamesRZ(varnames, "B", ComponentName("_fp", mode, "imag"));
+ }
+ }
+ }
}
if (plot_crsepatch)
diff --git a/Source/Diagnostics/Make.package b/Source/Diagnostics/Make.package
index 710e4399b..12560b49e 100644
--- a/Source/Diagnostics/Make.package
+++ b/Source/Diagnostics/Make.package
@@ -15,5 +15,7 @@ ifeq ($(USE_OPENPMD), TRUE)
CEXE_sources += WarpXOpenPMD.cpp
endif
+include $(WARPX_HOME)/Source/Diagnostics/ReducedDiags/Make.package
+
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 c08d58d36..ca9e86fdd 100644
--- a/Source/Diagnostics/ParticleIO.cpp
+++ b/Source/Diagnostics/ParticleIO.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Grote
+ * Luca Fedeli, Maxence Thevenet, Revathi Jambunathan
+ * Weiqun Zhang, levinem
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <MultiParticleContainer.H>
#include <WarpX.H>
diff --git a/Source/Diagnostics/ReducedDiags/FieldEnergy.H b/Source/Diagnostics/ReducedDiags/FieldEnergy.H
new file mode 100644
index 000000000..82fa4b6c4
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/FieldEnergy.H
@@ -0,0 +1,36 @@
+/* Copyright 2019-2020 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#ifndef WARPX_DIAGNOSTICS_REDUCEDDIAGS_FIELDENERGY_H_
+#define WARPX_DIAGNOSTICS_REDUCEDDIAGS_FIELDENERGY_H_
+
+#include "ReducedDiags.H"
+#include <fstream>
+
+/**
+ * This class mainly contains a function that
+ * computes the field energy.
+ */
+class FieldEnergy : public ReducedDiags
+{
+public:
+
+ /** constructor
+ * @param[in] rd_name reduced diags names */
+ FieldEnergy(std::string rd_name);
+
+ /** This funciton computes the field energy (EF).
+ * EF = E eps / 2 + B / mu / 2,
+ * where E is the electric field,
+ * B is the magnetic field,
+ * eps is the vacuum permittivity,
+ * mu is the vacuum permeability. */
+ virtual void ComputeDiags(int step) override final;
+
+};
+
+#endif
diff --git a/Source/Diagnostics/ReducedDiags/FieldEnergy.cpp b/Source/Diagnostics/ReducedDiags/FieldEnergy.cpp
new file mode 100644
index 000000000..73e6a1c9a
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/FieldEnergy.cpp
@@ -0,0 +1,139 @@
+/* Copyright 2019-2020 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#include "FieldEnergy.H"
+#include "WarpX.H"
+#include "WarpXConst.H"
+#include "AMReX_REAL.H"
+#include "AMReX_ParticleReduce.H"
+#include <iostream>
+#include <cmath>
+
+using namespace amrex;
+
+// constructor
+FieldEnergy::FieldEnergy (std::string rd_name)
+: ReducedDiags{rd_name}
+{
+
+ // RZ coordinate is not working
+ #if (defined WARPX_DIM_RZ)
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false,
+ "FieldEnergy reduced diagnostics does not work for RZ coordinate.");
+ #endif
+
+ // get WarpX class object
+ auto & warpx = WarpX::GetInstance();
+
+ // read number of levels
+ int nLevel = 0;
+ ParmParse pp("amr");
+ pp.query("max_level", nLevel);
+ nLevel += 1;
+
+ // resize data array
+ m_data.resize(3*nLevel,0.0);
+
+ if (ParallelDescriptor::IOProcessor())
+ {
+ if ( m_IsNotRestart )
+ {
+ // open file
+ std::ofstream ofs;
+ ofs.open(m_path + m_rd_name + "." + m_extension,
+ std::ofstream::out | std::ofstream::app);
+ // write header row
+ ofs << "#";
+ ofs << "[1]step";
+ ofs << m_sep;
+ ofs << "[2]time(s)";
+ for (int lev = 0; lev < nLevel; ++lev)
+ {
+ ofs << m_sep;
+ ofs << "[" + std::to_string(3+3*lev) + "]";
+ ofs << "total(J)lev"+std::to_string(lev);
+ ofs << m_sep;
+ ofs << "[" + std::to_string(4+3*lev) + "]";
+ ofs << "E(J)lev"+std::to_string(lev);
+ ofs << m_sep;
+ ofs << "[" + std::to_string(5+3*lev) + "]";
+ ofs << "B(J)lev"+std::to_string(lev);
+ }
+ ofs << std::endl;
+ // close file
+ ofs.close();
+ }
+ }
+
+}
+// end constructor
+
+// function that computes field energy
+void FieldEnergy::ComputeDiags (int step)
+{
+
+ // Judge if the diags should be done
+ if ( (step+1) % m_freq != 0 ) { return; }
+
+ // get WarpX class object
+ auto & warpx = WarpX::GetInstance();
+
+ // get number of level
+ auto nLevel = warpx.finestLevel() + 1;
+
+ // loop over refinement levels
+ for (int lev = 0; lev < nLevel; ++lev)
+ {
+
+ // get MultiFab data at lev
+ const MultiFab & Ex = warpx.getEfield(lev,0);
+ const MultiFab & Ey = warpx.getEfield(lev,1);
+ const MultiFab & Ez = warpx.getEfield(lev,2);
+ const MultiFab & Bx = warpx.getBfield(lev,0);
+ const MultiFab & By = warpx.getBfield(lev,1);
+ const MultiFab & Bz = warpx.getBfield(lev,2);
+
+ // get cell size
+ Geometry const & geom = warpx.Geom(lev);
+ auto domain_box = geom.Domain();
+ #if (AMREX_SPACEDIM == 2)
+ auto dV = geom.CellSize(0) * geom.CellSize(1);
+ #elif (AMREX_SPACEDIM == 3)
+ auto dV = geom.CellSize(0) * geom.CellSize(1) * geom.CellSize(2);
+ #endif
+
+ // compute E squared
+ Real tmpx = Ex.norm2(0,geom.periodicity());
+ Real tmpy = Ey.norm2(0,geom.periodicity());
+ Real tmpz = Ez.norm2(0,geom.periodicity());
+ Real Es = tmpx*tmpx + tmpy*tmpy + tmpz*tmpz;
+
+ // compute B squared
+ tmpx = Bx.norm2(0,geom.periodicity());
+ tmpy = By.norm2(0,geom.periodicity());
+ tmpz = Bz.norm2(0,geom.periodicity());
+ Real Bs = tmpx*tmpx + tmpy*tmpy + tmpz*tmpz;
+
+ // save data
+ m_data[lev*3+1] = 0.5 * Es * PhysConst::ep0 * dV;
+ m_data[lev*3+2] = 0.5 * Bs / PhysConst::mu0 * dV;
+ m_data[lev*3+0] = m_data[lev*3+1] + m_data[lev*3+2];
+
+ }
+ // end loop over refinement levels
+
+ /* m_data now contains up-to-date values for:
+ * [total field energy at level 0,
+ * electric field energy at level 0,
+ * magnetic field energy at level 0,
+ * total field energy at level 1,
+ * electric field energy at level 1,
+ * magnetic field energy at level 1,
+ * ......] */
+
+}
+// end void FieldEnergy::ComputeDiags
diff --git a/Source/Diagnostics/ReducedDiags/Make.package b/Source/Diagnostics/ReducedDiags/Make.package
new file mode 100644
index 000000000..37f76d3d5
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/Make.package
@@ -0,0 +1,14 @@
+CEXE_headers += MultiReducedDiags.H
+CEXE_sources += MultiReducedDiags.cpp
+
+CEXE_headers += ReducedDiags.H
+CEXE_sources += ReducedDiags.cpp
+
+CEXE_headers += ParticleEnergy.H
+CEXE_sources += ParticleEnergy.cpp
+
+CEXE_headers += FieldEnergy.H
+CEXE_sources += FieldEnergy.cpp
+
+INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Diagnostics/ReducedDiags
+VPATH_LOCATIONS += $(WARPX_HOME)/Source/Diagnostics/ReducedDiags
diff --git a/Source/Diagnostics/ReducedDiags/MultiReducedDiags.H b/Source/Diagnostics/ReducedDiags/MultiReducedDiags.H
new file mode 100644
index 000000000..79f487d81
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/MultiReducedDiags.H
@@ -0,0 +1,47 @@
+/* Copyright 2019-2020 Maxence Thevenet, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#ifndef WARPX_DIAGNOSTICS_REDUCEDDIAGS_MULTIREDUCEDDIAGS_H_
+#define WARPX_DIAGNOSTICS_REDUCEDDIAGS_MULTIREDUCEDDIAGS_H_
+
+#include "ReducedDiags.H"
+#include <vector>
+#include <string>
+#include <memory>
+
+/**
+ * This class holds multiple instances of ReducedDiagnostics, and contains
+ * general functions to initialize, compute, and write these diagnostics
+ * to file.
+ */
+class MultiReducedDiags
+{
+public:
+
+ /// Bool: whether or not reduced diagnostics are activated
+ int m_plot_rd = 0;
+
+ /// names of reduced diagnostics
+ std::vector<std::string> m_rd_names;
+
+ /// m_multi_rd stores a pointer to each reduced diagnostics
+ std::vector<std::unique_ptr<ReducedDiags>> m_multi_rd;
+
+ /// constructor
+ MultiReducedDiags();
+
+ /** Loop over all ReducedDiags and call their ComputeDiags
+ * @param[in] step current iteration time */
+ void ComputeDiags(int step);
+
+ /** Loop over all ReducedDiags and call their WriteToFile
+ * @param[in] step current iteration time */
+ void WriteToFile(int step);
+
+};
+
+#endif
diff --git a/Source/Diagnostics/ReducedDiags/MultiReducedDiags.cpp b/Source/Diagnostics/ReducedDiags/MultiReducedDiags.cpp
new file mode 100644
index 000000000..71a33924b
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/MultiReducedDiags.cpp
@@ -0,0 +1,94 @@
+/* Copyright 2019-2020 Maxence Thevenet, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#include "ParticleEnergy.H"
+#include "FieldEnergy.H"
+#include "MultiReducedDiags.H"
+#include "AMReX_ParmParse.H"
+#include "AMReX_ParallelDescriptor.H"
+#include <fstream>
+
+using namespace amrex;
+
+// constructor
+MultiReducedDiags::MultiReducedDiags ()
+{
+
+ // read reduced diags names
+ ParmParse pp("warpx");
+ m_plot_rd = pp.queryarr("reduced_diags_names", m_rd_names);
+
+ // if names are not given, reduced diags will not be done
+ if ( m_plot_rd == 0 ) { return; }
+
+ // resize
+ m_multi_rd.resize(m_rd_names.size());
+
+ // loop over all reduced diags
+ for (int i_rd = 0; i_rd < m_rd_names.size(); ++i_rd)
+ {
+
+ ParmParse pp(m_rd_names[i_rd]);
+
+ // read reduced diags type
+ std::string rd_type;
+ pp.query("type", rd_type);
+
+ // match diags
+ if (rd_type.compare("ParticleEnergy") == 0)
+ {
+ m_multi_rd[i_rd].reset
+ ( new ParticleEnergy(m_rd_names[i_rd]));
+ }
+ else if (rd_type.compare("FieldEnergy") == 0)
+ {
+ m_multi_rd[i_rd].reset
+ ( new FieldEnergy(m_rd_names[i_rd]));
+ }
+ else
+ { Abort("No matching reduced diagnostics type found."); }
+ // end if match diags
+
+ }
+ // end loop over all reduced diags
+
+}
+// end constructor
+
+// call functions to compute diags
+void MultiReducedDiags::ComputeDiags (int step)
+{
+ // loop over all reduced diags
+ for (int i_rd = 0; i_rd < m_rd_names.size(); ++i_rd)
+ {
+ m_multi_rd[i_rd] -> ComputeDiags(step);
+ }
+ // end loop over all reduced diags
+}
+// end void MultiReducedDiags::ComputeDiags
+
+// funciton to write data
+void MultiReducedDiags::WriteToFile (int step)
+{
+
+ // Only the I/O rank does
+ if ( !ParallelDescriptor::IOProcessor() ) { return; }
+
+ // loop over all reduced diags
+ for (int i_rd = 0; i_rd < m_rd_names.size(); ++i_rd)
+ {
+
+ // Judge if the diags should be done
+ if ( (step+1) % m_multi_rd[i_rd]->m_freq != 0 ) { return; }
+
+ // call the write to file function
+ m_multi_rd[i_rd]->WriteToFile(step);
+
+ }
+ // end loop over all reduced diags
+}
+// end void MultiReducedDiags::WriteToFile
diff --git a/Source/Diagnostics/ReducedDiags/ParticleEnergy.H b/Source/Diagnostics/ReducedDiags/ParticleEnergy.H
new file mode 100644
index 000000000..d7c60a24e
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/ParticleEnergy.H
@@ -0,0 +1,37 @@
+/* Copyright 2019-2020 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#ifndef WARPX_DIAGNOSTICS_REDUCEDDIAGS_PARTICLEENERGY_H_
+#define WARPX_DIAGNOSTICS_REDUCEDDIAGS_PARTICLEENERGY_H_
+
+#include "ReducedDiags.H"
+#include <fstream>
+
+/**
+ * This class mainly contains a function that
+ * computes the particle relativistic kinetic energy
+ * of each species.
+ */
+class ParticleEnergy : public ReducedDiags
+{
+public:
+
+ /** constructor
+ * @param[in] rd_name reduced diags names */
+ ParticleEnergy(std::string rd_name);
+
+ /** This funciton computes the particle relativistic
+ * kinetic energy (EP).
+ * \param [in] step current time step
+ * EP = sqrt( p^2 c^2 + m^2 c^4 ) - m c^2,
+ * where p is the relativistic momentum,
+ * m is the particle rest mass. */
+ virtual void ComputeDiags(int step) override final;
+
+};
+
+#endif
diff --git a/Source/Diagnostics/ReducedDiags/ParticleEnergy.cpp b/Source/Diagnostics/ReducedDiags/ParticleEnergy.cpp
new file mode 100644
index 000000000..132ad2165
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/ParticleEnergy.cpp
@@ -0,0 +1,166 @@
+/* Copyright 2019-2020 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#include "ParticleEnergy.H"
+#include "WarpX.H"
+#include "WarpXConst.H"
+#include "AMReX_REAL.H"
+#include "AMReX_ParticleReduce.H"
+#include <iostream>
+#include <cmath>
+#include <limits>
+
+using namespace amrex;
+
+// constructor
+ParticleEnergy::ParticleEnergy (std::string rd_name)
+: ReducedDiags{rd_name}
+{
+ // get WarpX class object
+ auto & warpx = WarpX::GetInstance();
+
+ // get MultiParticleContainer class object
+ auto & mypc = warpx.GetPartContainer();
+
+ // get number of species (int)
+ auto nSpecies = mypc.nSpecies();
+
+ // resize data array
+ m_data.resize(2*nSpecies+2,0.0);
+
+ // get species names (std::vector<std::string>)
+ auto species_names = mypc.GetSpeciesNames();
+
+ if (ParallelDescriptor::IOProcessor())
+ {
+ if ( m_IsNotRestart )
+ {
+ // open file
+ std::ofstream ofs;
+ ofs.open(m_path + m_rd_name + "." + m_extension,
+ std::ofstream::out | std::ofstream::app);
+ // write header row
+ ofs << "#";
+ ofs << "[1]step";
+ ofs << m_sep;
+ ofs << "[2]time(s)";
+ ofs << m_sep;
+ ofs << "[3]total(J)";
+ for (int i = 0; i < nSpecies; ++i)
+ {
+ ofs << m_sep;
+ ofs << "[" + std::to_string(4+i) + "]";
+ ofs << species_names[i]+"(J)";
+ }
+ ofs << m_sep;
+ ofs << "[" + std::to_string(4+nSpecies) + "]";
+ ofs << "total.mean(J)";
+ for (int i = 0; i < nSpecies; ++i)
+ {
+ ofs << m_sep;
+ ofs << "[" + std::to_string(5+nSpecies+i) + "]";
+ ofs << species_names[i]+".mean(J)";
+ }
+ ofs << std::endl;
+ // close file
+ ofs.close();
+ }
+ }
+
+}
+// end constructor
+
+// function that computes kinetic energy
+void ParticleEnergy::ComputeDiags (int step)
+{
+
+ // Judge if the diags should be done
+ if ( (step+1) % m_freq != 0 ) { return; }
+
+ // get MultiParticleContainer class object
+ auto & mypc = WarpX::GetInstance().GetPartContainer();
+
+ // get number of species (int)
+ auto nSpecies = mypc.nSpecies();
+
+ // get species names (std::vector<std::string>)
+ auto species_names = mypc.GetSpeciesNames();
+
+ // speed of light squared
+ auto c2 = PhysConst::c * PhysConst::c;
+
+ // loop over species
+ for (int i_s = 0; i_s < nSpecies; ++i_s)
+ {
+ // get WarpXParticleContainer class object
+ auto & myspc = mypc.GetParticleContainer(i_s);
+
+ // get mass (Real)
+ auto m = myspc.getMass();
+
+ using PType = typename WarpXParticleContainer::SuperParticleType;
+
+ // Use amex::ReduceSum to compute the sum of energies of all particles
+ // held by the current MPI rank, for this species. This involves a loop over all
+ // boxes held by this MPI rank.
+ auto Etot = ReduceSum( myspc,
+ [=] AMREX_GPU_HOST_DEVICE (const PType& p) -> Real
+ {
+ auto w = p.rdata(PIdx::w);
+ auto ux = p.rdata(PIdx::ux);
+ auto uy = p.rdata(PIdx::uy);
+ auto uz = p.rdata(PIdx::uz);
+ auto us = (ux*ux + uy*uy + uz*uz);
+ return ( std::sqrt(us*c2 + c2*c2) - c2 ) * m * w;
+ });
+
+ // Same thing for the particles weights.
+ auto Wtot = ReduceSum( myspc,
+ [=] AMREX_GPU_HOST_DEVICE (const PType& p) -> Real
+ {
+ return p.rdata(PIdx::w);
+ });
+
+ // reduced sum over mpi ranks
+ ParallelDescriptor::ReduceRealSum
+ (Etot, ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::ReduceRealSum
+ (Wtot, ParallelDescriptor::IOProcessorNumber());
+
+ // save results for this species i_s into m_data
+ m_data[i_s+1] = Etot;
+ if ( Wtot > std::numeric_limits<Real>::min() )
+ { m_data[nSpecies+2+i_s] = Etot / Wtot; }
+ else
+ { m_data[nSpecies+2+i_s] = 0.0; }
+
+ }
+ // end loop over species
+
+ // save total energy
+ // loop over species
+ m_data[0] = 0.0; // total energy
+ m_data[nSpecies+1] = 0.0; // total mean energy
+ for (int i_s = 0; i_s < nSpecies; ++i_s)
+ {
+ m_data[0] += m_data[i_s+1];
+ m_data[nSpecies+1] += m_data[nSpecies+2+i_s];
+ }
+ // end loop over species
+
+ /* m_data now contains up-to-date values for:
+ * [total energy (all species),
+ * total energy (species 1),
+ * ...,
+ * total energy (species n),
+ * mean energy (all species),
+ * mean energy (species 1),
+ * ...,
+ * mean energy (species n)] */
+
+}
+// end void ParticleEnergy::ComputeDiags
diff --git a/Source/Diagnostics/ReducedDiags/ReducedDiags.H b/Source/Diagnostics/ReducedDiags/ReducedDiags.H
new file mode 100644
index 000000000..7ff065f49
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/ReducedDiags.H
@@ -0,0 +1,59 @@
+/* Copyright 2019-2020 Maxence Thevenet, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#ifndef WARPX_DIAGNOSTICS_REDUCEDDIAGS_REDUCEDDIAGS_H_
+#define WARPX_DIAGNOSTICS_REDUCEDDIAGS_REDUCEDDIAGS_H_
+
+#include "AMReX_REAL.H"
+#include <string>
+#include <vector>
+#include <fstream>
+
+/**
+ * Base class for reduced diagnostics. Each type of reduced diagnostics is
+ * implemented in a derived class, and must override the (pure virtual)
+ * function ComputeDiags.
+ */
+class ReducedDiags
+{
+public:
+
+ /// output path (default)
+ std::string m_path = "./diags/reducedfiles/";
+
+ /// output extension (default)
+ std::string m_extension = "txt";
+
+ /// diags name
+ std::string m_rd_name;
+
+ /// output frequency
+ int m_freq = 1;
+
+ /// check if it is a restart run
+ int m_IsNotRestart = 1;
+
+ /// separator in the output file
+ std::string m_sep = ",";
+
+ /// output data
+ std::vector<amrex::Real> m_data;
+
+ /** constructor
+ * @param[in] rd_name reduced diags name */
+ ReducedDiags(std::string rd_name);
+
+ /// function to compute diags
+ virtual void ComputeDiags(int step) = 0;
+
+ /** write to file function
+ * @param[in] step time step */
+ virtual void WriteToFile(int step) const;
+
+};
+
+#endif
diff --git a/Source/Diagnostics/ReducedDiags/ReducedDiags.cpp b/Source/Diagnostics/ReducedDiags/ReducedDiags.cpp
new file mode 100644
index 000000000..81831aa79
--- /dev/null
+++ b/Source/Diagnostics/ReducedDiags/ReducedDiags.cpp
@@ -0,0 +1,92 @@
+/* Copyright 2019-2020 Maxence Thevenet, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+
+#include "ReducedDiags.H"
+#include "WarpX.H"
+#include "AMReX_ParmParse.H"
+#include "AMReX_Utility.H"
+#include <iomanip>
+
+using namespace amrex;
+
+// constructor
+ReducedDiags::ReducedDiags (std::string rd_name)
+{
+
+ m_rd_name = rd_name;
+
+ ParmParse pp(m_rd_name);
+
+ // read path
+ pp.query("path", m_path);
+
+ // read extension
+ pp.query("extension", m_extension);
+
+ // creater folder
+ if (!UtilCreateDirectory(m_path, 0755))
+ { CreateDirectoryFailed(m_path); }
+
+ // check if it is a restart run
+ std::string restart_chkfile = "";
+ ParmParse pp_amr("amr");
+ pp_amr.query("restart", restart_chkfile);
+ m_IsNotRestart = restart_chkfile.empty();
+
+ // replace / create output file
+ if ( m_IsNotRestart ) // not a restart
+ {
+ std::ofstream ofs;
+ ofs.open(m_path+m_rd_name+"."+m_extension, std::ios::trunc);
+ ofs.close();
+ }
+
+ // read reduced diags frequency
+ pp.query("frequency", m_freq);
+
+ // read separator
+ pp.query("separator", m_sep);
+
+}
+// end constructor
+
+// write to file function
+void ReducedDiags::WriteToFile (int step) const
+{
+
+ // open file
+ std::ofstream ofs;
+ ofs.open(m_path + m_rd_name + "." + m_extension,
+ std::ofstream::out | std::ofstream::app);
+
+ // write step
+ ofs << step+1;
+
+ ofs << m_sep;
+
+ // set precision
+ ofs << std::fixed << std::setprecision(14) << std::scientific;
+
+ // write time
+ ofs << WarpX::GetInstance().gett_new(0);
+
+ // loop over data size and write
+ for (int i = 0; i < m_data.size(); ++i)
+ {
+ ofs << m_sep;
+ ofs << m_data[i];
+ }
+ // end loop over data size
+
+ // end line
+ ofs << std::endl;
+
+ // close file
+ ofs.close();
+
+}
+// end ReducedDiags::WriteToFile
diff --git a/Source/Diagnostics/SliceDiagnostic.H b/Source/Diagnostics/SliceDiagnostic.H
index 1b9ca3967..68a8c1f92 100644
--- a/Source/Diagnostics/SliceDiagnostic.H
+++ b/Source/Diagnostics/SliceDiagnostic.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SliceDiagnostic_H_
#define WARPX_SliceDiagnostic_H_
diff --git a/Source/Diagnostics/SliceDiagnostic.cpp b/Source/Diagnostics/SliceDiagnostic.cpp
index 79f03985b..c6b5dd4da 100644
--- a/Source/Diagnostics/SliceDiagnostic.cpp
+++ b/Source/Diagnostics/SliceDiagnostic.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Luca Fedeli, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "SliceDiagnostic.H"
#include <AMReX_MultiFabUtil.H>
#include <AMReX_PlotFileUtil.H>
@@ -236,8 +243,10 @@ CheckSliceInput( const RealBox real_box, RealBox &slice_cc_nd_box,
{
// 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) );
+ int log_cr_ratio =
+ static_cast<int>(floor ( log2( double(slice_cr_ratio[idim]))));
+ slice_cr_ratio[idim] =
+ static_cast<int> (exp2( double(log_cr_ratio) ));
}
//// Default coarsening ratio is 1 //
@@ -269,20 +278,24 @@ CheckSliceInput( const RealBox real_box, RealBox &slice_cc_nd_box,
// 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)
+ slice_lo[idim] = static_cast<int>(
+ 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)
+ / dom_geom[0].CellSize(idim)) + fac * 1E-10) );
+ slice_lo2[idim] = static_cast<int>(
+ ceil( ( (slice_cc_nd_box.lo(idim)
- (real_box.lo(idim) + fac) )
- / dom_geom[0].CellSize(idim)) - fac * 1E-10 );
+ / dom_geom[0].CellSize(idim)) - fac * 1E-10 ) );
}
else {
- slice_lo[idim] = round( (slice_cc_nd_box.lo(idim)
+ slice_lo[idim] = static_cast<int>(
+ 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)
+ / dom_geom[0].CellSize(idim)) );
+ slice_lo2[idim] = static_cast<int>(
+ ceil((slice_cc_nd_box.lo(idim)
- (real_box.lo(idim) ) )
- / dom_geom[0].CellSize(idim) );
+ / dom_geom[0].CellSize(idim) ) );
}
// flag for interpolation -- if reduced dimension location //
@@ -302,10 +315,10 @@ CheckSliceInput( const RealBox real_box, RealBox &slice_cc_nd_box,
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)));
+ auto index_lo = static_cast<int>(floor(((slice_realbox.lo(idim) + 1E-10
+ - (real_box.lo(idim))) / dom_geom[0].CellSize(idim))) );
+ auto index_hi = static_cast<int>(ceil(((slice_realbox.hi(idim) - 1E-10
+ - (real_box.lo(idim))) / dom_geom[0].CellSize(idim))) );
bool modify_cr = true;
diff --git a/Source/Diagnostics/WarpXIO.cpp b/Source/Diagnostics/WarpXIO.cpp
index 31a5f700d..f85b9df3b 100644
--- a/Source/Diagnostics/WarpXIO.cpp
+++ b/Source/Diagnostics/WarpXIO.cpp
@@ -1,3 +1,12 @@
+/* Copyright 2019-2020 Andrew Myers, Ann Almgren, Axel Huebl
+ * Burlen Loring, David Grote, Gunther H. Weber
+ * Junmin Gu, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <AMReX_MultiFabUtil.H>
#include <AMReX_PlotFileUtil.H>
#include <AMReX_FillPatchUtil_F.H>
@@ -19,7 +28,7 @@
#endif
#ifdef WARPX_USE_OPENPMD
-#include "WarpXOpenPMD.H"
+# include "WarpXOpenPMD.H"
#endif
@@ -499,41 +508,68 @@ WarpX::UpdateInSitu () const
}
void
-WarpX::WritePlotFile () const
-{
- BL_PROFILE("WarpX::WritePlotFile()");
-
- const std::string& plotfilename = amrex::Concatenate(plot_file,istep[0]);
- amrex::Print() << " Writing plotfile " << plotfilename << "\n";
-
+WarpX::prepareFields(
+ int const step,
+ Vector<std::string>& varnames,
+ Vector<MultiFab>& mf_avg,
+ Vector<const MultiFab*>& output_mf,
+ Vector<Geometry>& output_geom
+) const {
// Average the fields from the simulation grid to the cell centers
const int ngrow = 0;
- Vector<std::string> varnames; // Name of the written fields
- // mf_avg will contain the averaged, cell-centered fields
- Vector<MultiFab> mf_avg;
WarpX::AverageAndPackFields( varnames, mf_avg, ngrow );
// Coarsen the fields, if requested by the user
- Vector<const MultiFab*> output_mf; // will point to the data to be written
Vector<MultiFab> coarse_mf; // will remain empty if there is no coarsening
- Vector<Geometry> output_geom;
if (plot_coarsening_ratio != 1) {
coarsenCellCenteredFields( coarse_mf, output_geom, mf_avg, Geom(),
- plot_coarsening_ratio, finest_level );
+ plot_coarsening_ratio, finest_level );
output_mf = amrex::GetVecOfConstPtrs(coarse_mf);
} else { // No averaging necessary, simply point to mf_avg
output_mf = amrex::GetVecOfConstPtrs(mf_avg);
output_geom = Geom();
}
+}
+
+void
+WarpX::WriteOpenPMDFile () const
+{
+ BL_PROFILE("WarpX::WriteOpenPMDFile()");
#ifdef WARPX_USE_OPENPMD
- m_OpenPMDPlotWriter->SetStep(istep[0]);
- if (dump_openpmd)
- m_OpenPMDPlotWriter->WriteOpenPMDFields(varnames,
- *output_mf[0], output_geom[0], istep[0], t_new[0] );
+ const auto step = istep[0];
+
+ Vector<std::string> varnames; // Name of the written fields
+ Vector<MultiFab> mf_avg; // contains the averaged, cell-centered fields
+ Vector<const MultiFab*> output_mf; // will point to the data to be written
+ Vector<Geometry> output_geom;
+
+ prepareFields(step, varnames, mf_avg, output_mf, output_geom);
+
+ m_OpenPMDPlotWriter->SetStep(step);
+ // fields: only dumped for coarse level
+ m_OpenPMDPlotWriter->WriteOpenPMDFields(
+ varnames, *output_mf[0], output_geom[0], step, t_new[0]);
+ // particles: all (reside only on locally finest level)
+ m_OpenPMDPlotWriter->WriteOpenPMDParticles(mypc);
#endif
+}
+
+void
+WarpX::WritePlotFile () const
+{
+ BL_PROFILE("WarpX::WritePlotFile()");
- if (dump_plotfiles || dump_openpmd) {
+ const auto step = istep[0];
+ const std::string& plotfilename = amrex::Concatenate(plot_file,step);
+ amrex::Print() << " Writing plotfile " << plotfilename << "\n";
+
+ Vector<std::string> varnames; // Name of the written fields
+ Vector<MultiFab> mf_avg; // contains the averaged, cell-centered fields
+ Vector<const MultiFab*> output_mf; // will point to the data to be written
+ Vector<Geometry> output_geom;
+
+ prepareFields(step, varnames, mf_avg, output_mf, output_geom);
// Write the fields contained in `mf_avg`, and corresponding to the
// names `varnames`, into a plotfile.
@@ -616,23 +652,13 @@ WarpX::WritePlotFile () const
}
}
-#ifdef WARPX_USE_OPENPMD
- // Write openPMD format: only for level 0
- if (dump_openpmd)
- m_OpenPMDPlotWriter->WriteOpenPMDParticles(mypc);
-#endif
- // leaving the option of binary output through AMREx around
- // regardless of openPMD. This can be adjusted later
- {
- mypc->WritePlotFile(plotfilename);
- }
+ mypc->WritePlotFile(plotfilename);
WriteJobInfo(plotfilename);
WriteWarpXHeader(plotfilename);
VisMF::SetHeaderVersion(current_version);
- } // endif: dump_plotfiles
}
diff --git a/Source/Diagnostics/WarpXOpenPMD.H b/Source/Diagnostics/WarpXOpenPMD.H
index c79a12066..bd18ec8c1 100644
--- a/Source/Diagnostics/WarpXOpenPMD.H
+++ b/Source/Diagnostics/WarpXOpenPMD.H
@@ -1,10 +1,27 @@
+/* Copyright 2019-2020 Axel Huebl, Junmin Gu, Maxence Thevenet
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_OPEN_PMD_H_
#define WARPX_OPEN_PMD_H_
-#include <MultiParticleContainer.H> // has AMReX Vector etc used below
+#include "WarpXParticleContainer.H"
+#include "MultiParticleContainer.H" // PIdx
+
+#include <AMReX_ParallelDescriptor.H>
+#include <AMReX_REAL.H>
+#include <AMReX_Utility.H>
#include <openPMD/openPMD.hpp>
+#include <memory>
+#include <string>
+#include <vector>
+
+
//
// helper class
//
@@ -61,10 +78,14 @@ private:
class WarpXOpenPMDPlot
{
public:
- // not using const string, to allow std::move to be effective
- WarpXOpenPMDPlot(bool, std::string& filetype);
+ /** Initialize openPMD I/O routines
+ *
+ * @param oneFilePerTS write one file per timestep
+ * @param filetype file backend, e.g. "bp" or "h5"
+ * @param fieldPMLdirections PML field solver, @see WarpX::getPMLdirections()
+ */
+ WarpXOpenPMDPlot(bool oneFilePerTS, std::string filetype, std::vector<bool> fieldPMLdirections);
- //WarpXOpenPMDPlot(const std::string& dir, const std::string& fileType);
~WarpXOpenPMDPlot();
void SetStep(int ts);
@@ -82,12 +103,14 @@ private:
void Init(//const std::string& filename,
openPMD::AccessType accessType);
- /** This function sets up the entries for storing the particle positions in an openPMD species
+ /** This function sets up the entries for storing the particle positions, global IDs, and constant records (charge, mass)
*
- * @param[in] currSpecies The openPMD species
- * @param[in] np Number of particles
+ * @param[in] pc WarpX particle container
+ * @param[in] currSpecies Corresponding openPMD species
+ * @param[in] np Number of particles
*/
- void SetupPos(openPMD::ParticleSpecies& currSpecies,
+ void SetupPos(const std::unique_ptr<WarpXParticleContainer>& pc,
+ openPMD::ParticleSpecies& currSpecies,
const unsigned long long& np) const ;
/** This function sets up the entries for particle properties
@@ -149,6 +172,9 @@ private:
bool m_OneFilePerTS = true; //! write in openPMD fileBased manner for individual time steps
std::string m_OpenPMDFileType = "bp"; //! MPI-parallel openPMD backend: bp or h5
int m_CurrentStep = -1;
+
+ // meta data
+ std::vector< bool > m_fieldPMLdirections; //! @see WarpX::getPMLdirections()
};
diff --git a/Source/Diagnostics/WarpXOpenPMD.cpp b/Source/Diagnostics/WarpXOpenPMD.cpp
index 05c2066de..85c64c8c9 100644
--- a/Source/Diagnostics/WarpXOpenPMD.cpp
+++ b/Source/Diagnostics/WarpXOpenPMD.cpp
@@ -1,18 +1,121 @@
+/* Copyright 2019-2020 Axel Huebl, Junmin Gu
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "WarpXOpenPMD.H"
+#include "WarpXAlgorithmSelection.H"
#include "FieldIO.H" // for getReversedVec
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+#include <sstream>
+#include <tuple>
+#include <utility>
+
+
+namespace detail
+{
+
+ /** Convert AMReX AoS .id and .cpu to a globally unique particle ID
+ */
+ union GlobalID {
+ struct { int id; int cpu; }; //! MPI-rank local ID (and rank/cpu)
+ uint64_t global_id; //! global ID that is unique in the whole simulation
+ };
+ static_assert(sizeof(int) * 2u <= sizeof(uint64_t), "int size might cause collisions in global IDs");
+
+ /** Unclutter a real_names to openPMD record
+ *
+ * @param fullName name as in real_names variable
+ * @return pair of openPMD record and component name
+ */
+ inline std::pair< std::string, std::string >
+ name2openPMD( std::string const& fullName )
+ {
+ std::string record_name = fullName;
+ std::string component_name = openPMD::RecordComponent::SCALAR;
+ std::size_t startComp = fullName.find_last_of("_");
+
+ if( startComp != std::string::npos ) { // non-scalar
+ record_name = fullName.substr(0, startComp);
+ component_name = fullName.substr(startComp + 1u);
+ }
+ return make_pair(record_name, component_name);
+ }
+
+ /** Get the openPMD physical dimensionality of a record
+ *
+ * @param record_name name of the openPMD record
+ * @return map with base quantities and power scaling
+ */
+ std::map< openPMD::UnitDimension, double >
+ getUnitDimension( std::string const & record_name )
+ {
+
+ if( record_name == "position" ) return {
+ {openPMD::UnitDimension::L, 1.}
+ };
+ else if( record_name == "positionOffset" ) return {
+ {openPMD::UnitDimension::L, 1.}
+ };
+ else if( record_name == "momentum" ) return {
+ {openPMD::UnitDimension::L, 1.},
+ {openPMD::UnitDimension::M, 1.},
+ {openPMD::UnitDimension::T, -1.}
+ };
+ else if( record_name == "charge" ) return {
+ {openPMD::UnitDimension::T, 1.},
+ {openPMD::UnitDimension::I, 1.}
+ };
+ else if( record_name == "mass" ) return {
+ {openPMD::UnitDimension::M, 1.}
+ };
+ else if( record_name == "E" ) return {
+ {openPMD::UnitDimension::L, 1.},
+ {openPMD::UnitDimension::M, 1.},
+ {openPMD::UnitDimension::T, -3.},
+ {openPMD::UnitDimension::I, -1.},
+ };
+ else if( record_name == "B" ) return {
+ {openPMD::UnitDimension::M, 1.},
+ {openPMD::UnitDimension::I, -1.},
+ {openPMD::UnitDimension::T, -2.}
+ };
+ else return {};
+ }
+}
+
WarpXOpenPMDPlot::WarpXOpenPMDPlot(bool oneFilePerTS,
- std::string& openPMDFileType)
+ std::string openPMDFileType, std::vector<bool> fieldPMLdirections)
:m_Series(nullptr),
m_OneFilePerTS(oneFilePerTS),
- m_OpenPMDFileType(std::move(openPMDFileType))
- //m_OpenPMDFileType(openPMDFileType)
-{}
+ m_OpenPMDFileType(std::move(openPMDFileType)),
+ m_fieldPMLdirections(std::move(fieldPMLdirections))
+{
+ // pick first available backend if default is chosen
+ if( m_OpenPMDFileType == "default" )
+#if openPMD_HAVE_ADIOS2==1
+ m_OpenPMDFileType = "bp";
+#elif openPMD_HAVE_ADIOS1==1
+ m_OpenPMDFileType = "bp";
+#elif openPMD_HAVE_HDF5==1
+ m_OpenPMDFileType = "h5";
+#else
+ m_OpenPMDFileType = "json";
+#endif
+}
WarpXOpenPMDPlot::~WarpXOpenPMDPlot()
{
- if (nullptr != m_Series) {
+ if( m_Series )
+ {
m_Series->flush();
+ m_Series.reset( nullptr );
}
}
@@ -48,34 +151,42 @@ void WarpXOpenPMDPlot::SetStep(int ts)
void
WarpXOpenPMDPlot::Init(openPMD::AccessType accessType)
{
- if (!m_OneFilePerTS) {// one file
- if (nullptr != m_Series) {
- return;
- }
- }
+ // either for the next ts file,
+ // or init a single file for all ts
+ std::string filename;
+ GetFileName(filename);
- // either for the next ts file,
- // or init a single file for all ts
- std::string filename;
- GetFileName(filename);
-
- if (m_Series != nullptr) {
- m_Series->flush();
- m_Series = nullptr;
- }
-
- if (amrex::ParallelDescriptor::NProcs() > 1) {
- m_Series = std::make_unique<openPMD::Series>(filename,
- accessType,
- amrex::ParallelDescriptor::Communicator());
- m_MPISize = amrex::ParallelDescriptor::NProcs();
- m_MPIRank = amrex::ParallelDescriptor::MyProc();
- }
+ if( amrex::ParallelDescriptor::NProcs() > 1 )
+ {
+ m_Series = std::make_unique<openPMD::Series>(
+ filename, accessType,
+ amrex::ParallelDescriptor::Communicator()
+ );
+ m_MPISize = amrex::ParallelDescriptor::NProcs();
+ m_MPIRank = amrex::ParallelDescriptor::MyProc();
+ }
else
- m_Series = std::make_unique<openPMD::Series>(filename, accessType);
+ {
+ m_Series = std::make_unique<openPMD::Series>(filename, accessType);
+ m_MPISize = 1;
+ m_MPIRank = 1;
+ }
- // actually default is "particles" by openPMD.
- m_Series->setParticlesPath("particles");
+ // input file / simulation setup author
+ if( WarpX::authors.size() > 0u )
+ m_Series->setAuthor( WarpX::authors );
+ // more natural naming for PIC
+ m_Series->setMeshesPath( "fields" );
+ // conform to ED-PIC extension of openPMD
+ uint32_t const openPMD_ED_PIC = 1u;
+ m_Series->setOpenPMDextension( openPMD_ED_PIC );
+ // meta info
+#if (OPENPMDAPI_VERSION_MAJOR>=0) && (OPENPMDAPI_VERSION_MINOR>=11)
+ m_Series->setSoftware( "WarpX", WarpX::Version() );
+#else
+ m_Series->setSoftware( "WarpX" );
+ m_Series->setSoftwareVersion( WarpX::Version() );
+#endif
}
@@ -89,23 +200,27 @@ WarpXOpenPMDPlot::WriteOpenPMDParticles(const std::unique_ptr<MultiParticleConta
auto& pc = mpc->GetUniqueContainer(i);
if (pc->plot_species) {
+ // names of amrex::Real and int particle attributes in SoA data
amrex::Vector<std::string> real_names;
amrex::Vector<std::string> int_names;
amrex::Vector<int> int_flags;
- real_names.push_back("weight");
+ // see openPMD ED-PIC extension for namings
+ // note: an underscore separates the record name from its component
+ // for non-scalar records
+ real_names.push_back("weighting");
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("E_x");
+ real_names.push_back("E_y");
+ real_names.push_back("E_z");
- real_names.push_back("Bx");
- real_names.push_back("By");
- real_names.push_back("Bz");
+ real_names.push_back("B_x");
+ real_names.push_back("B_y");
+ real_names.push_back("B_z");
#ifdef WARPX_DIM_RZ
real_names.push_back("theta");
@@ -152,61 +267,104 @@ WarpXOpenPMDPlot::SavePlotFile (const std::unique_ptr<WarpXParticleContainer>& p
const amrex::Vector<std::string>& real_comp_names,
const amrex::Vector<std::string>& int_comp_names) const
{
- if ( nullptr == m_Series)
- return;
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_Series != nullptr, "openPMD series must be initialized");
WarpXParticleCounter counter(pc);
openPMD::Iteration currIteration = m_Series->iterations[iteration];
openPMD::ParticleSpecies currSpecies = currIteration.particles[name];
+ // meta data for ED-PIC extension
+ currSpecies.setAttribute( "particleShape", double( WarpX::noz ) );
+ // TODO allow this per direction in the openPMD standard, ED-PIC extension?
+ currSpecies.setAttribute( "particleShapes", [](){
+ return std::vector< double >{
+ double(WarpX::nox),
+#if AMREX_SPACEDIM==3
+ double(WarpX::noy),
+#endif
+ double(WarpX::noz)
+ };
+ }() );
+ currSpecies.setAttribute( "particlePush", [](){
+ switch( WarpX::particle_pusher_algo ) {
+ case ParticlePusherAlgo::Boris : return "Boris";
+ case ParticlePusherAlgo::Vay : return "Vay";
+ case ParticlePusherAlgo::HigueraCary : return "HigueraCary";
+ default: return "other";
+ }
+ }() );
+ currSpecies.setAttribute( "particleInterpolation", [](){
+ switch( WarpX::field_gathering_algo ) {
+ case GatheringAlgo::EnergyConserving : return "energyConserving";
+ case GatheringAlgo::MomentumConserving : return "momentumConserving";
+ default: return "other";
+ }
+ }() );
+ currSpecies.setAttribute( "particleSmoothing", "none" );
+ currSpecies.setAttribute( "currentDeposition", [](){
+ switch( WarpX::current_deposition_algo ) {
+ case CurrentDepositionAlgo::Esirkepov : return "Esirkepov";
+ default: return "directMorseNielson";
+ }
+ }() );
+
//
// define positions & offsets
//
- SetupPos(currSpecies, counter.GetTotalNumParticles());
+ SetupPos(pc, currSpecies, counter.GetTotalNumParticles());
SetupRealProperties(currSpecies, write_real_comp, real_comp_names, counter.GetTotalNumParticles());
- // forces the files created by all processors! this is the key to resolve RZ storage issue!!
+ // open files from all processors, in case some will not contribute below
m_Series->flush();
+
for (auto currentLevel = 0; currentLevel <= pc->finestLevel(); currentLevel++)
{
- //long numParticles = counter.m_ParticleSizeAtRank[currentLevel]
- unsigned long long const numParticles = counter.m_ParticleSizeAtRank[currentLevel];
- unsigned long long offset = counter.m_ParticleOffsetAtRank[currentLevel];
-
- if (0 == numParticles)
- return;
-
- // pc->NumIntComp() & NumRealComp() are protected,
- // from WarpXParIter template class definition, we know that
- // soa num real attributes = PIdx::nattribs, and num int in soa is 0
+ uint64_t offset = static_cast<uint64_t>( counter.m_ParticleOffsetAtRank[currentLevel] );
for (WarpXParIter pti(*pc, currentLevel); pti.isValid(); ++pti) {
- auto numParticleOnTile = pti.numParticles();
+ auto const numParticleOnTile = pti.numParticles();
+ uint64_t const numParticleOnTile64 = static_cast<uint64_t>( numParticleOnTile );
- // get position from aos
+ // get position and particle ID from aos
+ // note: this implementation iterates the AoS 4x...
+ // if we flush late as we do now, we can also copy out the data in one go
const auto& aos = pti.GetArrayOfStructs(); // size = numParticlesOnTile
- { // :: Save Postions, 1D-3D::
- // this code is tested with laser 3d, not tested with 2D examples...
+ {
+ // Save positions
std::vector<std::string> axisNames={"x", "y", "z"};
-
for (auto currDim = 0; currDim < AMREX_SPACEDIM; currDim++) {
- std::vector<amrex::ParticleReal> curr(numParticleOnTile, 0);
+ std::shared_ptr< amrex::ParticleReal > curr(
+ new amrex::ParticleReal[numParticleOnTile],
+ [](amrex::ParticleReal const *p){ delete[] p; }
+ );
for (auto i=0; i<numParticleOnTile; i++) {
- curr[i] = aos[i].m_rdata.pos[currDim];
+ curr.get()[i] = aos[i].m_rdata.pos[currDim];
}
- currSpecies["position"][axisNames[currDim]].storeChunk(curr, {offset}, {static_cast<unsigned long long>(numParticleOnTile)});
- m_Series->flush();
+ currSpecies["position"][axisNames[currDim]].storeChunk(curr, {offset}, {numParticleOnTile64});
}
+
+ // save particle ID after converting it to a globally unique ID
+ std::shared_ptr< uint64_t > ids(
+ new uint64_t[numParticleOnTile],
+ [](uint64_t const *p){ delete[] p; }
+ );
+ for (auto i=0; i<numParticleOnTile; i++) {
+ detail::GlobalID const nextID = { aos[i].m_idata.id, aos[i].m_idata.cpu };
+ ids.get()[i] = nextID.global_id;
+ }
+ auto const scalar = openPMD::RecordComponent::SCALAR;
+ currSpecies["id"][scalar].storeChunk(ids, {offset}, {numParticleOnTile64});
}
- // save properties
+ // save "extra" particle properties in AoS and SoA
SaveRealProperty(pti,
currSpecies,
offset,
write_real_comp, real_comp_names);
- offset += numParticleOnTile;
+ offset += numParticleOnTile64;
}
}
+ m_Series->flush();
}
void
@@ -224,46 +382,78 @@ WarpXOpenPMDPlot::SetupRealProperties(openPMD::ParticleSpecies& currSpecies,
auto counter = std::min(write_real_comp.size(), real_comp_names.size());
for (int i = 0; i < counter; ++i)
if (write_real_comp[i]) {
- auto& particleVar = currSpecies[real_comp_names[i]];
- auto& particleVarComp = particleVar[openPMD::RecordComponent::SCALAR];
+ // handle scalar and non-scalar records by name
+ std::string record_name, component_name;
+ std::tie(record_name, component_name) = detail::name2openPMD(real_comp_names[i]);
+
+ auto particleVarComp = currSpecies[record_name][component_name];
particleVarComp.resetDataset(particlesLineup);
}
+
+ std::set< std::string > addedRecords; // add meta-data per record only once
+ for (auto idx=0; idx<m_NumSoARealAttributes; idx++) {
+ auto ii = m_NumAoSRealAttributes + idx;
+ if (write_real_comp[ii]) {
+ // handle scalar and non-scalar records by name
+ std::string record_name, component_name;
+ std::tie(record_name, component_name) = detail::name2openPMD(real_comp_names[ii]);
+ auto currRecord = currSpecies[record_name];
+
+ // meta data for ED-PIC extension
+ bool newRecord = false;
+ std::tie(std::ignore, newRecord) = addedRecords.insert(record_name);
+ if( newRecord ) {
+ currRecord.setUnitDimension( detail::getUnitDimension(record_name) );
+ currRecord.setAttribute( "macroWeighted", 0u );
+ if( record_name == "momentum" )
+ currRecord.setAttribute( "weightingPower", 1.0 );
+ else
+ currRecord.setAttribute( "weightingPower", 0.0 );
+ }
+ }
+ }
}
void
WarpXOpenPMDPlot::SaveRealProperty(WarpXParIter& pti,
openPMD::ParticleSpecies& currSpecies,
- unsigned long long offset,
- const amrex::Vector<int>& write_real_comp,
- const amrex::Vector<std::string>& real_comp_names) const
+ unsigned long long const offset,
+ amrex::Vector<int> const& write_real_comp,
+ amrex::Vector<std::string> const& real_comp_names) const
{
int numOutputReal = 0;
int const totalRealAttrs = m_NumAoSRealAttributes + m_NumSoARealAttributes;
- for (int i = 0; i < totalRealAttrs; ++i)
- if (write_real_comp[i])
+ for( int i = 0; i < totalRealAttrs; ++i )
+ if( write_real_comp[i] )
++numOutputReal;
- auto numParticleOnTile = pti.numParticles();
- const auto& aos = pti.GetArrayOfStructs(); // size = numParticlesOnTile
- const auto& soa = pti.GetStructOfArrays();
+ auto const numParticleOnTile = pti.numParticles();
+ uint64_t const numParticleOnTile64 = static_cast<uint64_t>( numParticleOnTile );
+ auto const& aos = pti.GetArrayOfStructs(); // size = numParticlesOnTile
+ auto const& soa = pti.GetStructOfArrays();
// properties are saved separately
{
- for (auto idx=0; idx<m_NumAoSRealAttributes; idx++) {
- if (write_real_comp[idx]) {
- auto& currVar = currSpecies[real_comp_names[idx]][openPMD::RecordComponent::SCALAR];
- typename amrex::ParticleReal *d =
- static_cast<typename amrex::ParticleReal*> (malloc(sizeof(typename amrex::ParticleReal) * numParticleOnTile));
-
- for (auto kk=0; kk<numParticleOnTile; kk++)
- d[kk] = aos[kk].m_rdata.arr[AMREX_SPACEDIM+idx];
-
- std::shared_ptr <typename amrex::ParticleReal> data(d, free);
- currVar.storeChunk(data,
- {offset}, {static_cast<unsigned long long>(numParticleOnTile)});
- m_Series->flush();
+ for( auto idx=0; idx<m_NumAoSRealAttributes; idx++ ) {
+ if( write_real_comp[idx] ) {
+ // handle scalar and non-scalar records by name
+ std::string record_name, component_name;
+ std::tie(record_name, component_name) = detail::name2openPMD(real_comp_names[idx]);
+ auto currRecord = currSpecies[record_name];
+ auto currRecordComp = currRecord[component_name];
+
+ std::shared_ptr< amrex::ParticleReal > d(
+ new amrex::ParticleReal[numParticleOnTile],
+ [](amrex::ParticleReal const *p){ delete[] p; }
+ );
+
+ for( auto kk=0; kk<numParticleOnTile; kk++ )
+ d.get()[kk] = aos[kk].m_rdata.arr[AMREX_SPACEDIM+idx];
+
+ currRecordComp.storeChunk(d,
+ {offset}, {numParticleOnTile64});
}
}
}
@@ -272,37 +462,60 @@ WarpXOpenPMDPlot::SaveRealProperty(WarpXParIter& pti,
for (auto idx=0; idx<m_NumSoARealAttributes; idx++) {
auto ii = m_NumAoSRealAttributes + idx;
if (write_real_comp[ii]) {
- auto& currVar = currSpecies[real_comp_names[ii]][openPMD::RecordComponent::SCALAR];
- currVar.storeChunk(openPMD::shareRaw(soa.GetRealData(idx)),
- {offset}, {static_cast<unsigned long long>(numParticleOnTile)});
+ // handle scalar and non-scalar records by name
+ std::string record_name, component_name;
+ std::tie(record_name, component_name) = detail::name2openPMD(real_comp_names[ii]);
+ auto& currRecord = currSpecies[record_name];
+ auto& currRecordComp = currRecord[component_name];
+
+ currRecordComp.storeChunk(openPMD::shareRaw(soa.GetRealData(idx)),
+ {offset}, {numParticleOnTile64});
}
}
- m_Series->flush();
}
}
void
-WarpXOpenPMDPlot::SetupPos(openPMD::ParticleSpecies& currSpecies,
- const unsigned long long& np) const
+WarpXOpenPMDPlot::SetupPos(const std::unique_ptr<WarpXParticleContainer>& pc,
+ openPMD::ParticleSpecies& currSpecies,
+ const unsigned long long& np) const
{
- auto particleLineup = openPMD::Dataset(openPMD::determineDatatype<amrex::ParticleReal>(), {np});
-
- currSpecies["positionOffset"]["x"].resetDataset(particleLineup);
- currSpecies["positionOffset"]["x"].makeConstant(0);
- currSpecies["positionOffset"]["y"].resetDataset(particleLineup);
- currSpecies["positionOffset"]["y"].makeConstant(0);
- currSpecies["positionOffset"]["z"].resetDataset(particleLineup);
- currSpecies["positionOffset"]["z"].makeConstant(0);
-
- //auto positions = openPMD::Dataset(openPMD::determineDatatype<amrex::ParticleReal>(), {np});
- currSpecies["position"]["x"].resetDataset(particleLineup);
- currSpecies["position"]["y"].resetDataset(particleLineup);
- currSpecies["position"]["z"].resetDataset(particleLineup);
-}
+ auto const realType = openPMD::Dataset(openPMD::determineDatatype<amrex::ParticleReal>(), {np});
+ auto const idType = openPMD::Dataset(openPMD::determineDatatype< uint64_t >(), {np});
+ for( auto const& comp : {"x", "y", "z"} ) {
+ currSpecies["positionOffset"][comp].resetDataset( realType );
+ currSpecies["positionOffset"][comp].makeConstant( 0. );
+ currSpecies["position"][comp].resetDataset( realType );
+ }
+ auto const scalar = openPMD::RecordComponent::SCALAR;
+ currSpecies["id"][scalar].resetDataset( idType );
+ currSpecies["charge"][scalar].resetDataset( realType );
+ currSpecies["charge"][scalar].makeConstant( pc->getCharge() );
+ currSpecies["mass"][scalar].resetDataset( realType );
+ currSpecies["mass"][scalar].makeConstant( pc->getMass() );
+
+ // meta data
+ currSpecies["position"].setUnitDimension( detail::getUnitDimension("position") );
+ currSpecies["positionOffset"].setUnitDimension( detail::getUnitDimension("positionOffset") );
+ currSpecies["charge"].setUnitDimension( detail::getUnitDimension("charge") );
+ currSpecies["mass"].setUnitDimension( detail::getUnitDimension("mass") );
+
+ // meta data for ED-PIC extension
+ currSpecies["position"].setAttribute( "macroWeighted", 0u );
+ currSpecies["position"].setAttribute( "weightingPower", 0.0 );
+ currSpecies["positionOffset"].setAttribute( "macroWeighted", 0u );
+ currSpecies["positionOffset"].setAttribute( "weightingPower", 0.0 );
+ currSpecies["id"].setAttribute( "macroWeighted", 0u );
+ currSpecies["id"].setAttribute( "weightingPower", 0.0 );
+ currSpecies["charge"].setAttribute( "macroWeighted", 0u );
+ currSpecies["charge"].setAttribute( "weightingPower", 1.0 );
+ currSpecies["mass"].setAttribute( "macroWeighted", 0u );
+ currSpecies["mass"].setAttribute( "weightingPower", 1.0 );
+}
//
@@ -316,48 +529,108 @@ WarpXOpenPMDPlot::WriteOpenPMDFields( //const std::string& filename,
const int iteration,
const double time ) const
{
- //This is AmrEx's tiny profiler. Possibly will apply it later
+ //This is AMReX's tiny profiler. Possibly will apply it later
BL_PROFILE("WarpXOpenPMDPlot::WriteOpenPMDFields()");
- if ( nullptr == m_Series)
- return;
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_Series != nullptr, "openPMD series must be initialized");
- const int ncomp = mf.nComp();
+ int const ncomp = mf.nComp();
// Create a few vectors that store info on the global domain
// Swap the indices for each of them, since AMReX data is Fortran order
// and since the openPMD API assumes contiguous C order
// - Size of the box, in integer number of cells
- const amrex::Box& global_box = geom.Domain();
- auto global_size = getReversedVec(global_box.size());
+ amrex::Box const & global_box = geom.Domain();
+ auto const global_size = getReversedVec(global_box.size());
// - Grid spacing
- std::vector<double> grid_spacing = getReversedVec(geom.CellSize());
+ std::vector<double> const grid_spacing = getReversedVec(geom.CellSize());
// - Global offset
- std::vector<double> global_offset = getReversedVec(geom.ProbLo());
+ std::vector<double> const global_offset = getReversedVec(geom.ProbLo());
// - AxisLabels
#if AMREX_SPACEDIM==3
- std::vector<std::string> axis_labels{"x", "y", "z"};
+ std::vector<std::string> const axis_labels{"x", "y", "z"};
#else
- std::vector<std::string> axis_labels{"x", "z"};
+ std::vector<std::string> const axis_labels{"x", "z"};
#endif
// Prepare the type of dataset that will be written
- openPMD::Datatype datatype = openPMD::determineDatatype<amrex::Real>();
- auto dataset = openPMD::Dataset(datatype, global_size);
+ openPMD::Datatype const datatype = openPMD::determineDatatype<amrex::Real>();
+ auto const dataset = openPMD::Dataset(datatype, global_size);
+ // meta data
auto series_iteration = m_Series->iterations[iteration];
series_iteration.setTime( time );
+ // meta data for ED-PIC extension
+ auto const period = geom.periodicity(); // TODO double-check: is this the proper global bound or of some level?
+ std::vector< std::string > fieldBoundary( 6, "reflecting" );
+ std::vector< std::string > particleBoundary( 6, "absorbing" );
+#if AMREX_SPACEDIM!=3
+ fieldBoundary.resize(4);
+ particleBoundary.resize(4);
+#endif
+
+ for( auto i = 0u; i < fieldBoundary.size() / 2u; ++i )
+ if( m_fieldPMLdirections.at( i ) )
+ fieldBoundary.at( i ) = "open";
+
+ for( auto i = 0u; i < fieldBoundary.size() / 2u; ++i )
+ if( period.isPeriodic( i ) ) {
+ fieldBoundary.at(2u*i ) = "periodic";
+ fieldBoundary.at(2u*i + 1u) = "periodic";
+ particleBoundary.at(2u*i ) = "periodic";
+ particleBoundary.at(2u*i + 1u) = "periodic";
+ }
+
+ auto meshes = series_iteration.meshes;
+ meshes.setAttribute( "fieldSolver", [](){
+#ifdef WARPX_USE_PSATD
+ return "PSATD"; // TODO double-check if WARPX_USE_PSATD_HYBRID is covered
+#else
+ switch( WarpX::particle_pusher_algo ) {
+ case MaxwellSolverAlgo::Yee : return "Yee";
+ case MaxwellSolverAlgo::CKC : return "CK";
+ default: return "other";
+ }
+#endif
+ }() );
+ meshes.setAttribute( "fieldBoundary", fieldBoundary );
+ meshes.setAttribute( "particleBoundary", particleBoundary );
+ meshes.setAttribute( "currentSmoothing", [](){
+ if( WarpX::use_filter ) return "Binomial";
+ else return "none";
+ }() );
+ if( WarpX::use_filter )
+ meshes.setAttribute( "currentSmoothingParameters", [](){
+ std::stringstream ss;
+ ss << "period=1;compensator=false";
+ ss << ";numPasses_x=" << WarpX::filter_npass_each_dir[0];
+#if (AMREX_SPACEDIM == 3)
+ ss << ";numPasses_y=" << WarpX::filter_npass_each_dir[1];
+ ss << ";numPasses_z=" << WarpX::filter_npass_each_dir[2];
+#else
+ ss << ";numPasses_z=" << WarpX::filter_npass_each_dir[1];
+#endif
+ std::string currentSmoothingParameters = ss.str();
+ return std::move(currentSmoothingParameters);
+ }() );
+ meshes.setAttribute("chargeCorrection", [](){
+ if( WarpX::do_dive_cleaning ) return "hyperbolic"; // TODO or "spectral" or something? double-check
+ else return "none";
+ }() );
+ if( WarpX::do_dive_cleaning )
+ meshes.setAttribute("chargeCorrectionParameters", "period=1");
+
// Loop through the different components, i.e. different fields stored in mf
for (int icomp=0; icomp<ncomp; icomp++){
// Check if this field is a vector or a scalar, and extract the field name
- const std::string& varname = varnames[icomp];
+ std::string const & varname = varnames[icomp];
std::string field_name = varname;
std::string comp_name = openPMD::MeshRecordComponent::SCALAR;
- for (const char* vector_field: {"E", "B", "j"}){
- for (const char* comp: {"x", "y", "z"}){
- if (varname[0] == *vector_field && varname[1] == *comp ){
+ for( char const* vector_field: {"E", "B", "j"} ) {
+ for( char const* comp: {"x", "y", "z"} ) {
+ if( varname[0] == *vector_field && varname[1] == *comp ) {
field_name = varname[0] + varname.substr(2); // Strip component
comp_name = varname[1];
}
@@ -365,35 +638,36 @@ WarpXOpenPMDPlot::WriteOpenPMDFields( //const std::string& filename,
}
// Setup the mesh record accordingly
- auto mesh = series_iteration.meshes[field_name];
- mesh.setDataOrder(openPMD::Mesh::DataOrder::F); // MultiFab: Fortran order
+ auto mesh = meshes[field_name];
+ mesh.setDataOrder( openPMD::Mesh::DataOrder::F ); // MultiFab: Fortran order of indices and axes
mesh.setAxisLabels( axis_labels );
mesh.setGridSpacing( grid_spacing );
mesh.setGridGlobalOffset( global_offset );
+ mesh.setAttribute( "fieldSmoothing", "none" );
setOpenPMDUnit( mesh, field_name );
// Create a new mesh record component, and store the associated metadata
auto mesh_comp = mesh[comp_name];
mesh_comp.resetDataset( dataset );
// Cell-centered data: position is at 0.5 of a cell size.
- mesh_comp.setPosition(std::vector<double>{AMREX_D_DECL(0.5, 0.5, 0.5)});
+ mesh_comp.setPosition( std::vector<double>{AMREX_D_DECL(0.5, 0.5, 0.5)} );
// Loop through the multifab, and store each box as a chunk,
// in the openPMD file.
- for (amrex::MFIter mfi(mf); mfi.isValid(); ++mfi) {
+ for( amrex::MFIter mfi(mf); mfi.isValid(); ++mfi ) {
- const amrex::FArrayBox& fab = mf[mfi];
- const amrex::Box& local_box = fab.box();
+ amrex::FArrayBox const& fab = mf[mfi];
+ amrex::Box const& local_box = fab.box();
// Determine the offset and size of this chunk
- amrex::IntVect box_offset = local_box.smallEnd() - global_box.smallEnd();
- auto chunk_offset = getReversedVec(box_offset);
- auto chunk_size = getReversedVec(local_box.size());
+ amrex::IntVect const box_offset = local_box.smallEnd() - global_box.smallEnd();
+ auto const chunk_offset = getReversedVec( box_offset );
+ auto const chunk_size = getReversedVec( local_box.size() );
// Write local data
- const double* local_data = fab.dataPtr(icomp);
- mesh_comp.storeChunk(openPMD::shareRaw(local_data),
- chunk_offset, chunk_size);
+ double const * local_data = fab.dataPtr( icomp );
+ mesh_comp.storeChunk( openPMD::shareRaw(local_data),
+ chunk_offset, chunk_size );
}
}
// Flush data to disk after looping over all components
@@ -444,13 +718,14 @@ WarpXParticleCounter::WarpXParticleCounter(const std::unique_ptr<WarpXParticleCo
// get the offset in the overall particle id collection
//
+// note: this is a MPI-collective operation
+//
// input: num of particles of from each processor
//
// output:
// offset within <all> the particles in the comm
// sum of all particles in the comm
//
-
void
WarpXParticleCounter::GetParticleOffsetOfProcessor(const long& numParticles,
unsigned long long& offset,
diff --git a/Source/Diagnostics/requirements.txt b/Source/Diagnostics/requirements.txt
new file mode 100644
index 000000000..5a3933299
--- /dev/null
+++ b/Source/Diagnostics/requirements.txt
@@ -0,0 +1,8 @@
+# Copyright 2020 Axel Huebl
+#
+# This file is part of WarpX.
+#
+# License: BSD-3-Clause-LBNL
+
+# keep this entry for GitHub's dependency graph
+openPMD-api>=0.10.3
diff --git a/Source/Evolve/WarpXDtType.H b/Source/Evolve/WarpXDtType.H
index c2c01db00..89fcb506f 100644
--- a/Source/Evolve/WarpXDtType.H
+++ b/Source/Evolve/WarpXDtType.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_DTTYPE_H_
#define WARPX_DTTYPE_H_
diff --git a/Source/Evolve/WarpXEvolveEM.cpp b/Source/Evolve/WarpXEvolveEM.cpp
index f5491ffe3..bb1300562 100644
--- a/Source/Evolve/WarpXEvolveEM.cpp
+++ b/Source/Evolve/WarpXEvolveEM.cpp
@@ -1,3 +1,13 @@
+/* Copyright 2019-2020 Andrew Myers, Ann Almgren, Aurore Blelly
+ * Axel Huebl, Burlen Loring, David Grote
+ * Glenn Richardson, Jean-Luc Vay, Luca Fedeli
+ * Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ * Weiqun Zhang, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <cmath>
#include <limits>
@@ -5,6 +15,7 @@
#include <WarpXConst.H>
#include <WarpX_f.H>
#include <WarpXUtil.H>
+#include <WarpXAlgorithmSelection.H>
#ifdef WARPX_USE_PY
#include <WarpX_py.H>
#endif
@@ -13,7 +24,6 @@
#include <AMReX_AmrMeshInSituBridge.H>
#endif
-
using namespace amrex;
void
@@ -75,8 +85,9 @@ WarpX::EvolveEM (int numsteps)
// Particles have p^{n} and x^{n}.
// is_synchronized is true.
if (is_synchronized) {
- FillBoundaryE();
- FillBoundaryB();
+ // Not called at each iteration, so exchange all guard cells
+ FillBoundaryE(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ FillBoundaryB(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
UpdateAuxilaryData();
// on first step, push p by -0.5*dt
for (int lev = 0; lev <= finest_level; ++lev) {
@@ -89,14 +100,23 @@ WarpX::EvolveEM (int numsteps)
} else {
// Beyond one step, we have E^{n} and B^{n}.
// Particles have p^{n-1/2} and x^{n}.
- FillBoundaryE();
- FillBoundaryB();
- UpdateAuxilaryData();
+ // E and B are up-to-date inside the domain only
+ FillBoundaryE(guard_cells.ng_FieldGather, guard_cells.ng_Extra);
+ FillBoundaryB(guard_cells.ng_FieldGather, guard_cells.ng_Extra);
+ // E and B: enough guard cells to update Aux or call Field Gather in fp and cp
+ // Need to update Aux on lower levels, to interpolate to higher levels.
+#ifndef WARPX_USE_PSATD
+ FillBoundaryAux(guard_cells.ng_UpdateAux);
+#endif
+ UpdateAuxilaryData();
}
if (do_subcycling == 0 || finest_level == 0) {
OneStep_nosub(cur_time);
+ // E : guard cells are up-to-date
+ // B : guard cells are NOT up-to-date
+ // F : guard cells are NOT up-to-date
} else if (do_subcycling == 1 && finest_level == 1) {
OneStep_sub1(cur_time);
} else {
@@ -106,6 +126,8 @@ WarpX::EvolveEM (int numsteps)
if (num_mirrors>0){
applyMirrors(cur_time);
+ // E : guard cells are NOT up-to-date
+ // B : guard cells are NOT up-to-date
}
#ifdef WARPX_USE_PY
@@ -133,7 +155,8 @@ WarpX::EvolveEM (int numsteps)
cur_time += dt[0];
- bool to_make_plot = (plot_int > 0) && ((step+1) % plot_int == 0);
+ bool to_make_plot = ( (plot_int > 0) && ((step+1) % plot_int == 0) );
+ bool to_write_openPMD = ( (openpmd_int > 0) && ((step+1) % openpmd_int == 0) );
// slice generation //
bool to_make_slice_plot = (slice_plot_int > 0) && ( (step+1)% slice_plot_int == 0);
@@ -149,7 +172,7 @@ WarpX::EvolveEM (int numsteps)
myBFD->writeLabFrameData(cell_centered_data.get(), *mypc, geom[0], cur_time, dt[0]);
}
- bool move_j = is_synchronized || to_make_plot || do_insitu;
+ bool move_j = is_synchronized || to_make_plot || to_write_openPMD || 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.
@@ -182,11 +205,24 @@ WarpX::EvolveEM (int numsteps)
t_new[i] = cur_time;
}
+ /// reduced diags
+ if (reduced_diags->m_plot_rd != 0)
+ {
+ reduced_diags->ComputeDiags(step);
+ reduced_diags->WriteToFile(step);
+ }
+
// slice gen //
- if (to_make_plot || do_insitu || to_make_slice_plot)
+ if (to_make_plot || to_write_openPMD || do_insitu || to_make_slice_plot)
{
- FillBoundaryE();
- FillBoundaryB();
+ // This is probably overkill, but it's not called often
+ FillBoundaryE(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ // This is probably overkill, but it's not called often
+ FillBoundaryB(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ // This is probably overkill, but it's not called often
+#ifndef WARPX_USE_PSATD
+ FillBoundaryAux(guard_cells.ng_UpdateAux);
+#endif
UpdateAuxilaryData();
for (int lev = 0; lev <= finest_level; ++lev) {
@@ -200,6 +236,8 @@ WarpX::EvolveEM (int numsteps)
if (to_make_plot)
WritePlotFile();
+ if (to_write_openPMD)
+ WriteOpenPMDFile();
if (to_make_slice_plot)
{
@@ -231,14 +269,21 @@ WarpX::EvolveEM (int numsteps)
bool write_plot_file = plot_int > 0 && istep[0] > last_plot_file_step
&& (max_time_reached || istep[0] >= max_step);
+ bool write_openPMD = openpmd_int > 0 && (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);
- if (write_plot_file || do_insitu)
+ if (write_plot_file || write_openPMD || do_insitu)
{
- FillBoundaryE();
- FillBoundaryB();
+ // This is probably overkill, but it's not called often
+ FillBoundaryE(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ // This is probably overkill, but it's not called often
+ FillBoundaryB(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ // This is probably overkill
+#ifndef WARPX_USE_PSATD
+ FillBoundaryAux(guard_cells.ng_UpdateAux);
+#endif
UpdateAuxilaryData();
for (int lev = 0; lev <= finest_level; ++lev) {
@@ -251,6 +296,8 @@ WarpX::EvolveEM (int numsteps)
if (write_plot_file)
WritePlotFile();
+ if (write_openPMD)
+ WriteOpenPMDFile();
if (do_insitu)
UpdateInSitu();
@@ -300,6 +347,10 @@ WarpX::OneStep_nosub (Real cur_time)
SyncRho();
+ // At this point, J is up-to-date inside the domain, and E and B are
+ // up-to-date including enough guard cells for first step of the field
+ // solve.
+
// For extended PML: copy J from regular grid to PML, and damp J in PML
if (do_pml && pml_has_particles) CopyJPML();
if (do_pml && do_pml_j_damping) DampJPML();
@@ -309,24 +360,28 @@ WarpX::OneStep_nosub (Real cur_time)
#ifdef WARPX_USE_PSATD
PushPSATD(dt[0]);
if (do_pml) DampPML();
- FillBoundaryE();
- FillBoundaryB();
+ FillBoundaryE(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
+ FillBoundaryB(guard_cells.ng_alloc_EB, guard_cells.ng_Extra);
#else
EvolveF(0.5*dt[0], DtType::FirstHalf);
- FillBoundaryF();
+ FillBoundaryF(guard_cells.ng_FieldSolverF);
EvolveB(0.5*dt[0]); // We now have B^{n+1/2}
- FillBoundaryB();
+ FillBoundaryB(guard_cells.ng_FieldSolver, IntVect::TheZeroVector());
EvolveE(dt[0]); // We now have E^{n+1}
- FillBoundaryE();
+
+ FillBoundaryE(guard_cells.ng_FieldSolver, IntVect::TheZeroVector());
EvolveF(0.5*dt[0], DtType::SecondHalf);
EvolveB(0.5*dt[0]); // We now have B^{n+1}
if (do_pml) {
+ FillBoundaryF(guard_cells.ng_alloc_F);
DampPML();
- FillBoundaryE();
+ FillBoundaryE(guard_cells.ng_MovingWindow, IntVect::TheZeroVector());
+ FillBoundaryF(guard_cells.ng_MovingWindow);
+ FillBoundaryB(guard_cells.ng_MovingWindow, IntVect::TheZeroVector());
}
- FillBoundaryB();
-
+ // E and B are up-to-date in the domain, but all guard cells are
+ // outdated.
#endif
}
@@ -345,11 +400,12 @@ WarpX::OneStep_nosub (Real cur_time)
* steps of the fine grid.
*
*/
+
+
void
WarpX::OneStep_sub1 (Real curtime)
{
// TODO: we could save some charge depositions
-
// Loop over species. For each ionizable species, create particles in
// product species.
mypc->doFieldIonization();
@@ -369,21 +425,22 @@ WarpX::OneStep_sub1 (Real curtime)
EvolveB(fine_lev, PatchType::fine, 0.5*dt[fine_lev]);
EvolveF(fine_lev, PatchType::fine, 0.5*dt[fine_lev], DtType::FirstHalf);
- FillBoundaryB(fine_lev, PatchType::fine);
- FillBoundaryF(fine_lev, PatchType::fine);
+ FillBoundaryB(fine_lev, PatchType::fine, guard_cells.ng_FieldSolver);
+ FillBoundaryF(fine_lev, PatchType::fine, guard_cells.ng_alloc_F);
EvolveE(fine_lev, PatchType::fine, dt[fine_lev]);
- FillBoundaryE(fine_lev, PatchType::fine);
+ FillBoundaryE(fine_lev, PatchType::fine, guard_cells.ng_FieldGather);
EvolveB(fine_lev, PatchType::fine, 0.5*dt[fine_lev]);
EvolveF(fine_lev, PatchType::fine, 0.5*dt[fine_lev], DtType::SecondHalf);
if (do_pml) {
+ FillBoundaryF(fine_lev, PatchType::fine, guard_cells.ng_alloc_F);
DampPML(fine_lev, PatchType::fine);
- FillBoundaryE(fine_lev, PatchType::fine);
+ FillBoundaryE(fine_lev, PatchType::fine, guard_cells.ng_FieldGather);
}
- FillBoundaryB(fine_lev, PatchType::fine);
+ FillBoundaryB(fine_lev, PatchType::fine, guard_cells.ng_FieldGather);
// ii) Push particles on the coarse patch and mother grid.
// Push the fields on the coarse patch and mother grid
@@ -395,20 +452,21 @@ WarpX::OneStep_sub1 (Real curtime)
EvolveB(fine_lev, PatchType::coarse, dt[fine_lev]);
EvolveF(fine_lev, PatchType::coarse, dt[fine_lev], DtType::FirstHalf);
- FillBoundaryB(fine_lev, PatchType::coarse);
- FillBoundaryF(fine_lev, PatchType::coarse);
+ FillBoundaryB(fine_lev, PatchType::coarse, guard_cells.ng_FieldGather);
+ FillBoundaryF(fine_lev, PatchType::coarse, guard_cells.ng_FieldSolverF);
EvolveE(fine_lev, PatchType::coarse, dt[fine_lev]);
- FillBoundaryE(fine_lev, PatchType::coarse);
+ FillBoundaryE(fine_lev, PatchType::coarse, guard_cells.ng_FieldGather);
EvolveB(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev]);
EvolveF(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev], DtType::FirstHalf);
- FillBoundaryB(coarse_lev, PatchType::fine);
- FillBoundaryF(coarse_lev, PatchType::fine);
+ FillBoundaryB(coarse_lev, PatchType::fine, guard_cells.ng_FieldGather + guard_cells.ng_Extra);
+ FillBoundaryF(coarse_lev, PatchType::fine, guard_cells.ng_FieldSolverF);
EvolveE(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev]);
- FillBoundaryE(coarse_lev, PatchType::fine);
+ FillBoundaryE(coarse_lev, PatchType::fine, guard_cells.ng_FieldGather + guard_cells.ng_Extra);
+ FillBoundaryAux(guard_cells.ng_UpdateAux);
// iii) Get auxiliary fields on the fine grid, at dt[fine_lev]
UpdateAuxilaryData();
@@ -423,22 +481,21 @@ WarpX::OneStep_sub1 (Real curtime)
EvolveB(fine_lev, PatchType::fine, 0.5*dt[fine_lev]);
EvolveF(fine_lev, PatchType::fine, 0.5*dt[fine_lev], DtType::FirstHalf);
- FillBoundaryB(fine_lev, PatchType::fine);
- FillBoundaryF(fine_lev, PatchType::fine);
+ FillBoundaryB(fine_lev, PatchType::fine, guard_cells.ng_FieldSolver);
+ FillBoundaryF(fine_lev, PatchType::fine, guard_cells.ng_FieldSolverF);
EvolveE(fine_lev, PatchType::fine, dt[fine_lev]);
- FillBoundaryE(fine_lev, PatchType::fine);
+ FillBoundaryE(fine_lev, PatchType::fine, guard_cells.ng_FieldSolver);
EvolveB(fine_lev, PatchType::fine, 0.5*dt[fine_lev]);
EvolveF(fine_lev, PatchType::fine, 0.5*dt[fine_lev], DtType::SecondHalf);
if (do_pml) {
DampPML(fine_lev, PatchType::fine);
- FillBoundaryE(fine_lev, PatchType::fine);
+ FillBoundaryE(fine_lev, PatchType::fine, guard_cells.ng_FieldSolver);
}
- FillBoundaryB(fine_lev, PatchType::fine);
- FillBoundaryF(fine_lev, PatchType::fine);
+ FillBoundaryB(fine_lev, PatchType::fine, guard_cells.ng_FieldSolver);
// v) Push the fields on the coarse patch and mother grid
// by only half a coarse step (second half)
@@ -447,32 +504,38 @@ WarpX::OneStep_sub1 (Real curtime)
AddRhoFromFineLevelandSumBoundary(coarse_lev, ncomps, ncomps);
EvolveE(fine_lev, PatchType::coarse, dt[fine_lev]);
- FillBoundaryE(fine_lev, PatchType::coarse);
+ FillBoundaryE(fine_lev, PatchType::coarse, guard_cells.ng_FieldSolver);
EvolveB(fine_lev, PatchType::coarse, dt[fine_lev]);
EvolveF(fine_lev, PatchType::coarse, dt[fine_lev], DtType::SecondHalf);
if (do_pml) {
+ FillBoundaryF(fine_lev, PatchType::fine, guard_cells.ng_FieldSolverF);
DampPML(fine_lev, PatchType::coarse); // do it twice
DampPML(fine_lev, PatchType::coarse);
- FillBoundaryE(fine_lev, PatchType::coarse);
+ FillBoundaryE(fine_lev, PatchType::coarse, guard_cells.ng_alloc_EB);
}
- FillBoundaryB(fine_lev, PatchType::coarse);
- FillBoundaryF(fine_lev, PatchType::coarse);
+ FillBoundaryB(fine_lev, PatchType::coarse, guard_cells.ng_FieldSolver);
+
+ FillBoundaryF(fine_lev, PatchType::coarse, guard_cells.ng_FieldSolverF);
EvolveE(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev]);
- FillBoundaryE(coarse_lev, PatchType::fine);
+ FillBoundaryE(coarse_lev, PatchType::fine, guard_cells.ng_FieldSolver);
EvolveB(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev]);
EvolveF(coarse_lev, PatchType::fine, 0.5*dt[coarse_lev], DtType::SecondHalf);
if (do_pml) {
+ if (do_moving_window){
+ // Exchance guard cells of PMLs only (0 cells are exchanged for the
+ // regular B field MultiFab). This is required as B and F have just been
+ // evolved.
+ FillBoundaryB(coarse_lev, PatchType::fine, IntVect::TheZeroVector());
+ FillBoundaryF(coarse_lev, PatchType::fine, IntVect::TheZeroVector());
+ }
DampPML(coarse_lev, PatchType::fine);
- FillBoundaryE(coarse_lev, PatchType::fine);
}
-
- FillBoundaryB(coarse_lev, PatchType::fine);
}
void
@@ -615,9 +678,10 @@ WarpX::computeMaxStepBoostAccelerator(const amrex::Geometry& a_geom){
// Divide by dt, and update value of max_step.
int computed_max_step;
if (do_subcycling){
- computed_max_step = interaction_time_boost/dt[0];
+ computed_max_step = static_cast<int>(interaction_time_boost/dt[0]);
} else {
- computed_max_step = interaction_time_boost/dt[maxLevel()];
+ computed_max_step =
+ static_cast<int>(interaction_time_boost/dt[maxLevel()]);
}
max_step = computed_max_step;
Print()<<"max_step computed in computeMaxStepBoostAccelerator: "
diff --git a/Source/Evolve/WarpXEvolveES.cpp b/Source/Evolve/WarpXEvolveES.cpp
index 555ab37ad..77e037154 100644
--- a/Source/Evolve/WarpXEvolveES.cpp
+++ b/Source/Evolve/WarpXEvolveES.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Bizzozero
+ * David Grote, Maxence Thevenet, Remi Lehe
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpX_f.H>
@@ -58,7 +66,7 @@ WarpX::EvolveES (int numsteps) {
// Beyond one step, particles have p^{n-1/2} and x^{n}.
if (is_synchronized) {
// on first step, push X by 0.5*dt
- mypc->PushXES(0.5*dt[lev]);
+ mypc->PushX(0.5*dt[lev]);
UpdatePlasmaInjectionPosition(0.5*dt[lev]);
mypc->Redistribute();
mypc->DepositCharge(rhoNodal);
@@ -95,7 +103,7 @@ WarpX::EvolveES (int numsteps) {
if (cur_time + dt[0] >= stop_time - 1.e-3*dt[0] || step == numsteps_max-1) {
// on last step, push by only 0.5*dt to synchronize all at n+1/2
- mypc->PushXES(-0.5*dt[lev]);
+ mypc->PushX(-0.5*dt[lev]);
UpdatePlasmaInjectionPosition(-0.5*dt[lev]);
is_synchronized = true;
}
diff --git a/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridFFTData.H b/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridFFTData.H
index 4e97ab675..44bb42982 100644
--- a/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridFFTData.H
+++ b/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridFFTData.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PICSAR_HYBRID_FFTDATA_H_
#define WARPX_PICSAR_HYBRID_FFTDATA_H_
diff --git a/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridSpectralSolver.cpp b/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridSpectralSolver.cpp
index 6b7a34271..5b7d95775 100644
--- a/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridSpectralSolver.cpp
+++ b/Source/FieldSolver/PicsarHybridSpectralSolver/PicsarHybridSpectralSolver.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpX_f.H>
diff --git a/Source/FieldSolver/PicsarHybridSpectralSolver/picsar_hybrid_spectral.F90 b/Source/FieldSolver/PicsarHybridSpectralSolver/picsar_hybrid_spectral.F90
index 35357a63f..96bfb6111 100644
--- a/Source/FieldSolver/PicsarHybridSpectralSolver/picsar_hybrid_spectral.F90
+++ b/Source/FieldSolver/PicsarHybridSpectralSolver/picsar_hybrid_spectral.F90
@@ -1,3 +1,10 @@
+! Copyright 2019 Andrew Myers, Maxence Thevenet, Remi Lehe
+! Weiqun Zhang
+!
+! This file is part of WarpX.
+!
+! License: BSD-3-Clause-LBNL
+
module warpx_fft_module
use amrex_error_module, only : amrex_error, amrex_abort
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.H
index 80ceb2e93..4452002d1 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PML_PSATD_ALGORITHM_H_
#define WARPX_PML_PSATD_ALGORITHM_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.cpp
index d76259d4c..bae74daf6 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PMLPsatdAlgorithm.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <PMLPsatdAlgorithm.H>
#include <WarpXConst.H>
#include <cmath>
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H
index b7aed9e40..4abe89d9d 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PSATD_ALGORITHM_H_
#define WARPX_PSATD_ALGORITHM_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp
index d45b01bda..4f4963e95 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithm.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe, Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <PsatdAlgorithm.H>
#include <WarpXConst.H>
#include <cmath>
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H
index 5d5e376c1..2c4946190 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/SpectralBaseAlgorithm.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SPECTRAL_BASE_ALGORITHM_H_
#define WARPX_SPECTRAL_BASE_ALGORITHM_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
index dc83d279d..e66a9ce50 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SPECTRAL_FIELD_DATA_H_
#define WARPX_SPECTRAL_FIELD_DATA_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
index edd4df34d..81e2b0907 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <SpectralFieldData.H>
using namespace amrex;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralKSpace.H b/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
index eb07e8fe6..c8b4f49eb 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralKSpace.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SPECTRAL_K_SPACE_H_
#define WARPX_SPECTRAL_K_SPACE_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp b/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
index aee131324..d0355fc1e 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralKSpace.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Andrew Myers, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpXConst.H>
#include <SpectralKSpace.H>
#include <cmath>
@@ -144,12 +151,7 @@ SpectralKSpace::getSpectralShiftFactor( const DistributionMapping& dm,
}
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
-
+ shift[i] = exp( I*sign*k[i]*0.5*dx[i_dim]);
}
}
return shift_factor;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.H b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
index bd92d003f..a6375e483 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralSolver.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
@@ -1,3 +1,9 @@
+/* Copyright 2019-2020 Maxence Thevenet, Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SPECTRAL_SOLVER_H_
#define WARPX_SPECTRAL_SOLVER_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
index 4b9def013..ca7bd06a0 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <SpectralKSpace.H>
#include <SpectralSolver.H>
#include <PsatdAlgorithm.H>
diff --git a/Source/FieldSolver/SpectralSolver/WarpX_ComplexForFFT.H b/Source/FieldSolver/SpectralSolver/WarpX_ComplexForFFT.H
index 43c7a1950..f75c9b19a 100644
--- a/Source/FieldSolver/SpectralSolver/WarpX_ComplexForFFT.H
+++ b/Source/FieldSolver/SpectralSolver/WarpX_ComplexForFFT.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 David Grote
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_COMPLEXFORFFT_H_
#define WARPX_COMPLEXFORFFT_H_
diff --git a/Source/FieldSolver/WarpXPushFieldsEM.cpp b/Source/FieldSolver/WarpXPushFieldsEM.cpp
index 4848b051e..1e922ecd3 100644
--- a/Source/FieldSolver/WarpXPushFieldsEM.cpp
+++ b/Source/FieldSolver/WarpXPushFieldsEM.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Aurore Blelly, Axel Huebl
+ * David Grote, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <cmath>
#include <limits>
diff --git a/Source/FieldSolver/WarpX_FDTD.H b/Source/FieldSolver/WarpX_FDTD.H
index b93c0f40a..4ad251264 100644
--- a/Source/FieldSolver/WarpX_FDTD.H
+++ b/Source/FieldSolver/WarpX_FDTD.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, David Grote
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_FDTD_H_
#define WARPX_FDTD_H_
diff --git a/Source/FieldSolver/WarpX_K.H b/Source/FieldSolver/WarpX_K.H
index f61a71e21..a4f657909 100644
--- a/Source/FieldSolver/WarpX_K.H
+++ b/Source/FieldSolver/WarpX_K.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_K_H_
#define WARPX_K_H_
diff --git a/Source/Filter/BilinearFilter.H b/Source/Filter/BilinearFilter.H
index 150ca8e08..f5405946b 100644
--- a/Source/Filter/BilinearFilter.H
+++ b/Source/Filter/BilinearFilter.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <Filter.H>
#ifndef WARPX_BILIN_FILTER_H_
diff --git a/Source/Filter/BilinearFilter.cpp b/Source/Filter/BilinearFilter.cpp
index 23abaf8bc..fd9153316 100644
--- a/Source/Filter/BilinearFilter.cpp
+++ b/Source/Filter/BilinearFilter.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <BilinearFilter.H>
#include <WarpX_f.H>
diff --git a/Source/Filter/Filter.H b/Source/Filter/Filter.H
index 1ecb1bff4..4e36a1f1f 100644
--- a/Source/Filter/Filter.H
+++ b/Source/Filter/Filter.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <AMReX_MultiFab.H>
#ifndef WARPX_FILTER_H_
diff --git a/Source/Filter/Filter.cpp b/Source/Filter/Filter.cpp
index 93729a0ae..dbe13747e 100644
--- a/Source/Filter/Filter.cpp
+++ b/Source/Filter/Filter.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <Filter.H>
diff --git a/Source/Filter/NCIGodfreyFilter.H b/Source/Filter/NCIGodfreyFilter.H
index de41de7ae..c174422c4 100644
--- a/Source/Filter/NCIGodfreyFilter.H
+++ b/Source/Filter/NCIGodfreyFilter.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <Filter.H>
#ifndef WARPX_GODFREY_FILTER_H_
diff --git a/Source/Filter/NCIGodfreyFilter.cpp b/Source/Filter/NCIGodfreyFilter.cpp
index 8723322f6..1a400cb32 100644
--- a/Source/Filter/NCIGodfreyFilter.cpp
+++ b/Source/Filter/NCIGodfreyFilter.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019-2020 Luca Fedeli, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <NCIGodfreyFilter.H>
#include <NCIGodfreyTables.H>
@@ -35,7 +41,7 @@ void NCIGodfreyFilter::ComputeStencils(){
"ERROR: NCI filter requires 5 points in z");
// Interpolate coefficients from the table, and store into prestencil.
- int index = tab_length*m_cdtodz;
+ auto index = static_cast<int>(tab_length*m_cdtodz);
index = min(index, tab_length-2);
index = max(index, 0);
Real weight_right = m_cdtodz - index/tab_length;
diff --git a/Source/FortranInterface/WarpX_f.F90 b/Source/FortranInterface/WarpX_f.F90
index 762ed2cd8..71b1ae9fa 100644
--- a/Source/FortranInterface/WarpX_f.F90
+++ b/Source/FortranInterface/WarpX_f.F90
@@ -1,3 +1,11 @@
+! Copyright 2019 Andrew Myers, Axel Huebl, David Grote
+! Ligia Diana Amorim, Mathieu Lobet, Maxence Thevenet
+! Remi Lehe, Weiqun Zhang
+!
+! This file is part of WarpX.
+!
+! License: BSD-3-Clause-LBNL
+
module warpx_module
@@ -8,49 +16,6 @@ module warpx_module
contains
- subroutine warpx_compute_E (lo, hi, &
- phi, phlo, phhi, &
- Ex, Exlo, Exhi, &
- Ey, Eylo, Eyhi, &
- Ez, Ezlo, Ezhi, &
- dx) bind(c,name='warpx_compute_E')
- integer(c_int), intent(in) :: lo(3), hi(3), phlo(3), phhi(3), Exlo(3), Exhi(3), &
- Eylo(3), Eyhi(3), Ezlo(3), Ezhi(3)
- real(amrex_real), intent(in) :: dx(3)
- real(amrex_real), intent(in ) :: phi(phlo(1):phhi(1),phlo(2):phhi(2),phlo(3):phhi(3))
- real(amrex_real), intent(inout) :: Ex (Exlo(1):Exhi(1),Exlo(2):Exhi(2),Exlo(3):Exhi(3))
- real(amrex_real), intent(inout) :: Ey (Eylo(1):Eyhi(1),Eylo(2):Eyhi(2),Eylo(3):Eyhi(3))
- real(amrex_real), intent(inout) :: Ez (Ezlo(1):Ezhi(1),Ezlo(2):Ezhi(2),Ezlo(3):Ezhi(3))
-
- integer :: i, j, k
- real(amrex_real) :: dxinv(3)
-
- dxinv = 1.0 / dx
-
- do k = lo(3), hi(3)
- do j = lo(2), hi(2)
-
- do i = lo(1), hi(1)-1
- Ex(i,j,k) = dxinv(1) * (phi(i,j,k) - phi(i+1,j,k))
- end do
-
- if (j < hi(2)) then
- do i = lo(1), hi(1)
- Ey(i,j,k) = dxinv(2) * (phi(i,j,k) - phi(i,j+1,k))
- end do
- end if
-
- if (k < hi(3)) then
- do i = lo(1), hi(1)
- Ez(i,j,k) = dxinv(3) * (phi(i,j,k) - phi(i,j,k+1))
- end do
- end if
-
- end do
- end do
-
- end subroutine warpx_compute_E
-
subroutine warpx_build_buffer_masks (lo, hi, msk, mlo, mhi, gmsk, glo, ghi, ng) &
bind(c, name='warpx_build_buffer_masks')
integer, dimension(3), intent(in) :: lo, hi, mlo, mhi, glo, ghi
diff --git a/Source/FortranInterface/WarpX_f.H b/Source/FortranInterface/WarpX_f.H
index 48aaac275..74fd9f379 100644
--- a/Source/FortranInterface/WarpX_f.H
+++ b/Source/FortranInterface/WarpX_f.H
@@ -1,3 +1,13 @@
+/* Copyright 2019 Andrew Myers, Aurore Blelly, Axel Huebl
+ * David Grote, Jean-Luc Vay, Ligia Diana Amorim
+ * Luca Fedeli, Mathieu Lobet, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_F_H_
#define WARPX_F_H_
@@ -24,7 +34,6 @@
#define WRPX_INTERPOLATE_CIC warpx_interpolate_cic_3d
#define WRPX_INTERPOLATE_CIC_TWO_LEVELS warpx_interpolate_cic_two_levels_3d
#define WRPX_PUSH_LEAPFROG warpx_push_leapfrog_3d
-#define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_3d
#elif (AMREX_SPACEDIM == 2)
@@ -33,7 +42,6 @@
#define WRPX_INTERPOLATE_CIC warpx_interpolate_cic_2d
#define WRPX_INTERPOLATE_CIC_TWO_LEVELS warpx_interpolate_cic_two_levels_2d
#define WRPX_PUSH_LEAPFROG warpx_push_leapfrog_2d
-#define WRPX_PUSH_LEAPFROG_POSITIONS warpx_push_leapfrog_positions_2d
#endif
diff --git a/Source/Initialization/CustomDensityProb.H b/Source/Initialization/CustomDensityProb.H
index c5c159ee8..804b56ce8 100644
--- a/Source/Initialization/CustomDensityProb.H
+++ b/Source/Initialization/CustomDensityProb.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef CUSTOM_DENSITY_PROB_H_
#define CUSTOM_DENSITY_PROB_H_
diff --git a/Source/Initialization/CustomMomentumProb.H b/Source/Initialization/CustomMomentumProb.H
index f8bc29a05..0b4d531c7 100644
--- a/Source/Initialization/CustomMomentumProb.H
+++ b/Source/Initialization/CustomMomentumProb.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef CUSTOM_MOMENTUM_PROB_H
#define CUSTOM_MOMENTUM_PROB_H
diff --git a/Source/Initialization/InitSpaceChargeField.cpp b/Source/Initialization/InitSpaceChargeField.cpp
index 0a873b742..36914d2c6 100644
--- a/Source/Initialization/InitSpaceChargeField.cpp
+++ b/Source/Initialization/InitSpaceChargeField.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <AMReX_ParallelDescriptor.H>
#include <AMReX_MLMG.H>
diff --git a/Source/Initialization/InjectorDensity.H b/Source/Initialization/InjectorDensity.H
index 7e61ae27d..4558eeb96 100644
--- a/Source/Initialization/InjectorDensity.H
+++ b/Source/Initialization/InjectorDensity.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef INJECTOR_DENSITY_H_
#define INJECTOR_DENSITY_H_
diff --git a/Source/Initialization/InjectorDensity.cpp b/Source/Initialization/InjectorDensity.cpp
index 9f711a7af..f59202db9 100644
--- a/Source/Initialization/InjectorDensity.cpp
+++ b/Source/Initialization/InjectorDensity.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Axel Huebl, Ligia Diana Amorim, Maxence Thevenet
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <InjectorDensity.H>
#include <PlasmaInjector.H>
@@ -36,8 +43,8 @@ InjectorDensity::sharedMemoryNeeded () const noexcept
case Type::parser:
{
// For parser injector, the 3D position of each particle
- // is stored in shared memory.
- return amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 3;
+ // and time, t, is stored in shared memory.
+ return amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 4;
}
default:
return 0;
diff --git a/Source/Initialization/InjectorMomentum.H b/Source/Initialization/InjectorMomentum.H
index 88c954df6..bb5a70784 100644
--- a/Source/Initialization/InjectorMomentum.H
+++ b/Source/Initialization/InjectorMomentum.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Cameron Yang, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef INJECTOR_MOMENTUM_H_
#define INJECTOR_MOMENTUM_H_
diff --git a/Source/Initialization/InjectorMomentum.cpp b/Source/Initialization/InjectorMomentum.cpp
index 8fadf0c4b..edbba8ac5 100644
--- a/Source/Initialization/InjectorMomentum.cpp
+++ b/Source/Initialization/InjectorMomentum.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Axel Huebl, Maxence Thevenet, Revathi Jambunathan
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <InjectorMomentum.H>
#include <PlasmaInjector.H>
@@ -30,9 +37,9 @@ InjectorMomentum::sharedMemoryNeeded () const noexcept
{
case Type::parser:
{
- // For parser injector, the 3D position of each particle
+ // For parser injector, the 3D position of each particle and time, t,
// is stored in shared memory.
- return amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 3;
+ return amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 4;
}
default:
return 0;
diff --git a/Source/Initialization/InjectorPosition.H b/Source/Initialization/InjectorPosition.H
index 4ab2fa022..a8d2200e9 100644
--- a/Source/Initialization/InjectorPosition.H
+++ b/Source/Initialization/InjectorPosition.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef INJECTOR_POSITION_H_
#define INJECTOR_POSITION_H_
diff --git a/Source/Initialization/PlasmaInjector.H b/Source/Initialization/PlasmaInjector.H
index 56b32c827..70d99b9a3 100644
--- a/Source/Initialization/PlasmaInjector.H
+++ b/Source/Initialization/PlasmaInjector.H
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Grote
+ * Maxence Thevenet, Remi Lehe, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef PLASMA_INJECTOR_H_
#define PLASMA_INJECTOR_H_
diff --git a/Source/Initialization/PlasmaInjector.cpp b/Source/Initialization/PlasmaInjector.cpp
index f7c7e498f..96e82d749 100644
--- a/Source/Initialization/PlasmaInjector.cpp
+++ b/Source/Initialization/PlasmaInjector.cpp
@@ -1,8 +1,18 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, Cameron Yang
+ * David Grote, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "PlasmaInjector.H"
#include <WarpXConst.H>
#include <WarpX_f.H>
#include <WarpX.H>
+#include <WarpXUtil.H>
#include <AMReX.H>
@@ -168,34 +178,6 @@ PlasmaInjector::PlasmaInjector (int ispecies, const std::string& name)
}
}
-namespace {
-WarpXParser makeParser (std::string const& parse_function)
-{
- WarpXParser parser(parse_function);
- parser.registerVariables({"x","y","z"});
-
- ParmParse pp("my_constants");
- std::set<std::string> symbols = parser.symbols();
- symbols.erase("x");
- symbols.erase("y");
- symbols.erase("z"); // 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("PlasmaInjector::makeParser: Unknown symbol "+s);
- }
-
- return parser;
-}
-}
-
// Depending on injection type at runtime, initialize inj_rho
// so that inj_rho->getDensity calls
// InjectorPosition[Constant or Custom or etc.].getDensity.
@@ -217,11 +199,7 @@ void PlasmaInjector::parseDensity (ParmParse& pp)
// Construct InjectorDensity with InjectorDensityPredefined.
inj_rho.reset(new InjectorDensity((InjectorDensityPredefined*)nullptr,species_name));
} else if (rho_prof_s == "parse_density_function") {
- std::vector<std::string> f;
- pp.getarr("density_function(x,y,z)", f);
- for (auto const& s : f) {
- str_density_function += s;
- }
+ Store_parserString(pp, "density_function(x,y,z)", str_density_function);
// Construct InjectorDensity with InjectorDensityParser.
inj_rho.reset(new InjectorDensity((InjectorDensityParser*)nullptr,
makeParser(str_density_function)));
@@ -339,21 +317,12 @@ void PlasmaInjector::parseMomentum (ParmParse& pp)
inj_mom.reset(new InjectorMomentum
((InjectorMomentumRadialExpansion*)nullptr, u_over_r));
} else if (mom_dist_s == "parse_momentum_function") {
- std::vector<std::string> f;
- pp.getarr("momentum_function_ux(x,y,z)", f);
- for (auto const& s : f) {
- str_momentum_function_ux += s;
- }
- f.clear();
- pp.getarr("momentum_function_uy(x,y,z)", f);
- for (auto const& s : f) {
- str_momentum_function_uy += s;
- }
- f.clear();
- pp.getarr("momentum_function_uz(x,y,z)", f);
- for (auto const& s : f) {
- str_momentum_function_uz += s;
- }
+ Store_parserString(pp, "momentum_function_ux(x,y,z)",
+ str_momentum_function_ux);
+ Store_parserString(pp, "momentum_function_uy(x,y,z)",
+ str_momentum_function_uy);
+ Store_parserString(pp, "momentum_function_uz(x,y,z)",
+ str_momentum_function_uz);
// Construct InjectorMomentum with InjectorMomentumParser.
inj_mom.reset(new InjectorMomentum((InjectorMomentumParser*)nullptr,
makeParser(str_momentum_function_ux),
diff --git a/Source/Initialization/WarpXInitData.cpp b/Source/Initialization/WarpXInitData.cpp
index 29c9a8955..8b2fe1831 100644
--- a/Source/Initialization/WarpXInitData.cpp
+++ b/Source/Initialization/WarpXInitData.cpp
@@ -1,4 +1,12 @@
-
+/* Copyright 2019-2020 Andrew Myers, Ann Almgren, Aurore Blelly
+ * Axel Huebl, Burlen Loring, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpX_f.H>
#include <BilinearFilter.H>
@@ -10,6 +18,9 @@
#ifdef BL_USE_SENSEI_INSITU
#include <AMReX_AmrMeshInSituBridge.H>
#endif
+#include <GpuParser.H>
+#include <WarpXUtil.H>
+
using namespace amrex;
@@ -72,11 +83,21 @@ WarpX::InitData ()
if (plot_int > 0)
WritePlotFile();
+ if (openpmd_int > 0)
+ WriteOpenPMDFile();
+
if (check_int > 0)
WriteCheckPointFile();
if ((insitu_int > 0) && (insitu_start == 0))
UpdateInSitu();
+
+ // Write reduced diagnostics before the first iteration.
+ if (reduced_diags->m_plot_rd != 0)
+ {
+ reduced_diags->ComputeDiags(-1);
+ reduced_diags->WriteToFile(-1);
+ }
}
}
@@ -231,24 +252,161 @@ WarpX::PostRestart ()
mypc->PostRestart();
}
+
void
WarpX::InitLevelData (int lev, Real time)
{
+
+ ParmParse pp("warpx");
+
+ // default values of E_external_grid and B_external_grid
+ // are used to set the E and B field when "constant" or
+ // "parser" is not explicitly used in the input.
+ pp.query("B_ext_grid_init_style", B_ext_grid_s);
+ std::transform(B_ext_grid_s.begin(),
+ B_ext_grid_s.end(),
+ B_ext_grid_s.begin(),
+ ::tolower);
+
+ pp.query("E_ext_grid_init_style", E_ext_grid_s);
+ std::transform(E_ext_grid_s.begin(),
+ E_ext_grid_s.end(),
+ E_ext_grid_s.begin(),
+ ::tolower);
+
+ // if the input string is "constant", the values for the
+ // external grid must be provided in the input.
+ if (B_ext_grid_s == "constant")
+ pp.getarr("B_external_grid", B_external_grid);
+
+ // if the input string is "constant", the values for the
+ // external grid must be provided in the input.
+ if (E_ext_grid_s == "constant")
+ pp.getarr("E_external_grid", E_external_grid);
+
for (int i = 0; i < 3; ++i) {
current_fp[lev][i]->setVal(0.0);
- Efield_fp[lev][i]->setVal(E_external_grid[i]);
- Bfield_fp[lev][i]->setVal(B_external_grid[i]);
+ if (lev > 0)
+ current_cp[lev][i]->setVal(0.0);
+
+ if (B_ext_grid_s == "constant" || B_ext_grid_s == "default") {
+ Bfield_fp[lev][i]->setVal(B_external_grid[i]);
+ if (lev > 0) {
+ Bfield_aux[lev][i]->setVal(B_external_grid[i]);
+ Bfield_cp[lev][i]->setVal(B_external_grid[i]);
+ }
+ }
+ if (E_ext_grid_s == "constant" || E_ext_grid_s == "default") {
+ Efield_fp[lev][i]->setVal(E_external_grid[i]);
+ if (lev > 0) {
+ Efield_aux[lev][i]->setVal(E_external_grid[i]);
+ Efield_cp[lev][i]->setVal(E_external_grid[i]);
+ }
+ }
}
- if (lev > 0) {
- for (int i = 0; i < 3; ++i) {
- Efield_aux[lev][i]->setVal(E_external_grid[i]);
- Bfield_aux[lev][i]->setVal(B_external_grid[i]);
+ // if the input string for the B-field is "parse_b_ext_grid_function",
+ // then the analytical expression or function must be
+ // provided in the input file.
+ if (B_ext_grid_s == "parse_b_ext_grid_function") {
- current_cp[lev][i]->setVal(0.0);
- Efield_cp[lev][i]->setVal(E_external_grid[i]);
- Bfield_cp[lev][i]->setVal(B_external_grid[i]);
- }
+#ifdef WARPX_DIM_RZ
+ amrex::Abort("E and B parser for external fields does not work with RZ -- TO DO");
+#endif
+ Store_parserString(pp, "Bx_external_grid_function(x,y,z)",
+ str_Bx_ext_grid_function);
+ Store_parserString(pp, "By_external_grid_function(x,y,z)",
+ str_By_ext_grid_function);
+ Store_parserString(pp, "Bz_external_grid_function(x,y,z)",
+ str_Bz_ext_grid_function);
+
+ Bxfield_parser.reset(new ParserWrapper(
+ makeParser(str_Bx_ext_grid_function)));
+ Byfield_parser.reset(new ParserWrapper(
+ makeParser(str_By_ext_grid_function)));
+ Bzfield_parser.reset(new ParserWrapper(
+ makeParser(str_Bz_ext_grid_function)));
+
+ // Initialize Bfield_fp with external function
+ InitializeExternalFieldsOnGridUsingParser(Bfield_fp[lev][0].get(),
+ Bfield_fp[lev][1].get(),
+ Bfield_fp[lev][2].get(),
+ Bxfield_parser.get(),
+ Byfield_parser.get(),
+ Bzfield_parser.get(),
+ Bx_nodal_flag, By_nodal_flag,
+ Bz_nodal_flag, lev);
+ if (lev > 0) {
+ InitializeExternalFieldsOnGridUsingParser(Bfield_aux[lev][0].get(),
+ Bfield_aux[lev][1].get(),
+ Bfield_aux[lev][2].get(),
+ Bxfield_parser.get(),
+ Byfield_parser.get(),
+ Bzfield_parser.get(),
+ Bx_nodal_flag, By_nodal_flag,
+ Bz_nodal_flag, lev);
+
+ InitializeExternalFieldsOnGridUsingParser(Bfield_cp[lev][0].get(),
+ Bfield_cp[lev][1].get(),
+ Bfield_cp[lev][2].get(),
+ Bxfield_parser.get(),
+ Byfield_parser.get(),
+ Bzfield_parser.get(),
+ Bx_nodal_flag, By_nodal_flag,
+ Bz_nodal_flag, lev);
+ }
+ }
+
+ // if the input string for the E-field is "parse_e_ext_grid_function",
+ // then the analytical expression or function must be
+ // provided in the input file.
+ if (E_ext_grid_s == "parse_e_ext_grid_function") {
+
+#ifdef WARPX_DIM_RZ
+ amrex::Abort("E and B parser for external fields does not work with RZ -- TO DO");
+#endif
+ Store_parserString(pp, "Ex_external_grid_function(x,y,z)",
+ str_Ex_ext_grid_function);
+ Store_parserString(pp, "Ey_external_grid_function(x,y,z)",
+ str_Ey_ext_grid_function);
+ Store_parserString(pp, "Ez_external_grid_function(x,y,z)",
+ str_Ez_ext_grid_function);
+
+ Exfield_parser.reset(new ParserWrapper(
+ makeParser(str_Ex_ext_grid_function)));
+ Eyfield_parser.reset(new ParserWrapper(
+ makeParser(str_Ey_ext_grid_function)));
+ Ezfield_parser.reset(new ParserWrapper(
+ makeParser(str_Ez_ext_grid_function)));
+
+ // Initialize Efield_fp with external function
+ InitializeExternalFieldsOnGridUsingParser(Efield_fp[lev][0].get(),
+ Efield_fp[lev][1].get(),
+ Efield_fp[lev][2].get(),
+ Exfield_parser.get(),
+ Eyfield_parser.get(),
+ Ezfield_parser.get(),
+ Ex_nodal_flag, Ey_nodal_flag,
+ Ez_nodal_flag, lev);
+ if (lev > 0) {
+ InitializeExternalFieldsOnGridUsingParser(Efield_aux[lev][0].get(),
+ Efield_aux[lev][1].get(),
+ Efield_aux[lev][2].get(),
+ Exfield_parser.get(),
+ Eyfield_parser.get(),
+ Ezfield_parser.get(),
+ Ex_nodal_flag, Ey_nodal_flag,
+ Ez_nodal_flag, lev);
+
+ InitializeExternalFieldsOnGridUsingParser(Efield_cp[lev][0].get(),
+ Efield_cp[lev][1].get(),
+ Efield_cp[lev][2].get(),
+ Exfield_parser.get(),
+ Eyfield_parser.get(),
+ Ezfield_parser.get(),
+ Ex_nodal_flag, Ey_nodal_flag,
+ Ez_nodal_flag, lev);
+ }
}
if (F_fp[lev]) {
@@ -306,3 +464,100 @@ WarpX::InitLevelDataFFT (int lev, Real time)
}
#endif
+
+void
+WarpX::InitializeExternalFieldsOnGridUsingParser (
+ MultiFab *mfx, MultiFab *mfy, MultiFab *mfz,
+ ParserWrapper *xfield_parser, ParserWrapper *yfield_parser,
+ ParserWrapper *zfield_parser, IntVect x_nodal_flag,
+ IntVect y_nodal_flag, IntVect z_nodal_flag,
+ const int lev)
+{
+
+ const auto dx_lev = geom[lev].CellSizeArray();
+ const RealBox& real_box = geom[lev].ProbDomain();
+ for ( MFIter mfi(*mfx, TilingIfNotGPU()); mfi.isValid(); ++mfi)
+ {
+ const Box& tbx = mfi.tilebox(x_nodal_flag);
+ const Box& tby = mfi.tilebox(y_nodal_flag);
+ const Box& tbz = mfi.tilebox(z_nodal_flag);
+
+ auto const& mfxfab = mfx->array(mfi);
+ auto const& mfyfab = mfy->array(mfi);
+ auto const& mfzfab = mfz->array(mfi);
+
+ auto const& mfx_IndexType = (*mfx).ixType();
+ auto const& mfy_IndexType = (*mfy).ixType();
+ auto const& mfz_IndexType = (*mfz).ixType();
+
+ // Initialize IntVect based on the index type of multiFab
+ // 0 if cell-centered, 1 if node-centered.
+ IntVect mfx_type(AMREX_D_DECL(0,0,0));
+ IntVect mfy_type(AMREX_D_DECL(0,0,0));
+ IntVect mfz_type(AMREX_D_DECL(0,0,0));
+
+ for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
+ mfx_type[idim] = mfx_IndexType.nodeCentered(idim);
+ mfy_type[idim] = mfy_IndexType.nodeCentered(idim);
+ mfz_type[idim] = mfz_IndexType.nodeCentered(idim);
+ }
+
+ amrex::ParallelFor (tbx, tby, tbz,
+ [=] AMREX_GPU_DEVICE (int i, int j, int k) {
+ // Shift required in the x-, y-, or z- position
+ // depending on the index type of the multifab
+ Real fac_x = (1.0 - mfx_type[0]) * dx_lev[0]*0.5;
+ Real x = i*dx_lev[0] + real_box.lo(0) + fac_x;
+#if (AMREX_SPACEDIM==2)
+ Real y = 0.0;
+ Real fac_z = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real z = j*dx_lev[1] + real_box.lo(1) + fac_z;
+#else
+ Real fac_y = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real y = j*dx_lev[1] + real_box.lo(1) + fac_y;
+ Real fac_z = (1.0 - mfx_type[2]) * dx_lev[2]*0.5;
+ Real z = k*dx_lev[2] + real_box.lo(2) + fac_z;
+#endif
+ // Initialize the x-component of the field.
+ mfxfab(i,j,k) = xfield_parser->getField(x,y,z);
+ },
+ [=] AMREX_GPU_DEVICE (int i, int j, int k) {
+ Real fac_x = (1.0 - mfy_type[0]) * dx_lev[0]*0.5;
+ Real x = i*dx_lev[0] + real_box.lo(0) + fac_x;
+#if (AMREX_SPACEDIM==2)
+ Real y = 0.0;
+ Real fac_z = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real z = j*dx_lev[1] + real_box.lo(1) + fac_z;
+#elif (AMREX_SPACEDIM==3)
+ Real fac_y = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real y = j*dx_lev[1] + real_box.lo(1) + fac_y;
+ Real fac_z = (1.0 - mfx_type[2]) * dx_lev[2]*0.5;
+ Real z = k*dx_lev[2] + real_box.lo(2) + fac_z;
+#endif
+ // Initialize the y-component of the field.
+ mfyfab(i,j,k) = yfield_parser->getField(x,y,z);
+ },
+ [=] AMREX_GPU_DEVICE (int i, int j, int k) {
+ Real fac_x = (1.0 - mfz_type[0]) * dx_lev[0]*0.5;
+ Real x = i*dx_lev[0] + real_box.lo(0) + fac_x;
+#if (AMREX_SPACEDIM==2)
+ Real y = 0.0;
+ Real fac_z = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real z = j*dx_lev[1] + real_box.lo(1) + fac_z;
+#elif (AMREX_SPACEDIM==3)
+ Real fac_y = (1.0 - mfx_type[1]) * dx_lev[1]*0.5;
+ Real y = j*dx_lev[1] + real_box.lo(1) + fac_y;
+ Real fac_z = (1.0 - mfz_type[2]) * dx_lev[2]*0.5;
+ Real z = k*dx_lev[2] + real_box.lo(2) + fac_z;
+#endif
+ // Initialize the z-component of the field.
+ mfzfab(i,j,k) = zfield_parser->getField(x,y,z);
+ },
+ /* To allocate shared memory for the GPU threads. */
+ /* But, for now only 4 doubles (x,y,z,t) are allocated. */
+ amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 4
+ );
+
+ }
+
+}
diff --git a/Source/Laser/LaserParticleContainer.H b/Source/Laser/LaserParticleContainer.H
index 1e83ca02f..0d56783ed 100644
--- a/Source/Laser/LaserParticleContainer.H
+++ b/Source/Laser/LaserParticleContainer.H
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Grote
+ * Luca Fedeli, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_LaserParticleContainer_H_
#define WARPX_LaserParticleContainer_H_
diff --git a/Source/Laser/LaserParticleContainer.cpp b/Source/Laser/LaserParticleContainer.cpp
index a330200cc..de192e65e 100644
--- a/Source/Laser/LaserParticleContainer.cpp
+++ b/Source/Laser/LaserParticleContainer.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, David Grote
+ * Luca Fedeli, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <limits>
#include <cmath>
#include <algorithm>
@@ -249,8 +257,8 @@ LaserParticleContainer::InitData (int lev)
{
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;
+ auto i = static_cast<int>(pos_plane[0]/S_X);
+ auto j = static_cast<int>(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);
@@ -386,6 +394,9 @@ LaserParticleContainer::Evolve (int lev,
t_lab = 1./WarpX::gamma_boost*t + WarpX::beta_boost*Z0_lab/PhysConst::c;
}
+ // Update laser profile
+ m_up_laser_profile->update(t);
+
BL_ASSERT(OnSameGrids(lev,jx));
MultiFab* cost = WarpX::getCosts(lev);
@@ -463,17 +474,19 @@ LaserParticleContainer::Evolve (int lev,
// Current Deposition
//
// Deposit inside domains
- int* ion_lev = nullptr;
- DepositCurrent(pti, wp, uxp, uyp, uzp, ion_lev, &jx, &jy, &jz,
- 0, np_current, thread_num,
- lev, lev, dt);
-
- bool has_buffer = cjx;
- if (has_buffer){
- // Deposit in buffers
- DepositCurrent(pti, wp, uxp, uyp, uzp, ion_lev, cjx, cjy, cjz,
- np_current, np-np_current, thread_num,
- lev, lev-1, dt);
+ {
+ int* ion_lev = nullptr;
+ DepositCurrent(pti, wp, uxp, uyp, uzp, ion_lev, &jx, &jy, &jz,
+ 0, np_current, thread_num,
+ lev, lev, dt);
+
+ bool has_buffer = cjx;
+ if (has_buffer){
+ // Deposit in buffers
+ DepositCurrent(pti, wp, uxp, uyp, uzp, ion_lev, cjx, cjy, cjz,
+ np_current, np-np_current, thread_num,
+ lev, lev-1, dt);
+ }
}
//
diff --git a/Source/Laser/LaserProfiles.H b/Source/Laser/LaserProfiles.H
index e0ec0dc28..94cfae090 100644
--- a/Source/Laser/LaserProfiles.H
+++ b/Source/Laser/LaserProfiles.H
@@ -1,3 +1,9 @@
+/* Copyright 2019-2020 Luca Fedeli, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_LaserProfiles_H_
#define WARPX_LaserProfiles_H_
@@ -5,6 +11,7 @@
#include <WarpXParser.H>
#include <AMReX_ParmParse.H>
#include <AMReX_Vector.H>
+#include <AMReX_Gpu.H>
#include <WarpXParser.H>
@@ -13,6 +20,7 @@
#include <memory>
#include <functional>
#include <limits>
+#include <utility>
namespace WarpXLaserProfiles {
@@ -31,8 +39,8 @@ struct CommonLaserParameters
/** Abstract interface for laser profile classes
*
- * Each new laser profile should inherit this interface and implement two
- * methods: init and fill_amplitude (described below).
+ * Each new laser profile should inherit this interface and implement three
+ * methods: init, update and fill_amplitude (described below).
*
* The declaration of a LaserProfile class should be placed in this file,
* while the implementation of the methods should be in a dedicated file in
@@ -60,6 +68,17 @@ public:
const amrex::ParmParse& ppc,
CommonLaserParameters params) = 0;
+ /** Update Laser Profile
+ *
+ * Some laser profiles might need to perform an "update" operation per
+ * time step.
+ *
+ * @param[in] t Current physical time in the simulation (seconds)
+ */
+ virtual void
+ update (
+ amrex::Real t) = 0;
+
/** Fill Electric Field Amplitude for each particle of the antenna.
*
* Xp, Yp and amplitude must be arrays with the same length
@@ -76,7 +95,7 @@ public:
amrex::Real const * AMREX_RESTRICT const Xp,
amrex::Real const * AMREX_RESTRICT const Yp,
amrex::Real t,
- amrex::Real * AMREX_RESTRICT const amplitude) = 0;
+ amrex::Real * AMREX_RESTRICT const amplitude) const = 0;
virtual ~ILaserProfile(){};
};
@@ -94,13 +113,17 @@ public:
const amrex::ParmParse& ppc,
CommonLaserParameters params) override final;
+ //No update needed
+ void
+ update (amrex::Real /*t */) override final {}
+
void
fill_amplitude (
const int np,
amrex::Real const * AMREX_RESTRICT const Xp,
amrex::Real const * AMREX_RESTRICT const Yp,
amrex::Real t,
- amrex::Real * AMREX_RESTRICT const amplitude) override final;
+ amrex::Real * AMREX_RESTRICT const amplitude) const override final;
private:
struct {
@@ -132,13 +155,17 @@ public:
const amrex::ParmParse& ppc,
CommonLaserParameters params) override final;
+ //No update needed
+ void
+ update (amrex::Real /*t */) override final {}
+
void
fill_amplitude (
const int np,
amrex::Real const * AMREX_RESTRICT const Xp,
amrex::Real const * AMREX_RESTRICT const Yp,
amrex::Real t,
- amrex::Real * AMREX_RESTRICT const amplitude) override final;
+ amrex::Real * AMREX_RESTRICT const amplitude) const override final;
private:
struct {
@@ -163,13 +190,17 @@ public:
const amrex::ParmParse& ppc,
CommonLaserParameters params) override final;
+ //No update needed
+ void
+ update (amrex::Real /*t */) override final {}
+
void
fill_amplitude (
const int np,
amrex::Real const * AMREX_RESTRICT const Xp,
amrex::Real const * AMREX_RESTRICT const Yp,
amrex::Real t,
- amrex::Real * AMREX_RESTRICT const amplitude) override final;
+ amrex::Real * AMREX_RESTRICT const amplitude) const override final;
private:
struct{
@@ -180,6 +211,160 @@ private:
};
/**
+ * Laser profile read from an 'TXYE' file
+ * The binary file must contain:
+ * - 3 unsigned integers (4 bytes): nt (points along t), nx (points along x) and ny (points along y)
+ * - nt*nx*ny doubles (8 bytes) in row major order : field amplitude
+ */
+class FromTXYEFileLaserProfile : public ILaserProfile
+{
+
+public:
+ void
+ init (
+ const amrex::ParmParse& ppl,
+ const amrex::ParmParse& ppc,
+ CommonLaserParameters params) override final;
+
+ /** \brief Reads new field data chunk from file if needed
+ *
+ * @param[in] t simulation time (seconds)
+ */
+ void
+ update (amrex::Real t) override final;
+
+ /** \brief compute field amplitude at particles' position for a laser beam
+ * loaded from an E(x,y,t) file.
+ *
+ * Both Xp and Yp are given in laser plane coordinate.
+ * For each particle with position Xp and Yp, this routine computes the
+ * amplitude of the laser electric field, stored in array amplitude.
+ *
+ * \param np: number of laser particles
+ * \param Xp: pointer to first component of positions of laser particles
+ * \param Yp: pointer to second component of positions of laser particles
+ * \param t: Current physical time
+ * \param amplitude: pointer to array of field amplitude.
+ */
+ void
+ fill_amplitude (
+ const int np,
+ amrex::Real const * AMREX_RESTRICT const Xp,
+ amrex::Real const * AMREX_RESTRICT const Yp,
+ amrex::Real t,
+ amrex::Real * AMREX_RESTRICT const amplitude) const override final;
+
+ /** \brief Function to fill the amplitude in case of a uniform grid.
+ * This function cannot be private due to restrictions related to
+ * the use of extended __device__ lambda
+ *
+ * \param idx_t_left index of the last time coordinate < t
+ * \param np: number of laser particles
+ * \param Xp: pointer to first component of positions of laser particles
+ * \param Yp: pointer to second component of positions of laser particles
+ * \param t: Current physical time
+ * \param amplitude: pointer to array of field amplitude.
+ */
+ void internal_fill_amplitude_uniform(
+ const int idx_t_left,
+ const int np,
+ amrex::Real const * AMREX_RESTRICT const Xp,
+ amrex::Real const * AMREX_RESTRICT const Yp,
+ amrex::Real t,
+ amrex::Real * AMREX_RESTRICT const amplitude) const;
+
+ /** \brief Function to fill the amplitude in case of a non-uniform grid.
+ * This function cannot be private due to restrictions related to
+ * the use of extended __device__ lambda
+ *
+ * \param idx_t_left index of the last time coordinate < t
+ * \param np: number of laser particles
+ * \param Xp: pointer to first component of positions of laser particles
+ * \param Yp: pointer to second component of positions of laser particles
+ * \param t: Current physical time
+ * \param amplitude: pointer to array of field amplitude.
+ */
+ void internal_fill_amplitude_nonuniform(
+ const int idx_t_left,
+ const int np,
+ amrex::Real const * AMREX_RESTRICT const Xp,
+ amrex::Real const * AMREX_RESTRICT const Yp,
+ amrex::Real t,
+ amrex::Real * AMREX_RESTRICT const amplitude) const;
+
+private:
+ /** \brief parse a field file in the binary 'txye' format (whose details are given below).
+ *
+ * A 'txye' file should be a binary file with the following format:
+ * -flag to indicate if the grid is uniform or not (1 byte, 0 means non-uniform, !=0 means uniform)
+ * -np, number of timesteps (uint32_t, must be >=2)
+ * -nx, number of points along x (uint32_t, must be >=2)
+ * -ny, number of points along y (uint32_t, must be 1 for 2D simulations and >=2 for 3D simulations)
+ * -timesteps (double[2] if grid is uniform, double[np] otherwise)
+ * -x_coords (double[2] if grid is uniform, double[nx] otherwise)
+ * -y_coords (double[1] if 2D, double[2] if 3D & uniform grid, double[ny] if 3D & non uniform grid)
+ * -field_data (double[nt * nx * ny], with nt being the slowest coordinate).
+ * The spatiotemporal grid must be rectangular.
+ *
+ * \param txye_file_name: name of the file to parse
+ */
+ void parse_txye_file(std::string txye_file_name);
+
+ /** \brief Finds left and right time indices corresponding to time t
+ *
+ *
+ * \param t: simulation time
+ */
+ std::pair<int,int> find_left_right_time_indices(amrex::Real t) const;
+
+ /** \brief Load field data within the temporal range [t_begin, t_end)
+ *
+ * Must be called after having parsed a data file with parse_txye_file.
+ *
+ * \param t_begin: left limit of the timestep range to read
+ * \param t_end: right limit of the timestep range to read (t_end is not read)
+ */
+ void read_data_t_chuck(int t_begin, int t_end);
+
+ /**
+ * \brief m_params contains all the internal parameters
+ * used by this laser profile
+ */
+ struct{
+ /** Name of the file containing the data */
+ std::string txye_file_name;
+ /** Flag to store if the grid is uniform */
+ bool is_grid_uniform = false;
+ /** Dimensions of E_data. nt, nx must be >=2.
+ * If DIM=3, ny must be >=2 as well.
+ * If DIM=2, ny must be 1 */
+ int nt, nx, ny;
+ /** Vector of temporal coordinates. For a non-uniform grid, it contains
+ * all values of time. For a uniform grid, it contains only the start and stop
+ * times and intermediate times are obtained with nt */
+ amrex::Gpu::ManagedVector<amrex::Real> t_coords;
+ /** Vector or x coordinates. For a non-uniform grid, it contains all values
+ * of space dimension x. For a uniform grid, it contains only the min and max
+ * x coordinates, and intermediate positions are obtained with nx */
+ amrex::Gpu::ManagedVector<amrex::Real> x_coords;
+ /** Vector or y coordinates. For a non-uniform grid, it contains all values
+ * of space dimension y. For a uniform grid, it contains only the min and max
+ * y coordinates, and intermediate positions are obtained with ny */
+ amrex::Gpu::ManagedVector<amrex::Real> y_coords;
+ /** Size of the timestep range to load */
+ int time_chunk_size;
+ /** Index of the first timestep in memory */
+ int first_time_index;
+ /** Index of the last timestep in memory */
+ int last_time_index;
+ /** Field data */
+ amrex::Gpu::ManagedVector<amrex::Real> E_data;
+ } m_params;
+
+ CommonLaserParameters m_common_params;
+};
+
+/**
* Maps laser profile names to lambdas returing unique pointers
* to the corresponding laser profile objects.
*/
@@ -195,7 +380,9 @@ laser_profiles_dictionary =
{"harris",
[] () {return std::make_unique<HarrisLaserProfile>();} },
{"parse_field_function",
- [] () {return std::make_unique<FieldFunctionLaserProfile>();} }
+ [] () {return std::make_unique<FieldFunctionLaserProfile>();} },
+ {"from_txye_file",
+ [] () {return std::make_unique<FromTXYEFileLaserProfile>();} }
};
} //WarpXLaserProfiles
diff --git a/Source/Laser/LaserProfilesImpl/LaserProfileFieldFunction.cpp b/Source/Laser/LaserProfilesImpl/LaserProfileFieldFunction.cpp
index 3c9d7379a..66660d6be 100644
--- a/Source/Laser/LaserProfilesImpl/LaserProfileFieldFunction.cpp
+++ b/Source/Laser/LaserProfilesImpl/LaserProfileFieldFunction.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <LaserProfiles.H>
#include <WarpX_Complex.H>
@@ -37,7 +43,7 @@ FieldFunctionLaserProfile::init (
void
FieldFunctionLaserProfile::fill_amplitude (
const int np, Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
- Real t, Real * AMREX_RESTRICT const amplitude)
+ Real t, Real * AMREX_RESTRICT const amplitude) const
{
for (int i = 0; i < np; ++i) {
amplitude[i] = m_parser.eval(Xp[i], Yp[i], t);
diff --git a/Source/Laser/LaserProfilesImpl/LaserProfileFromTXYEFile.cpp b/Source/Laser/LaserProfilesImpl/LaserProfileFromTXYEFile.cpp
new file mode 100644
index 000000000..114464dbf
--- /dev/null
+++ b/Source/Laser/LaserProfilesImpl/LaserProfileFromTXYEFile.cpp
@@ -0,0 +1,485 @@
+/* Copyright 2019-2020 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#include <LaserProfiles.H>
+
+#include <WarpX_Complex.H>
+#include <WarpXConst.H>
+#include <WarpXUtil.H>
+
+#include <AMReX_Print.H>
+#include <AMReX_ParallelDescriptor.H>
+
+#include <limits>
+#include <iostream>
+#include <fstream>
+#include <cstdint>
+#include <algorithm>
+
+using namespace amrex;
+using namespace WarpXLaserProfiles;
+
+void
+FromTXYEFileLaserProfile::init (
+ const amrex::ParmParse& ppl,
+ const amrex::ParmParse& /* ppc */,
+ CommonLaserParameters params)
+{
+ if (!std::numeric_limits< double >::is_iec559)
+ {
+ Print() << R"(Warning: double does not comply with IEEE 754: bad
+ things will happen parsing the X, Y and T profiles for the laser!)";
+ }
+
+ // Parse the TXYE file
+ ppl.get("txye_file_name", m_params.txye_file_name);
+ if(m_params.txye_file_name.empty())
+ {
+ Abort("txye_file_name must be provided for txye_file laser profile!");
+ }
+ parse_txye_file(m_params.txye_file_name);
+
+ //Set time_chunk_size
+ m_params.time_chunk_size = m_params.nt;
+ int temp = 1;
+ if(ppl.query("time_chunk_size", temp)){
+ m_params.time_chunk_size = min(
+ temp, m_params.time_chunk_size);
+ }
+ if(m_params.time_chunk_size < 2){
+ Abort("Error! time_chunk_size must be >= 2!");
+ }
+
+ //Allocate memory for E_data Vector
+ const int data_size = m_params.time_chunk_size*
+ m_params.nx*m_params.ny;
+ m_params.E_data = Gpu::ManagedVector<amrex::Real>(data_size);
+
+ //Read first time chunck
+ read_data_t_chuck(0, m_params.time_chunk_size);
+
+ //Copy common params
+ m_common_params = params;
+}
+
+void
+FromTXYEFileLaserProfile::update (amrex::Real t)
+{
+ if(t >= m_params.t_coords.back())
+ return;
+
+ const auto idx_times = find_left_right_time_indices(t);
+ const auto idx_t_left = idx_times.first;
+ const auto idx_t_right = idx_times.second;
+
+ //Load data chunck if needed
+ if(idx_t_right > m_params.last_time_index){
+ read_data_t_chuck(idx_t_left, idx_t_left+m_params.time_chunk_size);
+ }
+}
+
+void
+FromTXYEFileLaserProfile::fill_amplitude (
+ const int np,
+ Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
+ Real t, Real * AMREX_RESTRICT const amplitude) const
+{
+ //Amplitude is 0 if time is out of range
+ if(t < m_params.t_coords.front() || t > m_params.t_coords.back()){
+ amrex::ParallelFor(np,
+ [=] AMREX_GPU_DEVICE (int i) {
+ amplitude[i] = 0.0_rt;});
+ return;
+ }
+
+ //Find left and right time indices
+ int idx_t_left, idx_t_right;
+ std::tie(idx_t_left, idx_t_right) = find_left_right_time_indices(t);
+
+ if(idx_t_left < m_params.first_time_index){
+ Abort("Something bad has happened with the simulation time");
+ }
+
+ if(m_params.is_grid_uniform){
+ internal_fill_amplitude_uniform(
+ idx_t_left, np, Xp, Yp, t, amplitude);
+ }
+ else{
+ internal_fill_amplitude_nonuniform(
+ idx_t_left, np, Xp, Yp, t, amplitude);
+ }
+}
+
+void
+FromTXYEFileLaserProfile::parse_txye_file(std::string txye_file_name)
+{
+ if(ParallelDescriptor::IOProcessor()){
+ std::ifstream inp(txye_file_name, std::ios::binary);
+ if(!inp) Abort("Failed to open txye file");
+
+ //Uniform grid flag
+ char flag;
+ inp.read(&flag, 1);
+ if(!inp) Abort("Failed to read sizes from txye file");
+ m_params.is_grid_uniform=flag;
+
+ //Grid points along t, x and y
+ auto const three_uint32_size = sizeof(uint32_t)*3;
+ char buf[three_uint32_size];
+ inp.read(buf, three_uint32_size);
+ if(!inp) Abort("Failed to read sizes from txye file");
+ m_params.nt = reinterpret_cast<uint32_t*>(buf)[0];
+ m_params.nx = reinterpret_cast<uint32_t*>(buf)[1];
+ m_params.ny = reinterpret_cast<uint32_t*>(buf)[2];
+ if(m_params.nt <= 1) Abort("nt in txye file must be >=2");
+ if(m_params.nx <= 1) Abort("nx in txye file must be >=2");
+#if (AMREX_SPACEDIM == 3)
+ if(m_params.ny <= 1) Abort("ny in txye file must be >=2 in 3D");
+#elif(AMREX_SPACEDIM == 2)
+ if(m_params.ny != 1) Abort("ny in txye file must be 1 in 2D");
+#endif
+
+ //Coordinates
+ Vector<double> buf_t, buf_x, buf_y;
+ if(m_params.is_grid_uniform){
+ buf_t.resize(2);
+ buf_x.resize(2);
+#if (AMREX_SPACEDIM == 3)
+ buf_y.resize(2);
+#elif(AMREX_SPACEDIM == 2)
+ buf_y.resize(1);
+#endif
+ }
+ else{
+ buf_t.resize(m_params.nt);
+ buf_x.resize(m_params.nx);
+ buf_y.resize(m_params.ny);
+ }
+ inp.read(reinterpret_cast<char*>(buf_t.dataPtr()),
+ buf_t.size()*sizeof(double));
+ if(!inp)
+ Abort("Failed to read coords from txye file");
+ if (!std::is_sorted(buf_t.begin(), buf_t.end()))
+ Abort("Coordinates are not sorted in txye file");
+ inp.read(reinterpret_cast<char*>(buf_x.dataPtr()),
+ buf_x.size()*sizeof(double));
+ if(!inp)
+ Abort("Failed to read coords from txye file");
+ if (!std::is_sorted(buf_x.begin(), buf_x.end()))
+ Abort("Coordinates are not sorted in txye file");
+ inp.read(reinterpret_cast<char*>(buf_y.dataPtr()),
+ buf_y.size()*sizeof(double));
+ if(!inp)
+ Abort("Failed to read coords from txye file");
+ if (!std::is_sorted(buf_y.begin(), buf_y.end()))
+ Abort("Coordinates are not sorted in txye file");
+ m_params.t_coords = Gpu::ManagedVector<amrex::Real>(buf_t.size());
+ m_params.x_coords = Gpu::ManagedVector<amrex::Real>(buf_x.size());
+ m_params.y_coords = Gpu::ManagedVector<amrex::Real>(buf_y.size());
+ // Convert from double to amrex::Real
+ std::transform(buf_t.begin(), buf_t.end(), m_params.t_coords.begin(),
+ [](auto x) {return static_cast<amrex::Real>(x);} );
+ std::transform(buf_x.begin(), buf_x.end(), m_params.x_coords.begin(),
+ [](auto x) {return static_cast<amrex::Real>(x);} );
+ std::transform(buf_y.begin(), buf_y.end(), m_params.y_coords.begin(),
+ [](auto x) {return static_cast<amrex::Real>(x);} );
+ }
+
+ //Broadcast grid uniformity
+ char is_grid_uniform = m_params.is_grid_uniform;
+ ParallelDescriptor::Bcast(&is_grid_uniform, 1,
+ ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Barrier();
+ m_params.is_grid_uniform = is_grid_uniform;
+
+ //Broadcast grid size and coordinate sizes
+ //When a non-uniform grid is used, nt, nx and ny are identical
+ //to t_coords.size(), x_coords.size() and y_coords.size().
+ //When a uniform grid is used, nt,nx and ny store the number of points
+ //used for the mesh, while t_coords, x_coords and y_coords store the
+ //extrems in each direaction. Thus t_coords and x_coords in this case
+ //have size 2 and y_coords has size 1 in 2D and size 2 in 3D.
+ int t_sizes[6] = {m_params.nt, m_params.nx, m_params.ny,
+ static_cast<int>(m_params.t_coords.size()),
+ static_cast<int>(m_params.x_coords.size()),
+ static_cast<int>(m_params.y_coords.size())};
+ ParallelDescriptor::Bcast(t_sizes, 6,
+ ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Barrier();
+ m_params.nt = t_sizes[0]; m_params.nx = t_sizes[1]; m_params.ny = t_sizes[2];
+
+ //Broadcast coordinates
+ if(!ParallelDescriptor::IOProcessor()){
+ m_params.t_coords = Gpu::ManagedVector<amrex::Real>(t_sizes[3]);
+ m_params.x_coords = Gpu::ManagedVector<amrex::Real>(t_sizes[4]);
+ m_params.y_coords = Gpu::ManagedVector<amrex::Real>(t_sizes[5]);
+ }
+ ParallelDescriptor::Bcast(m_params.t_coords.dataPtr(),
+ m_params.t_coords.size(), ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Bcast(m_params.x_coords.dataPtr(),
+ m_params.x_coords.size(), ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Bcast(m_params.y_coords.dataPtr(),
+ m_params.y_coords.size(), ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Barrier();
+}
+
+std::pair<int,int>
+FromTXYEFileLaserProfile::find_left_right_time_indices(amrex::Real t) const
+{
+ int idx_t_right;
+ if(m_params.is_grid_uniform){
+ const auto t_min = m_params.t_coords.front();
+ const auto t_max = m_params.t_coords.back();
+ const auto temp_idx_t_right = static_cast<int>(
+ ceil( (m_params.nt-1)*(t-t_min)/(t_max-t_min)));
+ idx_t_right = max(min(temp_idx_t_right, m_params.nt-1),1);
+ }
+ else{
+ idx_t_right = std::distance(m_params.t_coords.begin(),
+ std::upper_bound(m_params.t_coords.begin(),
+ m_params.t_coords.end(), t));
+ }
+ return std::make_pair(idx_t_right-1, idx_t_right);
+}
+
+void
+FromTXYEFileLaserProfile::read_data_t_chuck(int t_begin, int t_end)
+{
+ amrex::Print() <<
+ "Reading [" << t_begin << ", " << t_end <<
+ ") data chunk from " << m_params.txye_file_name << "\n";
+
+ //Indices of the first and last timestep to read
+ auto i_first = max(0, t_begin);
+ auto i_last = min(t_end-1, m_params.nt-1);
+ if(i_last-i_first+1 > m_params.E_data.size())
+ Abort("Data chunk to read from file is too large");
+
+ if(ParallelDescriptor::IOProcessor()){
+ //Read data chunk
+ std::ifstream inp(m_params.txye_file_name, std::ios::binary);
+ if(!inp) Abort("Failed to open txye file");
+ auto skip_amount = 1 +
+ 3*sizeof(uint32_t) +
+ m_params.t_coords.size()*sizeof(double) +
+ m_params.x_coords.size()*sizeof(double) +
+ m_params.y_coords.size()*sizeof(double) +
+ sizeof(double)*t_begin*m_params.nx*m_params.ny;
+ inp.ignore(skip_amount);
+ if(!inp) Abort("Failed to read field data from txye file");
+ const int read_size = (i_last - i_first + 1)*
+ m_params.nx*m_params.ny;
+ Vector<double> buf_e(read_size);
+ inp.read(reinterpret_cast<char*>(buf_e.dataPtr()), read_size*sizeof(double));
+ if(!inp) Abort("Failed to read field data from txye file");
+ std::transform(buf_e.begin(), buf_e.end(), m_params.E_data.begin(),
+ [](auto x) {return static_cast<amrex::Real>(x);} );
+ }
+
+ //Broadcast E_data
+ ParallelDescriptor::Bcast(m_params.E_data.dataPtr(),
+ m_params.E_data.size(), ParallelDescriptor::IOProcessorNumber());
+ ParallelDescriptor::Barrier();
+
+ //Update first and last indices
+ m_params.first_time_index = i_first;
+ m_params.last_time_index = i_last;
+}
+
+void
+FromTXYEFileLaserProfile::internal_fill_amplitude_uniform(
+ const int idx_t_left,
+ const int np,
+ Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
+ Real t, Real * AMREX_RESTRICT const amplitude) const
+{
+ // Copy member variables to tmp copies
+ // and get pointers to underlying data for GPU.
+ const auto tmp_e_max = m_common_params.e_max;
+ const auto tmp_x_min = m_params.x_coords.front();
+ const auto tmp_x_max = m_params.x_coords.back();
+ const auto tmp_y_min = m_params.y_coords.front();
+ const auto tmp_y_max = m_params.y_coords.back();
+ const auto tmp_nx = m_params.nx;
+#if (AMREX_SPACEDIM == 3)
+ const auto tmp_ny = m_params.ny;
+#endif
+ const auto p_E_data = m_params.E_data.dataPtr();
+ const auto tmp_idx_first_time = m_params.first_time_index;
+ const int idx_t_right = idx_t_left+1;
+ const auto t_left = idx_t_left*
+ (m_params.t_coords.back()-m_params.t_coords.front())/(m_params.nt-1) +
+ m_params.t_coords.front();
+ const auto t_right = idx_t_right*
+ (m_params.t_coords.back()-m_params.t_coords.front())/(m_params.nt-1) +
+ m_params.t_coords.front();
+
+ // Loop through the macroparticle to calculate the proper amplitude
+ amrex::ParallelFor(
+ np,
+ [=] AMREX_GPU_DEVICE (int i) {
+ //Amplitude is zero if we are out of bounds
+ if (Xp[i] <= tmp_x_min || Xp[i] >= tmp_x_max){
+ amplitude[i] = 0.0_rt;
+ return;
+ }
+#if (AMREX_SPACEDIM == 3)
+ if (Yp[i] <= tmp_y_min || Yp[i] >= tmp_y_max){
+ amplitude[i] = 0.0_rt;
+ return;
+ }
+#endif
+ //Find indices and coordinates along x
+ const int temp_idx_x_right = static_cast<int>(
+ ceil((tmp_nx-1)*(Xp[i]- tmp_x_min)/(tmp_x_max-tmp_x_min)));
+ const int idx_x_right =
+ max(min(temp_idx_x_right,tmp_nx-1),static_cast<int>(1));
+ const int idx_x_left = idx_x_right - 1;
+ const auto x_0 =
+ idx_x_left*(tmp_x_max-tmp_x_min)/(tmp_nx-1) + tmp_x_min;
+ const auto x_1 =
+ idx_x_right*(tmp_x_max-tmp_x_min)/(tmp_nx-1) + tmp_x_min;
+
+#if (AMREX_SPACEDIM == 2)
+ //Interpolate amplitude
+ const auto idx = [=](int i, int j){
+ return (i-tmp_idx_first_time) * tmp_nx + j;
+ };
+ amplitude[i] = WarpXUtilAlgo::bilinear_interp(
+ t_left, t_right,
+ x_0, x_1,
+ p_E_data[idx(idx_t_left, idx_x_left)],
+ p_E_data[idx(idx_t_left, idx_x_right)],
+ p_E_data[idx(idx_t_right, idx_x_left)],
+ p_E_data[idx(idx_t_right, idx_x_right)],
+ t, Xp[i])*tmp_e_max;
+
+#elif (AMREX_SPACEDIM == 3)
+ //Find indices and coordinates along y
+ const int temp_idx_y_right = static_cast<int>(
+ ceil((tmp_ny-1)*(Yp[i]- tmp_y_min)/(tmp_y_max-tmp_y_min)));
+ const int idx_y_right =
+ max(min(temp_idx_y_right,tmp_ny-1),static_cast<int>(1));
+ const int idx_y_left = idx_y_right - 1;
+ const auto y_0 =
+ idx_y_left*(tmp_y_max-tmp_y_min)/(tmp_ny-1) + tmp_y_min;
+ const auto y_1 =
+ idx_y_right*(tmp_y_max-tmp_y_min)/(tmp_ny-1) + tmp_y_min;
+
+ //Interpolate amplitude
+ const auto idx = [=](int i, int j, int k){
+ return
+ (i-tmp_idx_first_time)*tmp_nx*tmp_ny+
+ j*tmp_ny + k;
+ };
+ amplitude[i] = WarpXUtilAlgo::trilinear_interp(
+ t_left, t_right,
+ x_0, x_1,
+ y_0, y_1,
+ p_E_data[idx(idx_t_left, idx_x_left, idx_y_left)],
+ p_E_data[idx(idx_t_left, idx_x_left, idx_y_right)],
+ p_E_data[idx(idx_t_left, idx_x_right, idx_y_left)],
+ p_E_data[idx(idx_t_left, idx_x_right, idx_y_right)],
+ p_E_data[idx(idx_t_right, idx_x_left, idx_y_left)],
+ p_E_data[idx(idx_t_right, idx_x_left, idx_y_right)],
+ p_E_data[idx(idx_t_right, idx_x_right, idx_y_left)],
+ p_E_data[idx(idx_t_right, idx_x_right, idx_y_right)],
+ t, Xp[i], Yp[i])*tmp_e_max;
+#endif
+ }
+ );
+}
+
+void
+FromTXYEFileLaserProfile::internal_fill_amplitude_nonuniform(
+ const int idx_t_left,
+ const int np,
+ Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
+ Real t, Real * AMREX_RESTRICT const amplitude) const
+{
+ // Copy member variables to tmp copies
+ // and get pointers to underlying data for GPU.
+ const auto tmp_e_max = m_common_params.e_max;
+ const auto tmp_x_min = m_params.x_coords.front();
+ const auto tmp_x_max = m_params.x_coords.back();
+ const auto tmp_y_min = m_params.y_coords.front();
+ const auto tmp_y_max = m_params.y_coords.back();
+ const auto p_x_coords = m_params.x_coords.dataPtr();
+ const int tmp_x_coords_size = static_cast<int>(m_params.x_coords.size());
+ const auto p_y_coords = m_params.y_coords.dataPtr();
+ const int tmp_y_coords_size = static_cast<int>(m_params.y_coords.size());
+ const auto p_E_data = m_params.E_data.dataPtr();
+ const auto tmp_idx_first_time = m_params.first_time_index;
+ const int idx_t_right = idx_t_left+1;
+ const auto t_left = m_params.t_coords[idx_t_left];
+ const auto t_right = m_params.t_coords[idx_t_right];
+
+ // Loop through the macroparticle to calculate the proper amplitude
+ amrex::ParallelFor(
+ np,
+ [=] AMREX_GPU_DEVICE (int i) {
+ //Amplitude is zero if we are out of bounds
+ if (Xp[i] <= tmp_x_min || Xp[i] >= tmp_x_max){
+ amplitude[i] = 0.0_rt;
+ return;
+ }
+#if (AMREX_SPACEDIM == 3)
+ if (Yp[i] <= tmp_y_min || Yp[i] >= tmp_y_max){
+ amplitude[i] = 0.0_rt;
+ return;
+ }
+#endif
+
+ //Find indices along x
+ auto const p_x_right = WarpXUtilAlgo::upper_bound(
+ p_x_coords, p_x_coords+tmp_x_coords_size, Xp[i]);
+ const int idx_x_right = p_x_right - p_x_coords;
+ const int idx_x_left = idx_x_right - 1;
+
+#if (AMREX_SPACEDIM == 2)
+ //Interpolate amplitude
+ const auto idx = [=](int i, int j){
+ return (i-tmp_idx_first_time) * tmp_x_coords_size + j;
+ };
+ amplitude[i] = WarpXUtilAlgo::bilinear_interp(
+ t_left, t_right,
+ p_x_coords[idx_x_left], p_x_coords[idx_x_right],
+ p_E_data[idx(idx_t_left, idx_x_left)],
+ p_E_data[idx(idx_t_left, idx_x_right)],
+ p_E_data[idx(idx_t_right, idx_x_left)],
+ p_E_data[idx(idx_t_right, idx_x_right)],
+ t, Xp[i])*tmp_e_max;
+
+#elif (AMREX_SPACEDIM == 3)
+ //Find indices along y
+ auto const p_y_right = WarpXUtilAlgo::upper_bound(
+ p_y_coords, p_y_coords+tmp_y_coords_size, Yp[i]);
+ const int idx_y_right = p_y_right - p_y_coords;
+ const int idx_y_left = idx_y_right - 1;
+
+ //Interpolate amplitude
+ const auto idx = [=](int i, int j, int k){
+ return
+ (i-tmp_idx_first_time)*tmp_x_coords_size*tmp_y_coords_size+
+ j*tmp_y_coords_size + k;
+ };
+ amplitude[i] = WarpXUtilAlgo::trilinear_interp(
+ t_left, t_right,
+ p_x_coords[idx_x_left], p_x_coords[idx_x_right],
+ p_y_coords[idx_y_left], p_y_coords[idx_y_right],
+ p_E_data[idx(idx_t_left, idx_x_left, idx_y_left)],
+ p_E_data[idx(idx_t_left, idx_x_left, idx_y_right)],
+ p_E_data[idx(idx_t_left, idx_x_right, idx_y_left)],
+ p_E_data[idx(idx_t_left, idx_x_right, idx_y_right)],
+ p_E_data[idx(idx_t_right, idx_x_left, idx_y_left)],
+ p_E_data[idx(idx_t_right, idx_x_left, idx_y_right)],
+ p_E_data[idx(idx_t_right, idx_x_right, idx_y_left)],
+ p_E_data[idx(idx_t_right, idx_x_right, idx_y_right)],
+ t, Xp[i], Yp[i])*tmp_e_max;
+#endif
+ }
+ );
+}
diff --git a/Source/Laser/LaserProfilesImpl/LaserProfileGaussian.cpp b/Source/Laser/LaserProfilesImpl/LaserProfileGaussian.cpp
index a0b5dd855..31e64eca5 100644
--- a/Source/Laser/LaserProfilesImpl/LaserProfileGaussian.cpp
+++ b/Source/Laser/LaserProfilesImpl/LaserProfileGaussian.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Luca Fedeli, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <LaserProfiles.H>
#include <WarpX_Complex.H>
@@ -72,7 +79,7 @@ GaussianLaserProfile::init (
void
GaussianLaserProfile::fill_amplitude (
const int np, Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
- Real t, Real * AMREX_RESTRICT const amplitude)
+ Real t, Real * AMREX_RESTRICT const amplitude) const
{
Complex I(0,1);
// Calculate a few factors which are independent of the macroparticle
diff --git a/Source/Laser/LaserProfilesImpl/LaserProfileHarris.cpp b/Source/Laser/LaserProfilesImpl/LaserProfileHarris.cpp
index 55374c5ea..de4879939 100644
--- a/Source/Laser/LaserProfilesImpl/LaserProfileHarris.cpp
+++ b/Source/Laser/LaserProfilesImpl/LaserProfileHarris.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <LaserProfiles.H>
#include <WarpX_Complex.H>
@@ -35,7 +41,7 @@ HarrisLaserProfile::init (
void
HarrisLaserProfile::fill_amplitude (
const int np, Real const * AMREX_RESTRICT const Xp, Real const * AMREX_RESTRICT const Yp,
- Real t, Real * AMREX_RESTRICT const amplitude)
+ Real t, Real * AMREX_RESTRICT const amplitude) const
{
// This function uses the Harris function as the temporal profile of the pulse
const Real omega0 =
diff --git a/Source/Laser/LaserProfilesImpl/Make.package b/Source/Laser/LaserProfilesImpl/Make.package
index 32284c4e4..2fef27b9f 100644
--- a/Source/Laser/LaserProfilesImpl/Make.package
+++ b/Source/Laser/LaserProfilesImpl/Make.package
@@ -1,6 +1,7 @@
CEXE_sources += LaserProfileGaussian.cpp
CEXE_sources += LaserProfileHarris.cpp
CEXE_sources += LaserProfileFieldFunction.cpp
+CEXE_sources += LaserProfileFromTXYEFile.cpp
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Laser/LaserProfilesImpl
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Laser/LaserProfilesImpl
diff --git a/Source/Parallelization/GuardCellManager.H b/Source/Parallelization/GuardCellManager.H
new file mode 100644
index 000000000..ef7738178
--- /dev/null
+++ b/Source/Parallelization/GuardCellManager.H
@@ -0,0 +1,82 @@
+/* Copyright 2019-2020 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#ifndef GUARDCELLMANAGER_H_
+#define GUARDCELLMANAGER_H_
+
+#include <AMReX_IntVect.H>
+
+/**
+ * \brief This class computes and stores the number of guard cells needed for
+ * the allocation of the MultiFabs and required for each part of the PIC loop.
+ */
+class guardCellManager{
+
+public:
+
+ /**
+ * \brief Initialize number of guard cells depending on the options used.
+ *
+ * \param do_subcycling bool, whether to use subcycling
+ * \param do_fdtd_nci_corr bool, whether to use Godfrey NCI corrector
+ * \param do_nodal bool, whether the field solver is nodal
+ * \param do_moving_window bool, whether to use moving window
+ * \param do_fft_mpi_dec bool, whether to do parallel FFTs for PSATD
+ * \param aux_is_nodal bool, true if the aux grid is nodal
+ * \param moving_window_dir direction of moving window
+ * \param nox order of current deposition
+ * \param nox_fft order of PSATD in x direction
+ * \param noy_fft order of PSATD in y direction
+ * \param noz_fft order of PSATD in z direction
+ * \param nci_corr_stencil stencil of NCI corrector
+ * \param maxwell_fdtd_solver_id if of Maxwell solver
+ * \param max_level max level of the simulation
+ */
+ void Init(
+ const bool do_subcycling,
+ const bool do_fdtd_nci_corr,
+ const bool do_nodal,
+ const bool do_moving_window,
+ const bool do_fft_mpi_dec,
+ const bool aux_is_nodal,
+ const int moving_window_dir,
+ const int nox,
+ const int nox_fft, const int noy_fft, const int noz_fft,
+ const int nci_corr_stencil,
+ const int maxwell_fdtd_solver_id,
+ const int max_level,
+ const bool exchange_all_guard_cells);
+
+ // Guard cells allocated for MultiFabs E and B
+ amrex::IntVect ng_alloc_EB = amrex::IntVect::TheZeroVector();
+ // Guard cells allocated for MultiFab J
+ amrex::IntVect ng_alloc_J = amrex::IntVect::TheZeroVector();
+ // Guard cells allocated for MultiFab Rho
+ amrex::IntVect ng_alloc_Rho = amrex::IntVect::TheZeroVector();
+ // Guard cells allocated for MultiFab F
+ amrex::IntVect ng_alloc_F = amrex::IntVect::TheZeroVector();
+
+ // Guard cells exchanged for specific parts of the PIC loop
+
+ // Number of guard cells of E and B that must exchanged before Field Solver
+ amrex::IntVect ng_FieldSolver = amrex::IntVect::TheZeroVector();
+ // Number of guard cells of F that must exchanged before Field Solver
+ amrex::IntVect ng_FieldSolverF = amrex::IntVect::TheZeroVector();
+ // Number of guard cells of E and B that must exchanged before Field Gather
+ amrex::IntVect ng_FieldGather = amrex::IntVect::TheZeroVector();
+ // Number of guard cells of E and B that must exchanged before updating the Aux grid
+ amrex::IntVect ng_UpdateAux = amrex::IntVect::TheZeroVector();
+ // Number of guard cells of all MultiFabs that must exchanged before moving window
+ amrex::IntVect ng_MovingWindow = amrex::IntVect::TheZeroVector();
+
+ // When the auxiliary grid is nodal but the field solver is staggered
+ // (typically with momentum-conserving gather with FDTD Yee solver),
+ // An extra guard cell is needed on the fine grid to do the interpolation
+ // for E and B.
+ amrex::IntVect ng_Extra = amrex::IntVect::TheZeroVector();
+};
+
+#endif // GUARDCELLMANAGER_H_
diff --git a/Source/Parallelization/GuardCellManager.cpp b/Source/Parallelization/GuardCellManager.cpp
new file mode 100644
index 000000000..d845a7447
--- /dev/null
+++ b/Source/Parallelization/GuardCellManager.cpp
@@ -0,0 +1,177 @@
+/* Copyright 2019-2020 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#include "GuardCellManager.H"
+#include "NCIGodfreyFilter.H"
+#include <AMReX_Print.H>
+
+using namespace amrex;
+
+void
+guardCellManager::Init(
+ const bool do_subcycling,
+ const bool do_fdtd_nci_corr,
+ const bool do_nodal,
+ const bool do_moving_window,
+ const bool do_fft_mpi_dec,
+ const bool aux_is_nodal,
+ const int moving_window_dir,
+ const int nox,
+ const int nox_fft, const int noy_fft, const int noz_fft,
+ const int nci_corr_stencil,
+ const int maxwell_fdtd_solver_id,
+ const int max_level,
+ const bool exchange_all_guard_cells)
+{
+ // When using subcycling, the particles on the fine level perform two pushes
+ // before being redistributed ; therefore, we need one extra guard cell
+ // (the particles may move by 2*c*dt)
+ const int ngx_tmp = (max_level > 0 && do_subcycling == 1) ? nox+1 : nox;
+ const int ngy_tmp = (max_level > 0 && do_subcycling == 1) ? nox+1 : nox;
+ const int ngz_tmp = (max_level > 0 && do_subcycling == 1) ? nox+1 : nox;
+
+ // Ex, Ey, Ez, Bx, By, and Bz have the same number of ghost cells.
+ // jx, jy, jz and rho have the same number of ghost cells.
+ // E and B have the same number of ghost cells as j and rho if NCI filter is not used,
+ // but different number of ghost cells in z-direction if NCI filter is used.
+ // The number of cells should be even, in order to easily perform the
+ // interpolation from coarse grid to fine grid.
+ int ngx = (ngx_tmp % 2) ? ngx_tmp+1 : ngx_tmp; // Always even number
+ int ngy = (ngy_tmp % 2) ? ngy_tmp+1 : ngy_tmp; // Always even number
+ int ngz_nonci = (ngz_tmp % 2) ? ngz_tmp+1 : ngz_tmp; // Always even number
+ int ngz;
+ if (do_fdtd_nci_corr) {
+ int ng = ngz_tmp + nci_corr_stencil;
+ ngz = (ng % 2) ? ng+1 : ng;
+ } else {
+ ngz = ngz_nonci;
+ }
+
+ // J is only interpolated from fine to coarse (not coarse to fine)
+ // and therefore does not need to be even.
+ int ngJx = ngx_tmp;
+ int ngJy = ngy_tmp;
+ int ngJz = ngz_tmp;
+
+ // When calling the moving window (with one level of refinement), we shift
+ // the fine grid by 2 cells ; therefore, we need at least 2 guard cells
+ // on level 1. This may not be necessary for level 0.
+ if (do_moving_window) {
+ ngx = std::max(ngx,2);
+ ngy = std::max(ngy,2);
+ ngz = std::max(ngz,2);
+ ngJx = std::max(ngJx,2);
+ ngJy = std::max(ngJy,2);
+ ngJz = std::max(ngJz,2);
+ }
+
+#if (AMREX_SPACEDIM == 3)
+ ng_alloc_EB = IntVect(ngx,ngy,ngz);
+ ng_alloc_J = IntVect(ngJx,ngJy,ngJz);
+#elif (AMREX_SPACEDIM == 2)
+ ng_alloc_EB = IntVect(ngx,ngz);
+ ng_alloc_J = IntVect(ngJx,ngJz);
+#endif
+
+ ng_alloc_Rho = ng_alloc_J+1; //One extra ghost cell, so that it's safe to deposit charge density
+ // after pushing particle.
+ int ng_alloc_F_int = (do_moving_window) ? 2 : 0;
+ // CKC solver requires one additional guard cell
+ if (maxwell_fdtd_solver_id == 1) ng_alloc_F_int = std::max( ng_alloc_F_int, 1 );
+ ng_alloc_F = IntVect(AMREX_D_DECL(ng_alloc_F_int, ng_alloc_F_int, ng_alloc_F_int));
+
+#ifdef WARPX_USE_PSATD
+ if (do_fft_mpi_dec == false){
+ // All boxes should have the same number of guard cells
+ // (to avoid temporary parallel copies)
+ // Thus take the max of the required number of guards for each field
+ // Also: the number of guard cell should be enough to contain
+ // the stencil of the FFT solver. Here, this number (`ngFFT`)
+ // is determined *empirically* to be the order of the solver
+ // for nodal, and half the order of the solver for staggered.
+ IntVect ngFFT;
+ if (do_nodal) {
+ ngFFT = IntVect(AMREX_D_DECL(nox_fft, noy_fft, noz_fft));
+ } else {
+ ngFFT = IntVect(AMREX_D_DECL(nox_fft/2, noy_fft/2, noz_fft/2));
+ }
+ for (int i_dim=0; i_dim<AMREX_SPACEDIM; i_dim++ ){
+ int ng_required = ngFFT[i_dim];
+ // Get the max
+ ng_required = std::max( ng_required, ng_alloc_EB[i_dim] );
+ ng_required = std::max( ng_required, ng_alloc_J[i_dim] );
+ ng_required = std::max( ng_required, ng_alloc_Rho[i_dim] );
+ ng_required = std::max( ng_required, ng_alloc_F[i_dim] );
+ // Set the guard cells to this max
+ ng_alloc_EB[i_dim] = ng_required;
+ ng_alloc_J[i_dim] = ng_required;
+ ng_alloc_F[i_dim] = ng_required;
+ ng_alloc_Rho[i_dim] = ng_required;
+ ng_alloc_F_int = ng_required;
+ }
+ }
+ ng_alloc_F = IntVect(AMREX_D_DECL(ng_alloc_F_int, ng_alloc_F_int, ng_alloc_F_int));
+#endif
+
+ ng_Extra = IntVect(static_cast<int>(aux_is_nodal and !do_nodal));
+
+ // Compute number of cells required for Field Solver
+#ifdef WARPX_USE_PSATD
+ ng_FieldSolver = ng_alloc_EB;
+ ng_FieldSolverF = ng_alloc_EB;
+#else
+ ng_FieldSolver = IntVect(AMREX_D_DECL(1,1,1));
+ ng_FieldSolverF = IntVect(AMREX_D_DECL(1,1,1));
+#endif
+
+ if (exchange_all_guard_cells){
+ // Run in safe mode: exchange all allocated guard cells at each
+ // call of FillBoundary
+ ng_FieldSolver = ng_alloc_EB;
+ ng_FieldSolverF = ng_alloc_F;
+ ng_FieldGather = ng_alloc_EB;
+ ng_UpdateAux = ng_alloc_EB;
+ if (do_moving_window){
+ ng_MovingWindow = ng_alloc_EB;
+ }
+ } else {
+
+ ng_FieldSolver = ng_FieldSolver.min(ng_alloc_EB);
+
+ // Compute number of cells required for Field Gather
+ int FGcell[4] = {0,1,1,2}; // Index is nox
+ IntVect ng_FieldGather_noNCI = IntVect(AMREX_D_DECL(FGcell[nox],FGcell[nox],FGcell[nox]));
+ // Add one cell if momentum_conserving gather in a staggered-field simulation
+ ng_FieldGather_noNCI += ng_Extra;
+ // Not sure why, but need one extra guard cell when using MR
+ if (max_level >= 1) ng_FieldGather_noNCI += ng_Extra;
+ ng_FieldGather_noNCI = ng_FieldGather_noNCI.min(ng_alloc_EB);
+ // If NCI filter, add guard cells in the z direction
+ IntVect ng_NCIFilter = IntVect::TheZeroVector();
+ if (do_fdtd_nci_corr)
+ ng_NCIFilter[AMREX_SPACEDIM-1] = NCIGodfreyFilter::m_stencil_width;
+ // Note: communications of guard cells for bilinear filter are handled
+ // separately.
+ ng_FieldGather = ng_FieldGather_noNCI + ng_NCIFilter;
+
+ // Guard cells for auxiliary grid.
+ // Not sure why there is a 2* here...
+ ng_UpdateAux = 2*ng_FieldGather_noNCI + ng_NCIFilter;
+
+ // Make sure we do not exchange more guard cells than allocated.
+ ng_FieldGather = ng_FieldGather.min(ng_alloc_EB);
+ ng_UpdateAux = ng_UpdateAux.min(ng_alloc_EB);
+ ng_FieldSolverF = ng_FieldSolverF.min(ng_alloc_F);
+ // Only FillBoundary(ng_FieldGather) is called between consecutive
+ // field solves. So ng_FieldGather must have enough cells
+ // for the field solve too.
+ ng_FieldGather = ng_FieldGather.max(ng_FieldSolver);
+
+ if (do_moving_window){
+ ng_MovingWindow[moving_window_dir] = 1;
+ }
+ }
+}
diff --git a/Source/Parallelization/InterpolateCurrentFineToCoarse.H b/Source/Parallelization/InterpolateCurrentFineToCoarse.H
index cbbcdfab5..43cda26df 100644
--- a/Source/Parallelization/InterpolateCurrentFineToCoarse.H
+++ b/Source/Parallelization/InterpolateCurrentFineToCoarse.H
@@ -1,4 +1,4 @@
-/* Copyright 2019 Axel Huebl, Weiqun Zhang
+/* Copyright 2019-2020 Axel Huebl
*
* This file is part of WarpX.
*
@@ -63,9 +63,9 @@ public:
// return zero for out-of-bounds accesses during interpolation
// this is efficiently used as a method to add neutral elements beyond guards in the average below
- auto const fine = [fine_unsafe] AMREX_GPU_DEVICE (int const j, int const k, int const l) noexcept
+ auto const fine = [fine_unsafe] AMREX_GPU_DEVICE (int const jj, int const kk, int const ll) noexcept
{
- return fine_unsafe.contains(j, k, l) ? fine_unsafe(j, k, l) : amrex::Real{0.};
+ return fine_unsafe.contains(jj, kk, ll) ? fine_unsafe(jj, kk, ll) : amrex::Real{0.};
};
int const ii = i * m_refinement_ratio;
diff --git a/Source/Parallelization/InterpolateDensityFineToCoarse.H b/Source/Parallelization/InterpolateDensityFineToCoarse.H
index 947db2aac..5d679583a 100644
--- a/Source/Parallelization/InterpolateDensityFineToCoarse.H
+++ b/Source/Parallelization/InterpolateDensityFineToCoarse.H
@@ -1,4 +1,4 @@
-/* Copyright 2019 Axel Huebl, Weiqun Zhang
+/* Copyright 2019 Axel Huebl
*
* This file is part of WarpX.
*
diff --git a/Source/Parallelization/Make.package b/Source/Parallelization/Make.package
index 7c3c38627..065556b33 100644
--- a/Source/Parallelization/Make.package
+++ b/Source/Parallelization/Make.package
@@ -1,7 +1,9 @@
CEXE_sources += WarpXComm.cpp
CEXE_sources += WarpXRegrid.cpp
+CEXE_sources += GuardCellManager.cpp
CEXE_headers += WarpXSumGuardCells.H
CEXE_headers += WarpXComm_K.H
+CEXE_headers += GuardCellManager.H
CEXE_headers += WarpXComm.H
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Parallelization
diff --git a/Source/Parallelization/WarpXComm.H b/Source/Parallelization/WarpXComm.H
index 81f00088e..7352e797e 100644
--- a/Source/Parallelization/WarpXComm.H
+++ b/Source/Parallelization/WarpXComm.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARALLELIZATION_COMM_H_
#define WARPX_PARALLELIZATION_COMM_H_
diff --git a/Source/Parallelization/WarpXComm.cpp b/Source/Parallelization/WarpXComm.cpp
index b61ae4fc7..31bb802f7 100644
--- a/Source/Parallelization/WarpXComm.cpp
+++ b/Source/Parallelization/WarpXComm.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Aurore Blelly, Axel Huebl
+ * David Grote, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpXComm.H>
#include <WarpXComm_K.H>
#include <WarpX.H>
@@ -321,41 +329,41 @@ WarpX::UpdateAuxilaryDataSameType ()
}
void
-WarpX::FillBoundaryB ()
+WarpX::FillBoundaryB (IntVect ng, IntVect ng_extra_fine)
{
for (int lev = 0; lev <= finest_level; ++lev)
{
- FillBoundaryB(lev);
+ FillBoundaryB(lev, ng, ng_extra_fine);
}
}
void
-WarpX::FillBoundaryE ()
+WarpX::FillBoundaryE (IntVect ng, IntVect ng_extra_fine)
{
for (int lev = 0; lev <= finest_level; ++lev)
{
- FillBoundaryE(lev);
+ FillBoundaryE(lev, ng, ng_extra_fine);
}
}
void
-WarpX::FillBoundaryF ()
+WarpX::FillBoundaryF (IntVect ng)
{
for (int lev = 0; lev <= finest_level; ++lev)
{
- FillBoundaryF(lev);
+ FillBoundaryF(lev, ng);
}
}
void
-WarpX::FillBoundaryE(int lev)
+WarpX::FillBoundaryE(int lev, IntVect ng, IntVect ng_extra_fine)
{
- FillBoundaryE(lev, PatchType::fine);
- if (lev > 0) FillBoundaryE(lev, PatchType::coarse);
+ FillBoundaryE(lev, PatchType::fine, ng+ng_extra_fine);
+ if (lev > 0) FillBoundaryE(lev, PatchType::coarse, ng);
}
void
-WarpX::FillBoundaryE (int lev, PatchType patch_type)
+WarpX::FillBoundaryE (int lev, PatchType patch_type, IntVect ng)
{
if (patch_type == PatchType::fine)
{
@@ -370,8 +378,12 @@ WarpX::FillBoundaryE (int lev, PatchType patch_type)
}
const auto& period = Geom(lev).periodicity();
- Vector<MultiFab*> mf{Efield_fp[lev][0].get(),Efield_fp[lev][1].get(),Efield_fp[lev][2].get()};
- amrex::FillBoundary(mf, period);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= Efield_fp[lev][0]->nGrowVect(),
+ "Error: in FillBoundaryE, requested more guard cells than allocated");
+ Efield_fp[lev][0]->FillBoundary(ng, period);
+ Efield_fp[lev][1]->FillBoundary(ng, period);
+ Efield_fp[lev][2]->FillBoundary(ng, period);
}
else if (patch_type == PatchType::coarse)
{
@@ -386,20 +398,24 @@ WarpX::FillBoundaryE (int lev, PatchType patch_type)
}
const auto& cperiod = Geom(lev-1).periodicity();
- Vector<MultiFab*> mf{Efield_cp[lev][0].get(),Efield_cp[lev][1].get(),Efield_cp[lev][2].get()};
- amrex::FillBoundary(mf, cperiod);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= Efield_cp[lev][0]->nGrowVect(),
+ "Error: in FillBoundaryE, requested more guard cells than allocated");
+ Efield_cp[lev][0]->FillBoundary(ng, cperiod);
+ Efield_cp[lev][1]->FillBoundary(ng, cperiod);
+ Efield_cp[lev][2]->FillBoundary(ng, cperiod);
}
}
void
-WarpX::FillBoundaryB (int lev)
+WarpX::FillBoundaryB (int lev, IntVect ng, IntVect ng_extra_fine)
{
- FillBoundaryB(lev, PatchType::fine);
- if (lev > 0) FillBoundaryB(lev, PatchType::coarse);
+ FillBoundaryB(lev, PatchType::fine, ng + ng_extra_fine);
+ if (lev > 0) FillBoundaryB(lev, PatchType::coarse, ng);
}
void
-WarpX::FillBoundaryB (int lev, PatchType patch_type)
+WarpX::FillBoundaryB (int lev, PatchType patch_type, IntVect ng)
{
if (patch_type == PatchType::fine)
{
@@ -413,8 +429,12 @@ WarpX::FillBoundaryB (int lev, PatchType patch_type)
pml[lev]->FillBoundaryB(patch_type);
}
const auto& period = Geom(lev).periodicity();
- Vector<MultiFab*> mf{Bfield_fp[lev][0].get(),Bfield_fp[lev][1].get(),Bfield_fp[lev][2].get()};
- amrex::FillBoundary(mf, period);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= Bfield_fp[lev][0]->nGrowVect(),
+ "Error: in FillBoundaryB, requested more guard cells than allocated");
+ Bfield_fp[lev][0]->FillBoundary(ng, period);
+ Bfield_fp[lev][1]->FillBoundary(ng, period);
+ Bfield_fp[lev][2]->FillBoundary(ng, period);
}
else if (patch_type == PatchType::coarse)
{
@@ -428,20 +448,24 @@ WarpX::FillBoundaryB (int lev, PatchType patch_type)
pml[lev]->FillBoundaryB(patch_type);
}
const auto& cperiod = Geom(lev-1).periodicity();
- Vector<MultiFab*> mf{Bfield_cp[lev][0].get(),Bfield_cp[lev][1].get(),Bfield_cp[lev][2].get()};
- amrex::FillBoundary(mf, cperiod);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= Bfield_cp[lev][0]->nGrowVect(),
+ "Error: in FillBoundaryB, requested more guard cells than allocated");
+ Bfield_cp[lev][0]->FillBoundary(ng, cperiod);
+ Bfield_cp[lev][1]->FillBoundary(ng, cperiod);
+ Bfield_cp[lev][2]->FillBoundary(ng, cperiod);
}
}
void
-WarpX::FillBoundaryF (int lev)
+WarpX::FillBoundaryF (int lev, IntVect ng)
{
- FillBoundaryF(lev, PatchType::fine);
- if (lev > 0) FillBoundaryF(lev, PatchType::coarse);
+ FillBoundaryF(lev, PatchType::fine, ng);
+ if (lev > 0) FillBoundaryF(lev, PatchType::coarse, ng);
}
void
-WarpX::FillBoundaryF (int lev, PatchType patch_type)
+WarpX::FillBoundaryF (int lev, PatchType patch_type, IntVect ng)
{
if (patch_type == PatchType::fine && F_fp[lev])
{
@@ -453,7 +477,10 @@ WarpX::FillBoundaryF (int lev, PatchType patch_type)
}
const auto& period = Geom(lev).periodicity();
- F_fp[lev]->FillBoundary(period);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= F_fp[lev]->nGrowVect(),
+ "Error: in FillBoundaryF, requested more guard cells than allocated");
+ F_fp[lev]->FillBoundary(ng, period);
}
else if (patch_type == PatchType::coarse && F_cp[lev])
{
@@ -465,11 +492,35 @@ WarpX::FillBoundaryF (int lev, PatchType patch_type)
}
const auto& cperiod = Geom(lev-1).periodicity();
- F_cp[lev]->FillBoundary(cperiod);
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ ng <= F_cp[lev]->nGrowVect(),
+ "Error: in FillBoundaryF, requested more guard cells than allocated");
+ F_cp[lev]->FillBoundary(ng, cperiod);
}
}
void
+WarpX::FillBoundaryAux (IntVect ng)
+{
+ for (int lev = 0; lev <= finest_level-1; ++lev)
+ {
+ FillBoundaryAux(lev, ng);
+ }
+}
+
+void
+WarpX::FillBoundaryAux (int lev, IntVect ng)
+{
+ const auto& period = Geom(lev).periodicity();
+ Efield_aux[lev][0]->FillBoundary(ng, period);
+ Efield_aux[lev][1]->FillBoundary(ng, period);
+ Efield_aux[lev][2]->FillBoundary(ng, period);
+ Bfield_aux[lev][0]->FillBoundary(ng, period);
+ Bfield_aux[lev][1]->FillBoundary(ng, period);
+ Bfield_aux[lev][2]->FillBoundary(ng, period);
+}
+
+void
WarpX::SyncCurrent ()
{
BL_PROFILE("SyncCurrent()");
diff --git a/Source/Parallelization/WarpXComm_K.H b/Source/Parallelization/WarpXComm_K.H
index 169cd0ee1..1b6eceb93 100644
--- a/Source/Parallelization/WarpXComm_K.H
+++ b/Source/Parallelization/WarpXComm_K.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_COMM_K_H_
#define WARPX_COMM_K_H_
diff --git a/Source/Parallelization/WarpXRegrid.cpp b/Source/Parallelization/WarpXRegrid.cpp
index 29ccc8f4d..54166e8ce 100644
--- a/Source/Parallelization/WarpXRegrid.cpp
+++ b/Source/Parallelization/WarpXRegrid.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Ann Almgren, Axel Huebl
+ * David Grote, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang, levinem
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <AMReX_BLProfiler.H>
diff --git a/Source/Parallelization/WarpXSumGuardCells.H b/Source/Parallelization/WarpXSumGuardCells.H
index 36eb4ed6c..972c1cd2d 100644
--- a/Source/Parallelization/WarpXSumGuardCells.H
+++ b/Source/Parallelization/WarpXSumGuardCells.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Maxence Thevenet, Remi Lehe, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_SUM_GUARD_CELLS_H_
#define WARPX_SUM_GUARD_CELLS_H_
diff --git a/Source/Parser/GpuParser.H b/Source/Parser/GpuParser.H
index c158ee314..c6d870800 100644
--- a/Source/Parser/GpuParser.H
+++ b/Source/Parser/GpuParser.H
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Maxence Thevenet, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_GPU_PARSER_H_
#define WARPX_GPU_PARSER_H_
@@ -17,7 +24,7 @@ public:
AMREX_GPU_HOST_DEVICE
amrex::Real
- operator() (amrex::Real x, amrex::Real y, amrex::Real z) const noexcept
+ operator() (amrex::Real x, amrex::Real y, amrex::Real z, amrex::Real t=0.0) const noexcept
{
#ifdef AMREX_USE_GPU
@@ -27,15 +34,17 @@ public:
amrex::Gpu::SharedMemory<amrex::Real> gsm;
amrex::Real* p = gsm.dataPtr();
int tid = threadIdx.x + threadIdx.y*blockDim.x + threadIdx.z*(blockDim.x*blockDim.y);
- p[tid*3] = x;
- p[tid*3+1] = y;
- p[tid*3+2] = z;
+ p[tid*4] = x;
+ p[tid*4+1] = y;
+ p[tid*4+2] = z;
+ p[tid*4+3] = t;
return wp_ast_eval(m_gpu_parser.ast);
#else
// WarpX compiled for GPU, function compiled for __host__
m_var.x = x;
m_var.y = y;
m_var.z = z;
+ m_t = t;
return wp_ast_eval(m_cpu_parser.ast);
#endif
@@ -49,10 +58,12 @@ public:
m_var[tid].x = x;
m_var[tid].y = y;
m_var[tid].z = z;
+ m_t[tid] = t;
return wp_ast_eval(m_parser[tid]->ast);
#endif
}
+
private:
#ifdef AMREX_USE_GPU
@@ -61,10 +72,12 @@ private:
// Copy of the parser running on __host__
struct wp_parser m_cpu_parser;
mutable amrex::XDim3 m_var;
+ mutable amrex::Real m_t;
#else
// Only one parser
struct wp_parser** m_parser;
mutable amrex::XDim3* m_var;
+ mutable amrex::Real* m_t;
int nthreads;
#endif
};
diff --git a/Source/Parser/GpuParser.cpp b/Source/Parser/GpuParser.cpp
index 5078b498b..22fab6313 100644
--- a/Source/Parser/GpuParser.cpp
+++ b/Source/Parser/GpuParser.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019-2020 Maxence Thevenet, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <GpuParser.H>
GpuParser::GpuParser (WarpXParser const& wp)
@@ -16,6 +23,7 @@ GpuParser::GpuParser (WarpXParser const& wp)
wp_parser_regvar_gpu(&m_gpu_parser, "x", 0);
wp_parser_regvar_gpu(&m_gpu_parser, "y", 1);
wp_parser_regvar_gpu(&m_gpu_parser, "z", 2);
+ wp_parser_regvar_gpu(&m_gpu_parser, "t", 3);
// Initialize CPU parser: allocate memory in CUDA managed memory,
// copy all data needed on CPU to m_cpu_parser
@@ -28,6 +36,7 @@ GpuParser::GpuParser (WarpXParser const& wp)
wp_parser_regvar(&m_cpu_parser, "x", &(m_var.x));
wp_parser_regvar(&m_cpu_parser, "y", &(m_var.y));
wp_parser_regvar(&m_cpu_parser, "z", &(m_var.z));
+ wp_parser_regvar(&m_cpu_parser, "t", &(m_t));
#else // not defined AMREX_USE_GPU
@@ -39,6 +48,7 @@ GpuParser::GpuParser (WarpXParser const& wp)
m_parser = ::new struct wp_parser*[nthreads];
m_var = ::new amrex::XDim3[nthreads];
+ m_t = ::new amrex::Real[nthreads];
for (int tid = 0; tid < nthreads; ++tid)
{
@@ -50,6 +60,7 @@ GpuParser::GpuParser (WarpXParser const& wp)
wp_parser_regvar(m_parser[tid], "x", &(m_var[tid].x));
wp_parser_regvar(m_parser[tid], "y", &(m_var[tid].y));
wp_parser_regvar(m_parser[tid], "z", &(m_var[tid].z));
+ wp_parser_regvar(m_parser[tid], "t", &(m_t[tid]));
}
#endif // AMREX_USE_GPU
diff --git a/Source/Parser/Make.package b/Source/Parser/Make.package
index 5ce02cbda..15115c138 100644
--- a/Source/Parser/Make.package
+++ b/Source/Parser/Make.package
@@ -5,6 +5,7 @@ CEXE_sources += WarpXParser.cpp
CEXE_headers += WarpXParser.H
CEXE_headers += GpuParser.H
CEXE_sources += GpuParser.cpp
+CEXE_headers += WarpXParserWrapper.H
INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Parser
VPATH_LOCATIONS += $(WARPX_HOME)/Source/Parser
diff --git a/Source/Parser/WarpXParser.H b/Source/Parser/WarpXParser.H
index 8c1d854d8..863b35fb8 100644
--- a/Source/Parser/WarpXParser.H
+++ b/Source/Parser/WarpXParser.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARSER_H_
#define WARPX_PARSER_H_
diff --git a/Source/Parser/WarpXParser.cpp b/Source/Parser/WarpXParser.cpp
index ced536327..8c8be7ecb 100644
--- a/Source/Parser/WarpXParser.cpp
+++ b/Source/Parser/WarpXParser.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <algorithm>
#include "WarpXParser.H"
diff --git a/Source/Parser/WarpXParserWrapper.H b/Source/Parser/WarpXParserWrapper.H
new file mode 100644
index 000000000..2c76d97a3
--- /dev/null
+++ b/Source/Parser/WarpXParserWrapper.H
@@ -0,0 +1,41 @@
+/* Copyright 2020 Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#ifndef WARPX_PARSER_WRAPPER_H_
+#define WARPX_PARSER_WRAPPER_H_
+
+#include <WarpXParser.H>
+#include <AMReX_Gpu.H>
+#include <GpuParser.H>
+/**
+ * \brief
+ * The ParserWrapper struct is constructed to safely use the GpuParser class
+ * that can essentially be though of as a raw pointer. The GpuParser does
+ * not have an explicit destructor and the AddPlasma subroutines handle the GpuParser
+ * in a safe way. The ParserWrapper struct is used to avoid memory leak
+ * in the EB parser functions.
+ */
+struct ParserWrapper
+ : public amrex::Gpu::Managed
+{
+ ParserWrapper (WarpXParser const& a_parser) noexcept
+ : m_parser(a_parser) {}
+
+ ~ParserWrapper() {
+ m_parser.clear();
+ }
+
+ AMREX_GPU_HOST_DEVICE
+ amrex::Real
+ getField (amrex::Real x, amrex::Real y, amrex::Real z, amrex::Real t=0.0) const noexcept
+ {
+ return m_parser(x,y,z,t);
+ }
+
+ GpuParser m_parser;
+};
+
+#endif
diff --git a/Source/Parser/wp_parser_c.h b/Source/Parser/wp_parser_c.h
index 970d6b355..2cf0e2c00 100644
--- a/Source/Parser/wp_parser_c.h
+++ b/Source/Parser/wp_parser_c.h
@@ -30,7 +30,7 @@ wp_ast_eval (struct wp_node* node)
#ifdef AMREX_DEVICE_COMPILE
extern __shared__ amrex_real extern_xyz[];
int tid = threadIdx.x + threadIdx.y*blockDim.x + threadIdx.z*(blockDim.x*blockDim.y);
- amrex_real* x = extern_xyz + tid*3;
+ amrex_real* x = extern_xyz + tid*4; // parser assumes 4 independent variables (x,y,z,t)
#endif
switch (node->type)
diff --git a/Source/Particles/Collision/CollisionType.H b/Source/Particles/Collision/CollisionType.H
index d020f47e8..29fdfb029 100644
--- a/Source/Particles/Collision/CollisionType.H
+++ b/Source/Particles/Collision/CollisionType.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_COLLISION_COLLISIONTYPE_H_
#define WARPX_PARTICLES_COLLISION_COLLISIONTYPE_H_
diff --git a/Source/Particles/Collision/CollisionType.cpp b/Source/Particles/Collision/CollisionType.cpp
index b8014579d..1d384ed8c 100644
--- a/Source/Particles/Collision/CollisionType.cpp
+++ b/Source/Particles/Collision/CollisionType.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "CollisionType.H"
#include "ShuffleFisherYates.H"
#include "ElasticCollisionPerez.H"
@@ -8,11 +14,9 @@ CollisionType::CollisionType(
std::string const collision_name)
{
-#if defined WARPX_DIM_XZ
- amrex::Abort("Collisions only work in 3D geometry for now.");
-#elif defined WARPX_DIM_RZ
+ #if defined WARPX_DIM_RZ
amrex::Abort("Collisions only work in Cartesian geometry for now.");
-#endif
+ #endif
// read collision species
std::vector<std::string> collision_species;
@@ -66,7 +70,7 @@ namespace {
const auto dxi = geom.InvCellSizeArray();
const auto plo = geom.ProbLoArray();
- // Find particles that are in each cell ;
+ // Find particles that are in each cell;
// results are stored in the object `bins`.
ParticleBins bins;
bins.build(np, particle_ptr, cbx,
@@ -128,7 +132,11 @@ void CollisionType::doCoulombCollisionsWithinTile
const Real dt = WarpX::GetInstance().getdt(lev);
Geometry const& geom = WarpX::GetInstance().Geom(lev);
- const Real dV = geom.CellSize(0)*geom.CellSize(1)*geom.CellSize(2);
+ #if (AMREX_SPACEDIM == 2)
+ auto dV = geom.CellSize(0) * geom.CellSize(1);
+ #elif (AMREX_SPACEDIM == 3)
+ auto dV = geom.CellSize(0) * geom.CellSize(1) * geom.CellSize(2);
+ #endif
// Loop over cells
amrex::ParallelFor( n_cells,
@@ -200,7 +208,11 @@ void CollisionType::doCoulombCollisionsWithinTile
const Real dt = WarpX::GetInstance().getdt(lev);
Geometry const& geom = WarpX::GetInstance().Geom(lev);
- const Real dV = geom.CellSize(0)*geom.CellSize(1)*geom.CellSize(2);
+ #if (AMREX_SPACEDIM == 2)
+ auto dV = geom.CellSize(0) * geom.CellSize(1);
+ #elif (AMREX_SPACEDIM == 3)
+ auto dV = geom.CellSize(0) * geom.CellSize(1) * geom.CellSize(2);
+ #endif
// Loop over cells
amrex::ParallelFor( n_cells,
diff --git a/Source/Particles/Collision/ComputeTemperature.H b/Source/Particles/Collision/ComputeTemperature.H
index 770510d74..81cb14dad 100644
--- a/Source/Particles/Collision/ComputeTemperature.H
+++ b/Source/Particles/Collision/ComputeTemperature.H
@@ -1,3 +1,9 @@
+/* Copyright 2019-2020 Andrew Myers, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_COLLISION_COMPUTE_TEMPERATURE_H_
#define WARPX_PARTICLES_COLLISION_COMPUTE_TEMPERATURE_H_
diff --git a/Source/Particles/Collision/ElasticCollisionPerez.H b/Source/Particles/Collision/ElasticCollisionPerez.H
index 8e16d95cc..b1fa64300 100644
--- a/Source/Particles/Collision/ElasticCollisionPerez.H
+++ b/Source/Particles/Collision/ElasticCollisionPerez.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_COLLISION_ELASTIC_COLLISION_PEREZ_H_
#define WARPX_PARTICLES_COLLISION_ELASTIC_COLLISION_PEREZ_H_
diff --git a/Source/Particles/Collision/ShuffleFisherYates.H b/Source/Particles/Collision/ShuffleFisherYates.H
index 621e654d6..614b44d37 100644
--- a/Source/Particles/Collision/ShuffleFisherYates.H
+++ b/Source/Particles/Collision/ShuffleFisherYates.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_COLLISION_SHUFFLE_FISHER_YATES_H_
#define WARPX_PARTICLES_COLLISION_SHUFFLE_FISHER_YATES_H_
diff --git a/Source/Particles/Collision/UpdateMomentumPerezElastic.H b/Source/Particles/Collision/UpdateMomentumPerezElastic.H
index 948e8b075..05c8cd227 100644
--- a/Source/Particles/Collision/UpdateMomentumPerezElastic.H
+++ b/Source/Particles/Collision/UpdateMomentumPerezElastic.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_COLLISION_UPDATE_MOMENTUM_PEREZ_ELASTIC_H_
#define WARPX_PARTICLES_COLLISION_UPDATE_MOMENTUM_PEREZ_ELASTIC_H_
diff --git a/Source/Particles/Deposition/ChargeDeposition.H b/Source/Particles/Deposition/ChargeDeposition.H
index eec407a2b..669fc4c57 100755
--- a/Source/Particles/Deposition/ChargeDeposition.H
+++ b/Source/Particles/Deposition/ChargeDeposition.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef CHARGEDEPOSITION_H_
#define CHARGEDEPOSITION_H_
diff --git a/Source/Particles/Deposition/CurrentDeposition.H b/Source/Particles/Deposition/CurrentDeposition.H
index 870dbcd33..90039dea2 100644
--- a/Source/Particles/Deposition/CurrentDeposition.H
+++ b/Source/Particles/Deposition/CurrentDeposition.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
+ * Remi Lehe, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef CURRENTDEPOSITION_H_
#define CURRENTDEPOSITION_H_
diff --git a/Source/Particles/Gather/FieldGather.H b/Source/Particles/Gather/FieldGather.H
index 57c5d1a4a..0a58f8425 100644
--- a/Source/Particles/Gather/FieldGather.H
+++ b/Source/Particles/Gather/FieldGather.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, David Grote, Maxence Thevenet
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef FIELDGATHER_H_
#define FIELDGATHER_H_
diff --git a/Source/Particles/MultiParticleContainer.H b/Source/Particles/MultiParticleContainer.H
index 9db129b05..65c13e39b 100644
--- a/Source/Particles/MultiParticleContainer.H
+++ b/Source/Particles/MultiParticleContainer.H
@@ -1,3 +1,13 @@
+/* Copyright 2019-2020 Andrew Myers, Ann Almgren, Axel Huebl
+ * David Grote, Jean-Luc Vay, Junmin Gu
+ * Luca Fedeli, Mathieu Lobet, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ * Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_ParticleContainer_H_
#define WARPX_ParticleContainer_H_
@@ -8,6 +18,7 @@
#include <RigidInjectedParticleContainer.H>
#include <PhotonParticleContainer.H>
#include <LaserParticleContainer.H>
+#include <WarpXParserWrapper.H>
#include <AMReX_Particles.H>
#ifdef WARPX_QED
@@ -81,13 +92,6 @@ public:
amrex::Real t, amrex::Real dt);
///
- /// This pushes the particle positions by one half time step for all the species in the
- /// MultiParticleContainer. It is used to desynchronize the particles after initializaton
- /// or when restarting from a checkpoint. This is the electrostatic version.
- ///
- void PushXES (amrex::Real dt);
-
- ///
/// This deposits the particle charge onto rho, accumulating the value for all the species
/// in the MultiParticleContainer. rho is assumed to contain node-centered multifabs.
/// This version is hard-coded for CIC deposition.
@@ -128,7 +132,7 @@ public:
///
/// This pushes the particle positions by one half time step for all the species in the
/// MultiParticleContainer. It is used to desynchronize the particles after initializaton
- /// or when restarting from a checkpoint. This is the electromagnetic version.
+ /// or when restarting from a checkpoint.
///
void PushX (amrex::Real dt);
@@ -215,6 +219,21 @@ public:
IonizationProcess ionization_process;
+ std::string m_B_ext_particle_s = "default";
+ std::string m_E_ext_particle_s = "default";
+ // External fields added to particle fields.
+ amrex::Vector<amrex::Real> m_B_external_particle;
+ amrex::Vector<amrex::Real> m_E_external_particle;
+ // ParserWrapper for B_external on the particle
+ std::unique_ptr<ParserWrapper> m_Bx_particle_parser;
+ std::unique_ptr<ParserWrapper> m_By_particle_parser;
+ std::unique_ptr<ParserWrapper> m_Bz_particle_parser;
+ // ParserWrapper for E_external on the particle
+ std::unique_ptr<ParserWrapper> m_Ex_particle_parser;
+ std::unique_ptr<ParserWrapper> m_Ey_particle_parser;
+ std::unique_ptr<ParserWrapper> m_Ez_particle_parser;
+
+
protected:
// Particle container types
diff --git a/Source/Particles/MultiParticleContainer.cpp b/Source/Particles/MultiParticleContainer.cpp
index d84bc1afa..f9a0d230b 100644
--- a/Source/Particles/MultiParticleContainer.cpp
+++ b/Source/Particles/MultiParticleContainer.cpp
@@ -1,3 +1,13 @@
+/* Copyright 2019-2020 Andrew Myers, Ann Almgren, Axel Huebl
+ * David Grote, Jean-Luc Vay, Luca Fedeli
+ * Mathieu Lobet, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang, Yinjian Zhao
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <MultiParticleContainer.H>
#include <AMReX_Vector.H>
@@ -72,6 +82,93 @@ MultiParticleContainer::ReadParameters ()
{
ParmParse pp("particles");
+ // allocating and initializing default values of external fields for particles
+ m_E_external_particle.resize(3);
+ m_B_external_particle.resize(3);
+ // initialize E and B fields to 0.0
+ for (int idim = 0; idim < 3; ++idim) {
+ m_E_external_particle[idim] = 0.0;
+ m_B_external_particle[idim] = 0.0;
+ }
+ // default values of E_external_particle and B_external_particle
+ // are used to set the E and B field when "constant" or "parser"
+ // is not explicitly used in the input
+ pp.query("B_ext_particle_init_style", m_B_ext_particle_s);
+ std::transform(m_B_ext_particle_s.begin(),
+ m_B_ext_particle_s.end(),
+ m_B_ext_particle_s.begin(),
+ ::tolower);
+ pp.query("E_ext_particle_init_style", m_E_ext_particle_s);
+ std::transform(m_E_ext_particle_s.begin(),
+ m_E_ext_particle_s.end(),
+ m_E_ext_particle_s.begin(),
+ ::tolower);
+ // if the input string for B_external on particles is "constant"
+ // then the values for the external B on particles must
+ // be provided in the input file.
+ if (m_B_ext_particle_s == "constant")
+ pp.getarr("B_external_particle", m_B_external_particle);
+
+ // if the input string for E_external on particles is "constant"
+ // then the values for the external E on particles must
+ // be provided in the input file.
+ if (m_E_ext_particle_s == "constant")
+ pp.getarr("E_external_particle", m_E_external_particle);
+
+ // if the input string for B_ext_particle_s is
+ // "parse_b_ext_particle_function" then the mathematical expression
+ // for the Bx_, By_, Bz_external_particle_function(x,y,z)
+ // must be provided in the input file.
+ if (m_B_ext_particle_s == "parse_b_ext_particle_function") {
+ // store the mathematical expression as string
+ std::string str_Bx_ext_particle_function;
+ std::string str_By_ext_particle_function;
+ std::string str_Bz_ext_particle_function;
+ Store_parserString(pp, "Bx_external_particle_function(x,y,z,t)",
+ str_Bx_ext_particle_function);
+ Store_parserString(pp, "By_external_particle_function(x,y,z,t)",
+ str_By_ext_particle_function);
+ Store_parserString(pp, "Bz_external_particle_function(x,y,z,t)",
+ str_Bz_ext_particle_function);
+
+ // Parser for B_external on the particle
+ m_Bx_particle_parser.reset(new ParserWrapper(
+ makeParser(str_Bx_ext_particle_function)));
+ m_By_particle_parser.reset(new ParserWrapper(
+ makeParser(str_By_ext_particle_function)));
+ m_Bz_particle_parser.reset(new ParserWrapper(
+ makeParser(str_Bz_ext_particle_function)));
+
+ }
+
+ // if the input string for E_ext_particle_s is
+ // "parse_e_ext_particle_function" then the mathematical expression
+ // for the Ex_, Ey_, Ez_external_particle_function(x,y,z)
+ // must be provided in the input file.
+ if (m_E_ext_particle_s == "parse_e_ext_particle_function") {
+ // store the mathematical expression as string
+ std::string str_Ex_ext_particle_function;
+ std::string str_Ey_ext_particle_function;
+ std::string str_Ez_ext_particle_function;
+ Store_parserString(pp, "Ex_external_particle_function(x,y,z,t)",
+ str_Ex_ext_particle_function);
+ Store_parserString(pp, "Ey_external_particle_function(x,y,z,t)",
+ str_Ey_ext_particle_function);
+ Store_parserString(pp, "Ez_external_particle_function(x,y,z,t)",
+ str_Ez_ext_particle_function);
+ // Parser for E_external on the particle
+ m_Ex_particle_parser.reset(new ParserWrapper(
+ makeParser(str_Ex_ext_particle_function)));
+ m_Ey_particle_parser.reset(new ParserWrapper(
+ makeParser(str_Ey_ext_particle_function)));
+ m_Ez_particle_parser.reset(new ParserWrapper(
+ makeParser(str_Ez_ext_particle_function)));
+
+ }
+
+
+
+
pp.query("nspecies", nspecies);
BL_ASSERT(nspecies >= 0);
@@ -215,14 +312,6 @@ MultiParticleContainer::EvolveES (const Vector<std::array<std::unique_ptr<MultiF
}
void
-MultiParticleContainer::PushXES (Real dt)
-{
- for (auto& pc : allcontainers) {
- pc->PushXES(dt);
- }
-}
-
-void
MultiParticleContainer::
DepositCharge (Vector<std::unique_ptr<MultiFab> >& rho, bool local)
{
diff --git a/Source/Particles/ParticleCreation/CopyParticle.H b/Source/Particles/ParticleCreation/CopyParticle.H
index 5e51c5283..8b2770891 100644
--- a/Source/Particles/ParticleCreation/CopyParticle.H
+++ b/Source/Particles/ParticleCreation/CopyParticle.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef COPYPARTICLE_H_
#define COPYPARTICLE_H_
diff --git a/Source/Particles/ParticleCreation/ElementaryProcess.H b/Source/Particles/ParticleCreation/ElementaryProcess.H
index bd9342e46..568f73fff 100644
--- a/Source/Particles/ParticleCreation/ElementaryProcess.H
+++ b/Source/Particles/ParticleCreation/ElementaryProcess.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef ELEMENTARYPROCESS_H_
#define ELEMENTARYPROCESS_H_
diff --git a/Source/Particles/ParticleCreation/TransformParticle.H b/Source/Particles/ParticleCreation/TransformParticle.H
index c0158db78..eb5820e32 100644
--- a/Source/Particles/ParticleCreation/TransformParticle.H
+++ b/Source/Particles/ParticleCreation/TransformParticle.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef TRANSFORMPARTICLE_H_
#define TRANSFORMPARTICLE_H_
diff --git a/Source/Particles/PhotonParticleContainer.H b/Source/Particles/PhotonParticleContainer.H
index 9b688cc59..7750d5ce8 100644
--- a/Source/Particles/PhotonParticleContainer.H
+++ b/Source/Particles/PhotonParticleContainer.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, David Grote, Luca Fedeli
+ * Maxence Thevenet, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PhotonParticleContainer_H_
#define WARPX_PhotonParticleContainer_H_
diff --git a/Source/Particles/PhotonParticleContainer.cpp b/Source/Particles/PhotonParticleContainer.cpp
index c03ed00c2..ab85170ac 100644
--- a/Source/Particles/PhotonParticleContainer.cpp
+++ b/Source/Particles/PhotonParticleContainer.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Luca Fedeli, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <limits>
#include <sstream>
#include <algorithm>
diff --git a/Source/Particles/PhysicalParticleContainer.H b/Source/Particles/PhysicalParticleContainer.H
index 0192ffb37..18a6540d5 100644
--- a/Source/Particles/PhysicalParticleContainer.H
+++ b/Source/Particles/PhysicalParticleContainer.H
@@ -1,3 +1,12 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, David Grote
+ * Ligia Diana Amorim, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ * Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PhysicalParticleContainer_H_
#define WARPX_PhysicalParticleContainer_H_
@@ -47,6 +56,26 @@ public:
amrex::Real t, amrex::Real dt) override;
#endif // WARPX_DO_ELECTROSTATIC
+ /**
+ * \brief Apply external E and B fields on the particles. The E and B
+ * fields could be defined as a constant or using a parser for reading
+ * in a mathematical expression. The default value for the E- and B-fields
+ * is (0.0,0.0,0.0).
+ *
+ * \param[in,out] Exp-Bzp pointer to fields on particles modified based
+ * on external E and B
+ * \param[in] xp,yp,zp arrays of particle positions required to compute
+ * mathematical expression for the external fields
+ * using parser.
+ */
+ void AssignExternalFieldOnParticles ( WarpXParIter& pti,
+ RealVector& Exp, RealVector& Eyp,
+ RealVector& Ezp, RealVector& Bxp,
+ RealVector& Byp, RealVector& Bzp,
+ const amrex::Gpu::ManagedDeviceVector<amrex::ParticleReal>& xp,
+ const amrex::Gpu::ManagedDeviceVector<amrex::ParticleReal>& yp,
+ const amrex::Gpu::ManagedDeviceVector<amrex::ParticleReal>& zp, int lev);
+
virtual void FieldGather (int lev,
const amrex::MultiFab& Ex,
const amrex::MultiFab& Ey,
@@ -318,6 +347,7 @@ protected:
//radiation reaction
bool do_classical_radiation_reaction = false;
+
#ifdef WARPX_QED
// A flag to enable quantum_synchrotron process for leptons
bool m_do_qed_quantum_sync = false;
diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp
index 94d9bc363..2891cada3 100644
--- a/Source/Particles/PhysicalParticleContainer.cpp
+++ b/Source/Particles/PhysicalParticleContainer.cpp
@@ -1,3 +1,13 @@
+/* Copyright 2019-2020 Andrew Myers, Aurore Blelly, Axel Huebl
+ * David Grote, Glenn Richardson, Jean-Luc Vay
+ * Ligia Diana Amorim, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ * Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <limits>
#include <sstream>
@@ -40,6 +50,7 @@ PhysicalParticleContainer::PhysicalParticleContainer (AmrCore* amr_core, int isp
pp.query("do_splitting", do_splitting);
pp.query("split_type", split_type);
pp.query("do_not_deposit", do_not_deposit);
+ pp.query("do_not_push", do_not_push);
pp.query("do_continuous_injection", do_continuous_injection);
pp.query("initialize_self_fields", initialize_self_fields);
@@ -450,7 +461,8 @@ PhysicalParticleContainer::AddPlasma (int lev, RealBox part_realbox)
overlap_box.setBig( dir,
int( std::round((overlap_realbox.hi(dir)-overlap_realbox.lo(dir))
/dx[dir] )) - 1);
- shifted[dir] = std::round((overlap_realbox.lo(dir)-problo[dir])/dx[dir]);
+ shifted[dir] =
+ static_cast<int>(std::round((overlap_realbox.lo(dir)-problo[dir])/dx[dir]));
// shifted is exact in non-moving-window direction. That's all we care.
}
if (no_overlap == 1) {
@@ -492,7 +504,9 @@ PhysicalParticleContainer::AddPlasma (int lev, RealBox part_realbox)
// Update NextID to include particles created in this function
int pid;
+#ifdef _OPENMP
#pragma omp critical (add_plasma_nextid)
+#endif
{
pid = ParticleType::NextID();
ParticleType::NextID(pid+max_new_particles);
@@ -580,7 +594,8 @@ PhysicalParticleContainer::AddPlasma (int lev, RealBox part_realbox)
IntVect iv = overlap_box.atOffset(cellid);
- const XDim3 r = inj_pos->getPositionUnitBox(i_part, fac);
+ const XDim3 r =
+ inj_pos->getPositionUnitBox(i_part, static_cast<int>(fac));
#if (AMREX_SPACEDIM == 3)
Real x = overlap_corner[0] + (iv[0]+r.x)*dx[0];
Real y = overlap_corner[1] + (iv[1]+r.y)*dx[1];
@@ -962,6 +977,79 @@ PhysicalParticleContainer::EvolveES (const Vector<std::array<std::unique_ptr<Mul
#endif // WARPX_DO_ELECTROSTATIC
void
+PhysicalParticleContainer::AssignExternalFieldOnParticles(WarpXParIter& pti,
+ RealVector& Exp, RealVector& Eyp, RealVector& Ezp,
+ RealVector& Bxp, RealVector& Byp, RealVector& Bzp,
+ const Gpu::ManagedDeviceVector<ParticleReal>& xp,
+ const Gpu::ManagedDeviceVector<ParticleReal>& yp,
+ const Gpu::ManagedDeviceVector<ParticleReal>& zp, int lev)
+{
+ const long np = pti.numParticles();
+ /// get WarpX class object
+ auto & warpx = WarpX::GetInstance();
+ /// get MultiParticleContainer class object
+ auto & mypc = warpx.GetPartContainer();
+ if (mypc.m_E_ext_particle_s=="constant" ||
+ mypc.m_E_ext_particle_s=="default") {
+ Exp.assign(np,mypc.m_E_external_particle[0]);
+ Eyp.assign(np,mypc.m_E_external_particle[1]);
+ Ezp.assign(np,mypc.m_E_external_particle[2]);
+ }
+ if (mypc.m_B_ext_particle_s=="constant" ||
+ mypc.m_B_ext_particle_s=="default") {
+ Bxp.assign(np,mypc.m_B_external_particle[0]);
+ Byp.assign(np,mypc.m_B_external_particle[1]);
+ Bzp.assign(np,mypc.m_B_external_particle[2]);
+ }
+ if (mypc.m_E_ext_particle_s=="parse_e_ext_particle_function") {
+ const Real* const AMREX_RESTRICT xp_data = xp.dataPtr();
+ const Real* const AMREX_RESTRICT yp_data = yp.dataPtr();
+ const Real* const AMREX_RESTRICT zp_data = zp.dataPtr();
+ Real* const AMREX_RESTRICT Exp_data = Exp.dataPtr();
+ Real* const AMREX_RESTRICT Eyp_data = Eyp.dataPtr();
+ Real* const AMREX_RESTRICT Ezp_data = Ezp.dataPtr();
+ ParserWrapper *xfield_partparser = mypc.m_Ex_particle_parser.get();
+ ParserWrapper *yfield_partparser = mypc.m_Ey_particle_parser.get();
+ ParserWrapper *zfield_partparser = mypc.m_Ez_particle_parser.get();
+ Real time = warpx.gett_new(lev);
+ amrex::ParallelFor(pti.numParticles(),
+ [=] AMREX_GPU_DEVICE (long i) {
+ Exp_data[i] = xfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ Eyp_data[i] = yfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ Ezp_data[i] = zfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ },
+ /* To allocate shared memory for the GPU threads. */
+ /* But, for now only 4 doubles (x,y,z,t) are allocated. */
+ amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 4
+ );
+ }
+ if (mypc.m_B_ext_particle_s=="parse_b_ext_particle_function") {
+ const Real* const AMREX_RESTRICT xp_data = xp.dataPtr();
+ const Real* const AMREX_RESTRICT yp_data = yp.dataPtr();
+ const Real* const AMREX_RESTRICT zp_data = zp.dataPtr();
+ Real* const AMREX_RESTRICT Bxp_data = Bxp.dataPtr();
+ Real* const AMREX_RESTRICT Byp_data = Byp.dataPtr();
+ Real* const AMREX_RESTRICT Bzp_data = Bzp.dataPtr();
+ ParserWrapper *xfield_partparser = mypc.m_Bx_particle_parser.get();
+ ParserWrapper *yfield_partparser = mypc.m_By_particle_parser.get();
+ ParserWrapper *zfield_partparser = mypc.m_Bz_particle_parser.get();
+ Real time = warpx.gett_new(lev);
+ amrex::ParallelFor(pti.numParticles(),
+ [=] AMREX_GPU_DEVICE (long i) {
+ Bxp_data[i] = xfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ Byp_data[i] = yfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ Bzp_data[i] = zfield_partparser->getField(xp_data[i],yp_data[i],zp_data[i],time);
+ },
+ /* To allocate shared memory for the GPU threads. */
+ /* But, for now only 4 doubles (x,y,z,t) are allocated. */
+ amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double) * 4
+ );
+ }
+}
+
+
+
+void
PhysicalParticleContainer::FieldGather (int lev,
const amrex::MultiFab& Ex,
const amrex::MultiFab& Ey,
@@ -1010,13 +1098,6 @@ PhysicalParticleContainer::FieldGather (int lev,
const FArrayBox& byfab = By[pti];
const FArrayBox& bzfab = Bz[pti];
- Exp.assign(np,WarpX::E_external_particle[0]);
- Eyp.assign(np,WarpX::E_external_particle[1]);
- Ezp.assign(np,WarpX::E_external_particle[2]);
- Bxp.assign(np,WarpX::B_external_particle[0]);
- Byp.assign(np,WarpX::B_external_particle[1]);
- Bzp.assign(np,WarpX::B_external_particle[2]);
-
//
// copy data from particle container to temp arrays
//
@@ -1041,6 +1122,9 @@ PhysicalParticleContainer::FieldGather (int lev,
costarr(i,j,k) += wt;
});
}
+ // synchronize avoids cudaStreams from over-writing the temporary arrays used to
+ // store positions
+ Gpu::synchronize();
}
}
}
@@ -1147,14 +1231,6 @@ PhysicalParticleContainer::Evolve (int lev,
exfab, eyfab, ezfab, bxfab, byfab, bzfab);
}
- Exp.assign(np,WarpX::E_external_particle[0]);
- Eyp.assign(np,WarpX::E_external_particle[1]);
- Ezp.assign(np,WarpX::E_external_particle[2]);
-
- Bxp.assign(np,WarpX::B_external_particle[0]);
- Byp.assign(np,WarpX::B_external_particle[1]);
- Bzp.assign(np,WarpX::B_external_particle[2]);
-
// Determine which particles deposit/gather in the buffer, and
// which particles deposit/gather in the fine patch
long nfine_current = np;
@@ -1614,10 +1690,9 @@ PhysicalParticleContainer::PushPX(WarpXParIter& pti,
#ifdef WARPX_QED
- auto t_chi_max = m_shr_p_qs_engine->get_ref_ctrl().chi_part_min;
-
if(do_classical_radiation_reaction){
if(m_do_qed_quantum_sync){
+ const auto t_chi_max = m_shr_p_qs_engine->get_ref_ctrl().chi_part_min;
amrex::ParallelFor(
pti.numParticles(),
[=] AMREX_GPU_DEVICE (long i) {
@@ -1795,14 +1870,6 @@ PhysicalParticleContainer::PushP (int lev, Real dt,
const FArrayBox& byfab = By[pti];
const FArrayBox& bzfab = Bz[pti];
- Exp.assign(np,WarpX::E_external_particle[0]);
- Eyp.assign(np,WarpX::E_external_particle[1]);
- Ezp.assign(np,WarpX::E_external_particle[2]);
-
- Bxp.assign(np,WarpX::B_external_particle[0]);
- Byp.assign(np,WarpX::B_external_particle[1]);
- Bzp.assign(np,WarpX::B_external_particle[2]);
-
//
// copy data from particle container to temp arrays
//
@@ -1976,7 +2043,6 @@ void PhysicalParticleContainer::GetParticleSlice(const int direction, const Real
#endif
for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti)
{
- int counter_for_ParticleCopy = 0;
const Box& box = pti.validbox();
auto index = std::make_pair(pti.index(), pti.LocalTileIndex());
const RealBox tile_real_box(box, dx, plo);
@@ -2172,9 +2238,16 @@ PhysicalParticleContainer::FieldGather (WarpXParIter& pti,
AMREX_ALWAYS_ASSERT_WITH_MESSAGE((gather_lev==(lev-1)) ||
(gather_lev==(lev )),
"Gather buffers only work for lev-1");
-
// If no particles, do not do anything
if (np_to_gather == 0) return;
+
+ // initializing the field value to the externally applied field before
+ // gathering fields from the grid to the particles.
+ AssignExternalFieldOnParticles(pti, Exp, Eyp, Ezp, Bxp, Byp, Bzp,
+ m_xp[thread_num], m_yp[thread_num],
+ m_zp[thread_num], lev);
+
+
// Get cell size on gather_lev
const std::array<Real,3>& dx = WarpX::CellSize(std::max(gather_lev,0));
@@ -2420,4 +2493,5 @@ set_quantum_sync_engine_ptr(std::shared_ptr<QuantumSynchrotronEngine> ptr)
{
m_shr_p_qs_engine = ptr;
}
+
#endif
diff --git a/Source/Particles/Pusher/GetAndSetPosition.H b/Source/Particles/Pusher/GetAndSetPosition.H
index ae73a74e4..7180f3c55 100644
--- a/Source/Particles/Pusher/GetAndSetPosition.H
+++ b/Source/Particles/Pusher/GetAndSetPosition.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
#define WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
diff --git a/Source/Particles/Pusher/UpdateMomentumBoris.H b/Source/Particles/Pusher/UpdateMomentumBoris.H
index 160f38ade..13582d7e0 100644
--- a/Source/Particles/Pusher/UpdateMomentumBoris.H
+++ b/Source/Particles/Pusher/UpdateMomentumBoris.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_BORIS_H_
#define WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_BORIS_H_
diff --git a/Source/Particles/Pusher/UpdateMomentumBorisWithRadiationReaction.H b/Source/Particles/Pusher/UpdateMomentumBorisWithRadiationReaction.H
index 0bc0f5d01..d8489e23e 100644
--- a/Source/Particles/Pusher/UpdateMomentumBorisWithRadiationReaction.H
+++ b/Source/Particles/Pusher/UpdateMomentumBorisWithRadiationReaction.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_BORIS_WITHRR_H_
#define WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_BORIS_WITHRR_H_
diff --git a/Source/Particles/Pusher/UpdateMomentumHigueraCary.H b/Source/Particles/Pusher/UpdateMomentumHigueraCary.H
index 51d7fd620..de2436ce2 100644
--- a/Source/Particles/Pusher/UpdateMomentumHigueraCary.H
+++ b/Source/Particles/Pusher/UpdateMomentumHigueraCary.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_HIGUERACARY_H_
#define WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_HIGUERACARY_H_
diff --git a/Source/Particles/Pusher/UpdateMomentumVay.H b/Source/Particles/Pusher/UpdateMomentumVay.H
index f7ec79d89..846d59310 100644
--- a/Source/Particles/Pusher/UpdateMomentumVay.H
+++ b/Source/Particles/Pusher/UpdateMomentumVay.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_VAY_H_
#define WARPX_PARTICLES_PUSHER_UPDATEMOMENTUM_VAY_H_
diff --git a/Source/Particles/Pusher/UpdatePosition.H b/Source/Particles/Pusher/UpdatePosition.H
index 9943128f1..7f86a106d 100644
--- a/Source/Particles/Pusher/UpdatePosition.H
+++ b/Source/Particles/Pusher/UpdatePosition.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEPOSITION_H_
#define WARPX_PARTICLES_PUSHER_UPDATEPOSITION_H_
diff --git a/Source/Particles/Pusher/UpdatePositionPhoton.H b/Source/Particles/Pusher/UpdatePositionPhoton.H
index 1a0bd114f..3a28e87a1 100644
--- a/Source/Particles/Pusher/UpdatePositionPhoton.H
+++ b/Source/Particles/Pusher/UpdatePositionPhoton.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_PUSHER_UPDATEPOSITIONPHOTON_H_
#define WARPX_PARTICLES_PUSHER_UPDATEPOSITIONPHOTON_H_
diff --git a/Source/Particles/RigidInjectedParticleContainer.H b/Source/Particles/RigidInjectedParticleContainer.H
index fecb9c48e..5e5749093 100644
--- a/Source/Particles/RigidInjectedParticleContainer.H
+++ b/Source/Particles/RigidInjectedParticleContainer.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, David Grote, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_RigidInjectedParticleContainer_H_
#define WARPX_RigidInjectedParticleContainer_H_
diff --git a/Source/Particles/RigidInjectedParticleContainer.cpp b/Source/Particles/RigidInjectedParticleContainer.cpp
index bee71fba1..f9db682d7 100644
--- a/Source/Particles/RigidInjectedParticleContainer.cpp
+++ b/Source/Particles/RigidInjectedParticleContainer.cpp
@@ -1,3 +1,12 @@
+/* Copyright 2019-2020 Andrew Myers, David Grote, Glenn Richardson
+ * Ligia Diana Amorim, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ * Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <limits>
#include <sstream>
#include <algorithm>
@@ -392,13 +401,6 @@ RigidInjectedParticleContainer::PushP (int lev, Real dt,
const FArrayBox& byfab = By[pti];
const FArrayBox& bzfab = Bz[pti];
- Exp.assign(np,WarpX::E_external_particle[0]);
- Eyp.assign(np,WarpX::E_external_particle[1]);
- Ezp.assign(np,WarpX::E_external_particle[2]);
- Bxp.assign(np,WarpX::B_external_particle[0]);
- Byp.assign(np,WarpX::B_external_particle[1]);
- Bzp.assign(np,WarpX::B_external_particle[2]);
-
//
// copy data from particle container to temp arrays
//
diff --git a/Source/Particles/ShapeFactors.H b/Source/Particles/ShapeFactors.H
index be79a4871..dd36fb31f 100644
--- a/Source/Particles/ShapeFactors.H
+++ b/Source/Particles/ShapeFactors.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef SHAPEFACTORS_H_
#define SHAPEFACTORS_H_
diff --git a/Source/Particles/Sorting/Partition.cpp b/Source/Particles/Sorting/Partition.cpp
index e88af017f..c25c24d5d 100644
--- a/Source/Particles/Sorting/Partition.cpp
+++ b/Source/Particles/Sorting/Partition.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <SortingUtils.H>
#include <PhysicalParticleContainer.H>
#include <WarpX.H>
diff --git a/Source/Particles/Sorting/SortingUtils.H b/Source/Particles/Sorting/SortingUtils.H
index 35bc059aa..f0e991367 100644
--- a/Source/Particles/Sorting/SortingUtils.H
+++ b/Source/Particles/Sorting/SortingUtils.H
@@ -1,12 +1,16 @@
+/* Copyright 2019-2020 Andrew Myers, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PARTICLES_SORTING_SORTINGUTILS_H_
#define WARPX_PARTICLES_SORTING_SORTINGUTILS_H_
#include <WarpXParticleContainer.H>
#include <AMReX_Gpu.H>
-#ifdef AMREX_USE_GPU
- #include <thrust/partition.h>
- #include <thrust/distance.h>
-#endif
+#include <AMReX_Partition.H>
/** \brief Fill the elements of the input vector with consecutive integer,
* starting from 0
@@ -16,8 +20,10 @@
void fillWithConsecutiveIntegers( amrex::Gpu::DeviceVector<long>& v )
{
#ifdef AMREX_USE_GPU
- // On GPU: Use thrust
- thrust::sequence( v.begin(), v.end() );
+ // On GPU: Use amrex
+ auto data = v.data();
+ auto N = v.size();
+ AMREX_FOR_1D( N, i, data[i] = i;);
#else
// On CPU: Use std library
std::iota( v.begin(), v.end(), 0L );
@@ -35,17 +41,18 @@ void fillWithConsecutiveIntegers( amrex::Gpu::DeviceVector<long>& v )
*/
template< typename ForwardIterator >
ForwardIterator stablePartition(ForwardIterator const index_begin,
- ForwardIterator const index_end,
- amrex::Gpu::DeviceVector<int> const& predicate)
+ ForwardIterator const index_end,
+ amrex::Gpu::DeviceVector<int> const& predicate)
{
#ifdef AMREX_USE_GPU
- // On GPU: Use thrust
+ // On GPU: Use amrex
int const* AMREX_RESTRICT predicate_ptr = predicate.dataPtr();
- ForwardIterator const sep = thrust::stable_partition(
- thrust::cuda::par(amrex::Gpu::The_ThrustCachedAllocator()),
- index_begin, index_end,
- [predicate_ptr] AMREX_GPU_DEVICE (long i) { return predicate_ptr[i]; }
- );
+ int N = static_cast<int>(std::distance(index_begin, index_end));
+ auto num_true = amrex::StablePartition(&(*index_begin), N,
+ [predicate_ptr] AMREX_GPU_DEVICE (long i) { return predicate_ptr[i]; });
+
+ ForwardIterator sep = index_begin;
+ std::advance(sep, num_true);
#else
// On CPU: Use std library
ForwardIterator const sep = std::stable_partition(
@@ -66,12 +73,7 @@ template< typename ForwardIterator >
int iteratorDistance(ForwardIterator const first,
ForwardIterator const last)
{
-#ifdef AMREX_USE_GPU
- // On GPU: Use thrust
- return thrust::distance( first, last );
-#else
return std::distance( first, last );
-#endif
}
/** \brief Functor that fills the elements of the particle array `inexflag`
diff --git a/Source/Particles/WarpXParticleContainer.H b/Source/Particles/WarpXParticleContainer.H
index 33c10e8de..b89ea83fc 100644
--- a/Source/Particles/WarpXParticleContainer.H
+++ b/Source/Particles/WarpXParticleContainer.H
@@ -1,3 +1,12 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, David Grote
+ * Jean-Luc Vay, Junmin Gu, Luca Fedeli
+ * Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ * Weiqun Zhang, Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_WarpXParticleContainer_H_
#define WARPX_WarpXParticleContainer_H_
@@ -193,15 +202,6 @@ public:
/// This pushes the particle positions by one half time step.
/// It is used to desynchronize the particles after initializaton
/// or when restarting from a checkpoint.
- /// This is the electrostatic version of the particle push.
- ///
- void PushXES (amrex::Real dt);
-
- ///
- /// This pushes the particle positions by one half time step.
- /// It is used to desynchronize the particles after initializaton
- /// or when restarting from a checkpoint.
- /// This is the electromagnetic version of the particle push.
///
void PushX ( amrex::Real dt);
void PushX (int lev, amrex::Real dt);
@@ -339,8 +339,8 @@ protected:
//! instead of gathering fields from the finest patch level, gather from the coarsest
bool m_gather_from_main_grid = false;
- static int do_not_push;
- static int do_not_deposit;
+ int do_not_push = 0;
+ int do_not_deposit = 0;
// Whether to allow particles outside of the simulation domain to be
// initialized when they enter the domain.
diff --git a/Source/Particles/WarpXParticleContainer.cpp b/Source/Particles/WarpXParticleContainer.cpp
index 15a6cff9b..7628cfd85 100644
--- a/Source/Particles/WarpXParticleContainer.cpp
+++ b/Source/Particles/WarpXParticleContainer.cpp
@@ -1,3 +1,12 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, David Grote
+ * Jean-Luc Vay, Luca Fedeli, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ * Yinjian Zhao, levinem
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <limits>
#include <MultiParticleContainer.H>
@@ -16,9 +25,6 @@
using namespace amrex;
-int WarpXParticleContainer::do_not_push = 0;
-int WarpXParticleContainer::do_not_deposit = 0;
-
WarpXParIter::WarpXParIter (ContainerType& pc, int level)
: ParIter(pc, level, MFItInfo().SetDynamic(WarpX::do_dynamic_scheduling))
{
@@ -113,6 +119,7 @@ WarpXParticleContainer::WarpXParticleContainer (AmrCore* amr_core, int ispecies)
m_xp.resize(num_threads);
m_yp.resize(num_threads);
m_zp.resize(num_threads);
+
}
void
@@ -129,7 +136,6 @@ WarpXParticleContainer::ReadParameters ()
do_tiling = true;
#endif
pp.query("do_tiling", do_tiling);
- pp.query("do_not_push", do_not_push);
initialized = true;
}
@@ -737,37 +743,6 @@ Real WarpXParticleContainer::maxParticleVelocity(bool local) {
}
void
-WarpXParticleContainer::PushXES (Real dt)
-{
- BL_PROFILE("WPC::PushXES()");
-
- const int num_levels = finestLevel() + 1;
-
- for (int lev = 0; lev < num_levels; ++lev) {
- const auto& gm = m_gdb->Geom(lev);
- const RealBox& prob_domain = gm.ProbDomain();
- for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti) {
- auto& particles = pti.GetArrayOfStructs();
- int nstride = particles.dataShape().first;
- const long np = pti.numParticles();
-
- auto& attribs = pti.GetAttribs();
- auto& uxp = attribs[PIdx::ux];
- auto& uyp = attribs[PIdx::uy];
- auto& uzp = attribs[PIdx::uz];
-
- WRPX_PUSH_LEAPFROG_POSITIONS(particles.dataPtr(), nstride, np,
- uxp.dataPtr(), uyp.dataPtr(),
-#if AMREX_SPACEDIM == 3
- uzp.dataPtr(),
-#endif
- &dt,
- prob_domain.lo(), prob_domain.hi());
- }
- }
-}
-
-void
WarpXParticleContainer::PushX (amrex::Real dt)
{
const int nLevels = finestLevel();
diff --git a/Source/Particles/interpolate_cic.F90 b/Source/Particles/interpolate_cic.F90
index 3eb361d2f..97bd8c153 100644
--- a/Source/Particles/interpolate_cic.F90
+++ b/Source/Particles/interpolate_cic.F90
@@ -1,3 +1,9 @@
+! Copyright 2019 Maxence Thevenet, Weiqun Zhang
+!
+! This file is part of WarpX.
+!
+! License: BSD-3-Clause-LBNL
+
module warpx_ES_interpolate_cic
use iso_c_binding
diff --git a/Source/Particles/push_particles_ES.F90 b/Source/Particles/push_particles_ES.F90
index b84f48d5f..a22ee5a62 100644
--- a/Source/Particles/push_particles_ES.F90
+++ b/Source/Particles/push_particles_ES.F90
@@ -1,3 +1,9 @@
+! Copyright 2019 Maxence Thevenet, Weiqun Zhang
+!
+! This file is part of WarpX.
+!
+! License: BSD-3-Clause-LBNL
+
module warpx_ES_push_particles
use iso_c_binding
@@ -145,114 +151,4 @@ contains
end subroutine warpx_push_leapfrog_2d
-
-!
-! This routine advances the particle positions using the current
-! velocity. This is needed to desynchronize the particle positions
-! from the velocities after particle initialization.
-!
-! Arguments:
-! particles : a pointer to the particle array-of-structs
-! ns : the stride length of particle struct (the size of the struct in number of reals)
-! np : the number of particles
-! xx_p : the electric field in the x-direction at the particle positions
-! vy_p : the electric field in the y-direction at the particle positions
-! vz_p : the electric field in the z-direction at the particle positions
-! dt : the time step
-! prob_lo : the left-hand corner of the problem domain
-! prob_hi : the right-hand corner of the problem domain
-!
- subroutine warpx_push_leapfrog_positions_3d(particles, ns, np, &
- vx_p, vy_p, vz_p, dt, &
- prob_lo, prob_hi) &
- bind(c,name='warpx_push_leapfrog_positions_3d')
- integer, value, intent(in) :: ns, np
- real(amrex_particle_real), intent(inout) :: particles(ns,np)
- real(amrex_particle_real), intent(inout) :: vx_p(np), vy_p(np), vz_p(np)
- real(amrex_real), intent(in) :: dt
- real(amrex_real), intent(in) :: prob_lo(3), prob_hi(3)
-
- integer n
-
- do n = 1, np
-
- particles(1, n) = particles(1, n) + dt * vx_p(n)
- particles(2, n) = particles(2, n) + dt * vy_p(n)
- particles(3, n) = particles(3, n) + dt * vz_p(n)
-
-! bounce off the walls in the x...
- do while (particles(1, n) .lt. prob_lo(1) .or. particles(1, n) .gt. prob_hi(1))
- if (particles(1, n) .lt. prob_lo(1)) then
- particles(1, n) = 2.d0*prob_lo(1) - particles(1, n)
- else
- particles(1, n) = 2.d0*prob_hi(1) - particles(1, n)
- end if
- vx_p(n) = -vx_p(n)
- end do
-
-! ... y...
- do while (particles(2, n) .lt. prob_lo(2) .or. particles(2, n) .gt. prob_hi(2))
- if (particles(2, n) .lt. prob_lo(2)) then
- particles(2, n) = 2.d0*prob_lo(2) - particles(2, n)
- else
- particles(2, n) = 2.d0*prob_hi(2) - particles(2, n)
- end if
- vy_p(n) = -vy_p(n)
- end do
-
-! ... and z directions
- do while (particles(3, n) .lt. prob_lo(3) .or. particles(3, n) .gt. prob_hi(3))
- if (particles(3, n) .lt. prob_lo(3)) then
- particles(3, n) = 2.d0*prob_lo(3) - particles(3, n)
- else
- particles(3, n) = 2.d0*prob_hi(3) - particles(3, n)
- end if
- vz_p(n) = -vz_p(n)
- end do
-
- end do
-
- end subroutine warpx_push_leapfrog_positions_3d
-
- subroutine warpx_push_leapfrog_positions_2d(particles, ns, np, &
- vx_p, vy_p, dt, &
- prob_lo, prob_hi) &
- bind(c,name='warpx_push_leapfrog_positions_2d')
- integer, value, intent(in) :: ns, np
- real(amrex_particle_real), intent(inout) :: particles(ns,np)
- real(amrex_particle_real), intent(inout) :: vx_p(np), vy_p(np)
- real(amrex_real), intent(in) :: dt
- real(amrex_real), intent(in) :: prob_lo(2), prob_hi(2)
-
- integer n
-
- do n = 1, np
-
- particles(1, n) = particles(1, n) + dt * vx_p(n)
- particles(2, n) = particles(2, n) + dt * vy_p(n)
-
-! bounce off the walls in the x...
- do while (particles(1, n) .lt. prob_lo(1) .or. particles(1, n) .gt. prob_hi(1))
- if (particles(1, n) .lt. prob_lo(1)) then
- particles(1, n) = 2.d0*prob_lo(1) - particles(1, n)
- else
- particles(1, n) = 2.d0*prob_hi(1) - particles(1, n)
- end if
- vx_p(n) = -vx_p(n)
- end do
-
-! ... y...
- do while (particles(2, n) .lt. prob_lo(2) .or. particles(2, n) .gt. prob_hi(2))
- if (particles(2, n) .lt. prob_lo(2)) then
- particles(2, n) = 2.d0*prob_lo(2) - particles(2, n)
- else
- particles(2, n) = 2.d0*prob_hi(2) - particles(2, n)
- end if
- vy_p(n) = -vy_p(n)
- end do
-
- end do
-
- end subroutine warpx_push_leapfrog_positions_2d
-
end module warpx_ES_push_particles
diff --git a/Source/Python/WarpXWrappers.cpp b/Source/Python/WarpXWrappers.cpp
index 54dfe1955..bf5377dae 100644
--- a/Source/Python/WarpXWrappers.cpp
+++ b/Source/Python/WarpXWrappers.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019 Andrew Myers, Axel Huebl, David Grote
+ * Luca Fedeli, Maxence Thevenet, Remi Lehe
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpXWrappers.h>
#include <WarpXParticleContainer.H>
@@ -346,11 +354,11 @@ extern "C"
}
void warpx_FillBoundaryE () {
WarpX& warpx = WarpX::GetInstance();
- warpx.FillBoundaryE ();
+ warpx.FillBoundaryE (warpx.getngE());
}
void warpx_FillBoundaryB () {
WarpX& warpx = WarpX::GetInstance();
- warpx.FillBoundaryB ();
+ warpx.FillBoundaryB (warpx.getngE());
}
void warpx_SyncCurrent () {
WarpX& warpx = WarpX::GetInstance();
@@ -404,6 +412,11 @@ extern "C"
return warpx.plotInt ();
}
+ int warpx_openpmdInt () {
+ WarpX& warpx = WarpX::GetInstance();
+ return warpx.openpmdInt ();
+ }
+
void warpx_WriteCheckPointFile () {
WarpX& warpx = WarpX::GetInstance();
warpx.WriteCheckPointFile ();
@@ -412,6 +425,10 @@ extern "C"
WarpX& warpx = WarpX::GetInstance();
warpx.WritePlotFile ();
}
+ void warpx_WriteOpenPMDFile () {
+ WarpX& warpx = WarpX::GetInstance();
+ warpx.WriteOpenPMDFile ();
+ }
int warpx_finestLevel () {
WarpX& warpx = WarpX::GetInstance();
diff --git a/Source/Python/WarpXWrappers.h b/Source/Python/WarpXWrappers.h
index 4de885b88..53309ad93 100644
--- a/Source/Python/WarpXWrappers.h
+++ b/Source/Python/WarpXWrappers.h
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, David Grote, Maxence Thevenet
+ * Remi Lehe, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_WRAPPERS_H_
#define WARPX_WRAPPERS_H_
@@ -95,9 +102,11 @@ extern "C" {
int warpx_checkInt ();
int warpx_plotInt ();
+ int warpx_openpmdInt ();
void warpx_WriteCheckPointFile ();
void warpx_WritePlotFile ();
+ void warpx_WriteOpenPMDFile ();
int warpx_finestLevel ();
diff --git a/Source/Python/WarpX_py.H b/Source/Python/WarpX_py.H
index d8cf22155..b6a813bfc 100644
--- a/Source/Python/WarpX_py.H
+++ b/Source/Python/WarpX_py.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_PY_H_
#define WARPX_PY_H_
diff --git a/Source/Python/WarpX_py.cpp b/Source/Python/WarpX_py.cpp
index 276d637d7..4ca06b644 100644
--- a/Source/Python/WarpX_py.cpp
+++ b/Source/Python/WarpX_py.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX_py.H>
extern "C" {
diff --git a/Source/QED/BreitWheelerDummyTable.H b/Source/QED/BreitWheelerDummyTable.H
index e03f9d20b..95f65923e 100644
--- a/Source/QED/BreitWheelerDummyTable.H
+++ b/Source/QED/BreitWheelerDummyTable.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_breit_wheeler_dummy_tables_h_
#define WARPX_breit_wheeler_dummy_tables_h_
diff --git a/Source/QED/BreitWheelerEngineInnards.H b/Source/QED/BreitWheelerEngineInnards.H
index 640cdfa94..d6c644aa3 100644
--- a/Source/QED/BreitWheelerEngineInnards.H
+++ b/Source/QED/BreitWheelerEngineInnards.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_breit_wheeler_engine_innards_h_
#define WARPX_breit_wheeler_engine_innards_h_
diff --git a/Source/QED/BreitWheelerEngineTableBuilder.H b/Source/QED/BreitWheelerEngineTableBuilder.H
index e30b82208..98b0b17a4 100644
--- a/Source/QED/BreitWheelerEngineTableBuilder.H
+++ b/Source/QED/BreitWheelerEngineTableBuilder.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_breit_wheeler_engine_table_builder_h_
#define WARPX_breit_wheeler_engine_table_builder_h_
diff --git a/Source/QED/BreitWheelerEngineTableBuilder.cpp b/Source/QED/BreitWheelerEngineTableBuilder.cpp
index 3326d5b59..7cb41f7ea 100644
--- a/Source/QED/BreitWheelerEngineTableBuilder.cpp
+++ b/Source/QED/BreitWheelerEngineTableBuilder.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "BreitWheelerEngineTableBuilder.H"
//Include the full Breit Wheeler engine with table generation support
diff --git a/Source/QED/BreitWheelerEngineWrapper.H b/Source/QED/BreitWheelerEngineWrapper.H
index 369c64375..102d15efa 100644
--- a/Source/QED/BreitWheelerEngineWrapper.H
+++ b/Source/QED/BreitWheelerEngineWrapper.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_breit_wheeler_engine_wrapper_h_
#define WARPX_breit_wheeler_engine_wrapper_h_
diff --git a/Source/QED/BreitWheelerEngineWrapper.cpp b/Source/QED/BreitWheelerEngineWrapper.cpp
index c963d44d1..e1eb55714 100644
--- a/Source/QED/BreitWheelerEngineWrapper.cpp
+++ b/Source/QED/BreitWheelerEngineWrapper.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "BreitWheelerEngineWrapper.H"
#include "QedTableParserHelperFunctions.H"
diff --git a/Source/QED/QedChiFunctions.H b/Source/QED/QedChiFunctions.H
index dd8ffac0e..bdeb6df57 100644
--- a/Source/QED/QedChiFunctions.H
+++ b/Source/QED/QedChiFunctions.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_amrex_qed_chi_functions_h_
#define WARPX_amrex_qed_chi_functions_h_
diff --git a/Source/QED/QedTableParserHelperFunctions.H b/Source/QED/QedTableParserHelperFunctions.H
index 528613727..dd66f626f 100644
--- a/Source/QED/QedTableParserHelperFunctions.H
+++ b/Source/QED/QedTableParserHelperFunctions.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_amrex_qed_table_parser_helper_functions_h_
#define WARPX_amrex_qed_table_parser_helper_functions_h_
diff --git a/Source/QED/QedWrapperCommons.H b/Source/QED/QedWrapperCommons.H
index 210e7247e..1d4500a81 100644
--- a/Source/QED/QedWrapperCommons.H
+++ b/Source/QED/QedWrapperCommons.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_amrex_qed_wrapper_commons_h_
#define WARPX_amrex_qed_wrapper_commons_h_
diff --git a/Source/QED/QuantumSyncDummyTable.H b/Source/QED/QuantumSyncDummyTable.H
index 587e8b546..f34c521a3 100644
--- a/Source/QED/QuantumSyncDummyTable.H
+++ b/Source/QED/QuantumSyncDummyTable.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_quantum_sync_dummy_tables_h_
#define WARPX_quantum_sync_dummy_tables_h_
diff --git a/Source/QED/QuantumSyncEngineInnards.H b/Source/QED/QuantumSyncEngineInnards.H
index 6206b103a..64e67690a 100644
--- a/Source/QED/QuantumSyncEngineInnards.H
+++ b/Source/QED/QuantumSyncEngineInnards.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_quantum_sync_engine_innards_h_
#define WARPX_quantum_sync_engine_innards_h_
diff --git a/Source/QED/QuantumSyncEngineTableBuilder.H b/Source/QED/QuantumSyncEngineTableBuilder.H
index e70f5d02f..16be2d5eb 100644
--- a/Source/QED/QuantumSyncEngineTableBuilder.H
+++ b/Source/QED/QuantumSyncEngineTableBuilder.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_quantum_sync_engine_table_builder_h_
#define WARPX_quantum_sync_engine_table_builder_h_
diff --git a/Source/QED/QuantumSyncEngineTableBuilder.cpp b/Source/QED/QuantumSyncEngineTableBuilder.cpp
index 51c3720f2..c4e500122 100644
--- a/Source/QED/QuantumSyncEngineTableBuilder.cpp
+++ b/Source/QED/QuantumSyncEngineTableBuilder.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "QuantumSyncEngineTableBuilder.H"
//Include the full Quantum Synchrotron engine with table generation support
diff --git a/Source/QED/QuantumSyncEngineWrapper.H b/Source/QED/QuantumSyncEngineWrapper.H
index df0bdc5f5..e1e3d94eb 100644
--- a/Source/QED/QuantumSyncEngineWrapper.H
+++ b/Source/QED/QuantumSyncEngineWrapper.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_quantum_sync_engine_wrapper_h_
#define WARPX_quantum_sync_engine_wrapper_h_
diff --git a/Source/QED/QuantumSyncEngineWrapper.cpp b/Source/QED/QuantumSyncEngineWrapper.cpp
index ffafec761..b185251d8 100644
--- a/Source/QED/QuantumSyncEngineWrapper.cpp
+++ b/Source/QED/QuantumSyncEngineWrapper.cpp
@@ -1,3 +1,9 @@
+/* Copyright 2019 Luca Fedeli, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include "QuantumSyncEngineWrapper.H"
#include "QedTableParserHelperFunctions.H"
diff --git a/Source/Utils/IonizationEnergiesTable.H b/Source/Utils/IonizationEnergiesTable.H
index 47b71e4f1..f910fa4fe 100644
--- a/Source/Utils/IonizationEnergiesTable.H
+++ b/Source/Utils/IonizationEnergiesTable.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
// This script was automatically generated!
// Edit dev/Source/Utils/write_atomic_data_cpp.py instead!
#ifndef WARPX_IONIZATION_TABLE_H_
diff --git a/Source/Utils/NCIGodfreyTables.H b/Source/Utils/NCIGodfreyTables.H
index 708215c77..0403b10c3 100644
--- a/Source/Utils/NCIGodfreyTables.H
+++ b/Source/Utils/NCIGodfreyTables.H
@@ -1,3 +1,9 @@
+/* Copyright 2019 Maxence Thevenet
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <AMReX_AmrCore.H>
#ifndef WARPX_GODFREY_COEFF_TABLE_H_
diff --git a/Source/Utils/WarpXAlgorithmSelection.H b/Source/Utils/WarpXAlgorithmSelection.H
index 7d26e7af5..919428704 100644
--- a/Source/Utils/WarpXAlgorithmSelection.H
+++ b/Source/Utils/WarpXAlgorithmSelection.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 David Grote, Luca Fedeli, Remi Lehe
+ * Yinjian Zhao
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef UTILS_WARPXALGORITHMSELECTION_H_
#define UTILS_WARPXALGORITHMSELECTION_H_
diff --git a/Source/Utils/WarpXAlgorithmSelection.cpp b/Source/Utils/WarpXAlgorithmSelection.cpp
index 08272089e..f6e2405a9 100644
--- a/Source/Utils/WarpXAlgorithmSelection.cpp
+++ b/Source/Utils/WarpXAlgorithmSelection.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019-2020 Axel Huebl, David Grote, Luca Fedeli
+ * Remi Lehe, Weiqun Zhang, Yinjian Zhao
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpXAlgorithmSelection.H>
#include <map>
diff --git a/Source/Utils/WarpXConst.H b/Source/Utils/WarpXConst.H
index 70436cb72..34e08118d 100644
--- a/Source/Utils/WarpXConst.H
+++ b/Source/Utils/WarpXConst.H
@@ -1,3 +1,10 @@
+/* Copyright 2019 Andrew Myers, Luca Fedeli, Maxence Thevenet
+ * Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_CONST_H_
#define WARPX_CONST_H_
diff --git a/Source/Utils/WarpXMovingWindow.cpp b/Source/Utils/WarpXMovingWindow.cpp
index c577da7f3..f6cd6de20 100644
--- a/Source/Utils/WarpXMovingWindow.cpp
+++ b/Source/Utils/WarpXMovingWindow.cpp
@@ -1,4 +1,14 @@
+/* Copyright 2019-2020 Andrew Myers, Axel Huebl, Maxence Thevenet
+ * Remi Lehe, Revathi Jambunathan, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#include "GuardCellManager.H"
#include <WarpX.H>
+#include <WarpXUtil.H>
#include <WarpXConst.H>
using namespace amrex;
@@ -28,6 +38,9 @@ WarpX::MoveWindow (bool move_j)
{
if (do_moving_window == 0) return 0;
+ IntVect ng_extra = guard_cells.ng_Extra;
+ IntVect ng_zero = IntVect::TheZeroVector();
+
// Update the continuous position of the moving window,
// and of the plasma injection
moving_window_x += moving_window_v * dt[0];
@@ -97,34 +110,49 @@ WarpX::MoveWindow (bool move_j)
// Shift each component of vector fields (E, B, j)
for (int dim = 0; dim < 3; ++dim) {
-
// Fine grid
- shiftMF(*Bfield_fp[lev][dim], geom[lev], num_shift, dir, B_external_grid[dim]);
- shiftMF(*Efield_fp[lev][dim], geom[lev], num_shift, dir, E_external_grid[dim]);
+ ParserWrapper *Bfield_parser;
+ ParserWrapper *Efield_parser;
+ bool use_Bparser = false;
+ bool use_Eparser = false;
+ if (B_ext_grid_s == "parse_b_ext_grid_function") {
+ use_Bparser = true;
+ if (dim == 0) Bfield_parser = Bxfield_parser.get();
+ if (dim == 1) Bfield_parser = Byfield_parser.get();
+ if (dim == 2) Bfield_parser = Bzfield_parser.get();
+ }
+ if (E_ext_grid_s == "parse_e_ext_grid_function") {
+ use_Eparser = true;
+ if (dim == 0) Efield_parser = Exfield_parser.get();
+ if (dim == 1) Efield_parser = Eyfield_parser.get();
+ if (dim == 2) Efield_parser = Ezfield_parser.get();
+ }
+ shiftMF(*Bfield_fp[lev][dim], geom[lev], num_shift, dir, ng_extra, B_external_grid[dim], use_Bparser, Bfield_parser);
+ shiftMF(*Efield_fp[lev][dim], geom[lev], num_shift, dir, ng_extra, E_external_grid[dim], use_Eparser, Efield_parser);
if (move_j) {
- shiftMF(*current_fp[lev][dim], geom[lev], num_shift, dir);
+ shiftMF(*current_fp[lev][dim], geom[lev], num_shift, dir, ng_zero);
}
if (do_pml && pml[lev]->ok()) {
const std::array<MultiFab*, 3>& pml_B = pml[lev]->GetB_fp();
const std::array<MultiFab*, 3>& pml_E = pml[lev]->GetE_fp();
- shiftMF(*pml_B[dim], geom[lev], num_shift, dir);
- shiftMF(*pml_E[dim], geom[lev], num_shift, dir);
+ shiftMF(*pml_B[dim], geom[lev], num_shift, dir, ng_extra);
+ shiftMF(*pml_E[dim], geom[lev], num_shift, dir, ng_extra);
}
if (lev > 0) {
- // Coarse grid
- shiftMF(*Bfield_cp[lev][dim], geom[lev-1], num_shift_crse, dir, B_external_grid[dim]);
- shiftMF(*Efield_cp[lev][dim], geom[lev-1], num_shift_crse, dir, E_external_grid[dim]);
- shiftMF(*Bfield_aux[lev][dim], geom[lev], num_shift, dir);
- shiftMF(*Efield_aux[lev][dim], geom[lev], num_shift, dir);
+ // coarse grid
+ shiftMF(*Bfield_cp[lev][dim], geom[lev-1], num_shift_crse, dir, ng_zero, B_external_grid[dim], use_Bparser, Bfield_parser);
+ shiftMF(*Efield_cp[lev][dim], geom[lev-1], num_shift_crse, dir, ng_zero, E_external_grid[dim], use_Eparser, Efield_parser);
+ shiftMF(*Bfield_aux[lev][dim], geom[lev], num_shift, dir, ng_zero);
+ shiftMF(*Efield_aux[lev][dim], geom[lev], num_shift, dir, ng_zero);
if (move_j) {
- shiftMF(*current_cp[lev][dim], geom[lev-1], num_shift_crse, dir);
+ shiftMF(*current_cp[lev][dim], geom[lev-1], num_shift_crse, dir, ng_zero);
}
if (do_pml && pml[lev]->ok()) {
const std::array<MultiFab*, 3>& pml_B = pml[lev]->GetB_cp();
const std::array<MultiFab*, 3>& pml_E = pml[lev]->GetE_cp();
- shiftMF(*pml_B[dim], geom[lev-1], num_shift_crse, dir);
- shiftMF(*pml_E[dim], geom[lev-1], num_shift_crse, dir);
+ shiftMF(*pml_B[dim], geom[lev-1], num_shift_crse, dir, ng_extra);
+ shiftMF(*pml_E[dim], geom[lev-1], num_shift_crse, dir, ng_extra);
}
}
}
@@ -132,19 +160,19 @@ WarpX::MoveWindow (bool move_j)
// Shift scalar component F for dive cleaning
if (do_dive_cleaning) {
// Fine grid
- shiftMF(*F_fp[lev], geom[lev], num_shift, dir);
+ shiftMF(*F_fp[lev], geom[lev], num_shift, dir, ng_zero);
if (do_pml && pml[lev]->ok()) {
MultiFab* pml_F = pml[lev]->GetF_fp();
- shiftMF(*pml_F, geom[lev], num_shift, dir);
+ shiftMF(*pml_F, geom[lev], num_shift, dir, ng_extra);
}
if (lev > 0) {
// Coarse grid
- shiftMF(*F_cp[lev], geom[lev-1], num_shift_crse, dir);
+ shiftMF(*F_cp[lev], geom[lev-1], num_shift_crse, dir, ng_zero);
if (do_pml && pml[lev]->ok()) {
MultiFab* pml_F = pml[lev]->GetF_cp();
- shiftMF(*pml_F, geom[lev-1], num_shift_crse, dir);
+ shiftMF(*pml_F, geom[lev-1], num_shift_crse, dir, ng_zero);
}
- shiftMF(*rho_cp[lev], geom[lev-1], num_shift_crse, dir);
+ shiftMF(*rho_cp[lev], geom[lev-1], num_shift_crse, dir, ng_zero);
}
}
@@ -152,10 +180,10 @@ WarpX::MoveWindow (bool move_j)
if (move_j) {
if (rho_fp[lev]){
// Fine grid
- shiftMF(*rho_fp[lev], geom[lev], num_shift, dir);
+ shiftMF(*rho_fp[lev], geom[lev], num_shift, dir, ng_zero);
if (lev > 0){
// Coarse grid
- shiftMF(*rho_cp[lev], geom[lev-1], num_shift_crse, dir);
+ shiftMF(*rho_cp[lev], geom[lev-1], num_shift_crse, dir, ng_zero);
}
}
}
@@ -204,7 +232,8 @@ WarpX::MoveWindow (bool move_j)
void
WarpX::shiftMF (MultiFab& mf, const Geometry& geom, int num_shift, int dir,
- amrex::Real external_field)
+ IntVect ng_extra, amrex::Real external_field, bool useparser,
+ ParserWrapper *field_parser)
{
BL_PROFILE("WarpX::shiftMF()");
const BoxArray& ba = mf.boxArray();
@@ -216,7 +245,16 @@ WarpX::shiftMF (MultiFab& mf, const Geometry& geom, int num_shift, int dir,
MultiFab tmpmf(ba, dm, nc, ng);
MultiFab::Copy(tmpmf, mf, 0, 0, nc, ng);
- tmpmf.FillBoundary(geom.periodicity());
+
+ IntVect ng_mw = IntVect::TheUnitVector();
+ // Enough guard cells in the MW direction
+ ng_mw[dir] = num_shift;
+ // Add the extra cell (if momentum-conserving gather with staggered field solve)
+ ng_mw += ng_extra;
+ // Make sure we don't exceed number of guard cells allocated
+ ng_mw = ng_mw.min(ng);
+ // Fill guard cells.
+ tmpmf.FillBoundary(ng_mw, geom.periodicity());
// Make a box that covers the region that the window moved into
const IndexType& typ = ba.ixType();
@@ -246,20 +284,57 @@ WarpX::shiftMF (MultiFab& mf, const Geometry& geom, int num_shift, int dir,
shiftiv[dir] = num_shift;
Dim3 shift = shiftiv.dim3();
+ const RealBox& real_box = geom.ProbDomain();
+ const auto dx = geom.CellSizeArray();
+
#ifdef _OPENMP
#pragma omp parallel if (Gpu::notInLaunchRegion())
#endif
+
+
for (MFIter mfi(tmpmf); mfi.isValid(); ++mfi )
{
auto const& dstfab = mf.array(mfi);
auto const& srcfab = tmpmf.array(mfi);
const Box& outbox = mfi.fabbox() & adjBox;
+
if (outbox.ok()) {
- AMREX_PARALLEL_FOR_4D ( outbox, nc, i, j, k, n,
- {
- srcfab(i,j,k,n) = external_field;
- });
+ if (useparser == false) {
+ AMREX_PARALLEL_FOR_4D ( outbox, nc, i, j, k, n,
+ {
+ srcfab(i,j,k,n) = external_field;
+ });
+ } else if (useparser == true) {
+ // index type of the src mf
+ auto const& mf_IndexType = (tmpmf).ixType();
+ IntVect mf_type(AMREX_D_DECL(0,0,0));
+ for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
+ mf_type[idim] = mf_IndexType.nodeCentered(idim);
+ }
+
+ amrex::ParallelFor (outbox, nc,
+ [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
+ {
+ // Compute x,y,z co-ordinates based on index type of mf
+ Real fac_x = (1.0 - mf_type[0]) * dx[0]*0.5;
+ Real x = i*dx[0] + real_box.lo(0) + fac_x;
+#if (AMREX_SPACEDIM==2)
+ Real y = 0.0;
+ Real fac_z = (1.0 - mf_type[1]) * dx[1]*0.5;
+ Real z = j*dx[1] + real_box.lo(1) + fac_z;
+#else
+ Real fac_y = (1.0 - mf_type[1]) * dx[1]*0.5;
+ Real y = j*dx[1] + real_box.lo(1) + fac_y;
+ Real fac_z = (1.0 - mf_type[2]) * dx[2]*0.5;
+ Real z = k*dx[2] + real_box.lo(2) + fac_z;
+#endif
+ srcfab(i,j,k,n) = field_parser->getField(x,y,z);
+ }
+ , amrex::Gpu::numThreadsPerBlockParallelFor() * sizeof(double)*4
+ );
+ }
+
}
Box dstBox = mf[mfi].box();
diff --git a/Source/Utils/WarpXTagging.cpp b/Source/Utils/WarpXTagging.cpp
index 91bb802e8..b2ac48e40 100644
--- a/Source/Utils/WarpXTagging.cpp
+++ b/Source/Utils/WarpXTagging.cpp
@@ -1,3 +1,10 @@
+/* Copyright 2019 Axel Huebl, Maxence Thevenet, Weiqun Zhang
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <AMReX_BoxIterator.H>
diff --git a/Source/Utils/WarpXUtil.H b/Source/Utils/WarpXUtil.H
index 195e309cf..9231fa60a 100644
--- a/Source/Utils/WarpXUtil.H
+++ b/Source/Utils/WarpXUtil.H
@@ -1,9 +1,18 @@
+/* Copyright 2019-2020 Andrew Myers, Luca Fedeli, Maxence Thevenet
+ * Revathi Jambunathan, Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_UTILS_H_
#define WARPX_UTILS_H_
#include <AMReX_REAL.H>
#include <AMReX_Vector.H>
#include <AMReX_MultiFab.H>
+#include <AMReX_ParmParse.H>
+#include <WarpXParser.H>
#include <string>
@@ -15,14 +24,108 @@ void ConvertLabParamsToBoost();
void NullifyMF(amrex::MultiFab& mf, int lev, amrex::Real zmin,
amrex::Real zmax);
+/**
+ * \brief Parse a string (typically a mathematical expression) from the
+ * input file and store it into a variable.
+ *
+ * \param ParmParse pp used to read the query_string pp.<function>=string
+ * \param parmparse_string String used to initialize ParmParse
+ * \param query_string ParmParse.query will look for this string
+ * \param stored_string variable in which the string to parse is stored
+ */
+void Store_parserString(amrex::ParmParse &pp, std::string query_string,
+ std::string& stored_string);
+
namespace WarpXUtilIO{
- /**
- * A helper function to write binary data on disk.
- * @param[in] filename where to write
- * @param[in] data Vector containing binary data to write on disk
- * return true if it succeeds, false otherwise
- */
- bool WriteBinaryDataOnFile(std::string filename, const amrex::Vector<char>& data);
+/**
+ * A helper function to write binary data on disk.
+ * @param[in] filename where to write
+ * @param[in] data Vector containing binary data to write on disk
+ * return true if it succeeds, false otherwise
+ */
+bool WriteBinaryDataOnFile(std::string filename, const amrex::Vector<char>& data);
+}
+
+namespace WarpXUtilAlgo{
+
+/** \brief Returns a pointer to the first element in the range [first, last) that is greater than val
+ *
+ * A re-implementation of the upper_bound algorithm suitable for GPU kernels.
+ *
+ * @param first: pointer to left limit of the range to consider
+ * @param last: pointer to right limit of the range to consider
+ * @param val: value to compare the elements of [first, last) to
+ */
+template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+const T* upper_bound(const T* first, const T* last, const T& val)
+{
+ const T* it;
+ size_t count, step;
+ count = last-first;
+ while(count>0){
+ it = first;
+ step = count/2;
+ it += step;
+ if (!(val<*it)){
+ first = ++it;
+ count -= step + 1;
+ }
+ else{
+ count = step;
+ }
+ }
+ return first;
}
+/** \brief Performs a linear interpolation
+ *
+ * Performs a linear interpolation at x given the 2 points
+ * (x0, f0) and (x1, f1)
+ */
+template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+T linear_interp(T x0, T x1, T f0, T f1, T x)
+{
+ return ((x1-x)*f0 + (x-x0)*f1)/(x1-x0);
+}
+
+/** \brief Performs a bilinear interpolation
+ *
+ * Performs a bilinear interpolation at (x,y) given the 4 points
+ * (x0, y0, f00), (x0, y1, f01), (x1, y0, f10), (x1, y1, f11).
+ */
+template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+T bilinear_interp(T x0, T x1, T y0, T y1, T f00, T f01, T f10, T f11, T x, T y)
+{
+ const T fx0 = linear_interp(x0, x1, f00, f10, x);
+ const T fx1 = linear_interp(x0, x1, f01, f11, x);
+ return linear_interp(y0, y1, fx0, fx1, y);
+}
+
+/** \brief Performs a trilinear interpolation
+ *
+ * Performs a trilinear interpolation at (x,y,z) given the 8 points
+ * (x0, y0, z0, f000), (x0, y0, z1, f001), (x0, y1, z0, f010), (x0, y1, z1, f011),
+ * (x1, y0, z0, f100), (x1, y0, z1, f101), (x1, y1, z0, f110), (x1, y1, z1, f111)
+ */
+template<typename T> AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+T trilinear_interp(T x0, T x1,T y0, T y1, T z0, T z1,
+ T f000, T f001, T f010, T f011, T f100, T f101, T f110, T f111,
+ T x, T y, T z)
+{
+ const T fxy0 = bilinear_interp(
+ x0, x1, y0, y1, f000, f010, f100, f110, x, y);
+ const T fxy1 = bilinear_interp(
+ x0, x1, y0, y1, f001, f011, f101, f111, x, y);
+ return linear_interp(z0, z1, fxy0, fxy1, z);
+}
+
+}
+
+/**
+* \brief Initialize a WarpXParser object from a string containing a math expression
+*
+* \param parse_function String to read to initialize the parser.
+*/
+WarpXParser makeParser (std::string const& parse_function);
+
#endif //WARPX_UTILS_H_
diff --git a/Source/Utils/WarpXUtil.cpp b/Source/Utils/WarpXUtil.cpp
index 8764a09c6..983654aed 100644
--- a/Source/Utils/WarpXUtil.cpp
+++ b/Source/Utils/WarpXUtil.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2019-2020 Andrew Myers, Burlen Loring, Luca Fedeli
+ * Maxence Thevenet, Remi Lehe, Revathi Jambunathan
+ * Revathi Jambunathan
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpXUtil.H>
#include <WarpXConst.H>
#include <AMReX_ParmParse.H>
@@ -164,3 +172,45 @@ namespace WarpXUtilIO{
}
}
+void Store_parserString(amrex::ParmParse& pp, std::string query_string,
+ std::string& stored_string)
+{
+
+ char cstr[query_string.size()+1];
+ strcpy(cstr, query_string.c_str());
+
+ std::vector<std::string> f;
+ pp.getarr(cstr, f);
+ stored_string.clear();
+ for (auto const& s : f) {
+ stored_string += s;
+ }
+ f.clear();
+
+}
+
+
+WarpXParser makeParser (std::string const& parse_function)
+{
+ WarpXParser parser(parse_function);
+ parser.registerVariables({"x","y","z","t"});
+ ParmParse pp("my_constants");
+ std::set<std::string> symbols = parser.symbols();
+ symbols.erase("x");
+ symbols.erase("y");
+ symbols.erase("z");
+ symbols.erase("t");
+ 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) {
+ amrex::Abort("makeParser::Unknown symbol "+s);
+ }
+ return parser;
+}
diff --git a/Source/Utils/WarpX_Complex.H b/Source/Utils/WarpX_Complex.H
index 25ed1a53a..cda4204a8 100644
--- a/Source/Utils/WarpX_Complex.H
+++ b/Source/Utils/WarpX_Complex.H
@@ -1,15 +1,23 @@
+/* Copyright 2019-2020 Andrew Myers, David Grote, Maxence Thevenet
+ * Remi Lehe
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_COMPLEX_H_
#define WARPX_COMPLEX_H_
#include <AMReX_REAL.H>
#include <AMReX_Gpu.H>
+#include <AMReX_GpuComplex.H>
+
+#include <complex>
// Define complex type on GPU/CPU
#ifdef AMREX_USE_GPU
-#include <thrust/complex.h>
-
-using Complex = thrust::complex<amrex::Real>;
+using Complex = amrex::GpuComplex<amrex::Real>;
#ifdef WARPX_USE_PSATD
#include <cufft.h>
@@ -19,7 +27,6 @@ static_assert( sizeof(Complex) == sizeof(cuDoubleComplex),
#else
-#include <complex>
using Complex = std::complex<amrex::Real>;
#ifdef WARPX_USE_PSATD
@@ -39,7 +46,7 @@ namespace MathFunc
template<typename T>
AMREX_GPU_HOST_DEVICE T exp (const T& val){
#ifdef AMREX_USE_GPU
- return thrust::exp(val);
+ return amrex::exp(val);
#else
return std::exp(val);
#endif
@@ -49,7 +56,7 @@ namespace MathFunc
template<typename T>
AMREX_GPU_HOST_DEVICE T sqrt (const T& val){
#ifdef AMREX_USE_GPU
- return thrust::sqrt(val);
+ return amrex::sqrt(val);
#else
return std::sqrt(val);
#endif
@@ -59,7 +66,7 @@ namespace MathFunc
template<typename T1, typename T2>
AMREX_GPU_HOST_DEVICE T1 pow (const T1& val, const T2& power){
#ifdef AMREX_USE_GPU
- return thrust::pow(val, power);
+ return amrex::pow(val, power);
#else
return std::pow(val, power);
#endif
diff --git a/Source/Utils/atomic_data.txt b/Source/Utils/atomic_data.txt
index 140f5a26a..cd58e076a 100644
--- a/Source/Utils/atomic_data.txt
+++ b/Source/Utils/atomic_data.txt
@@ -1,3 +1,9 @@
+# Copyright 2019 Maxence Thevenet
+#
+# This file is part of WarpX.
+#
+# License: BSD-3-Clause-LBNL
+
# Reference:
# Kramida, A., Ralchenko, Yu., Reader, J., and NIST ASD Team (2014).
# NIST Atomic Spectra Database (ver. 5.2), [Online].
diff --git a/Source/Utils/utils_ES.F90 b/Source/Utils/utils_ES.F90
index baadeb7af..c11e849eb 100644
--- a/Source/Utils/utils_ES.F90
+++ b/Source/Utils/utils_ES.F90
@@ -1,3 +1,9 @@
+! Copyright 2019 Maxence Thevenet, Remi Lehe
+!
+! This file is part of WarpX.
+!
+! License: BSD-3-Clause-LBNL
+
module warpx_ES_utils
use iso_c_binding
diff --git a/Source/Utils/write_atomic_data_cpp.py b/Source/Utils/write_atomic_data_cpp.py
index 35baf2cdf..12cafad0c 100644
--- a/Source/Utils/write_atomic_data_cpp.py
+++ b/Source/Utils/write_atomic_data_cpp.py
@@ -1,3 +1,10 @@
+# Copyright 2019-2020 Axel Huebl, Luca Fedeli, Maxence Thevenet
+#
+#
+# This file is part of WarpX.
+#
+# License: BSD-3-Clause-LBNL
+
'''
This python script reads ionization tables in atomic_data.txt (generated from
the NIST website) and extracts ionization levels into C++ file
@@ -6,7 +13,6 @@ IonizationEnergiesTable.H, which contains tables + metadata.
import re, os
import numpy as np
-from scipy.constants import e
filename = os.path.join( '.', 'atomic_data.txt' )
with open(filename) as f:
diff --git a/Source/WarpX.H b/Source/WarpX.H
index decde3dc2..ae25a8168 100644
--- a/Source/WarpX.H
+++ b/Source/WarpX.H
@@ -1,3 +1,14 @@
+/* Copyright 2016-2020 Andrew Myers, Ann Almgren, Aurore Blelly
+ * Axel Huebl, Burlen Loring, David Grote
+ * Glenn Richardson, Junmin Gu, Luca Fedeli
+ * Mathieu Lobet, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang, Yinjian Zhao
+ *
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#ifndef WARPX_H_
#define WARPX_H_
@@ -7,6 +18,7 @@
#include <BackTransformedDiagnostic.H>
#include <BilinearFilter.H>
#include <NCIGodfreyFilter.H>
+#include "MultiReducedDiags.H"
#ifdef WARPX_USE_PSATD
# include <SpectralSolver.H>
@@ -24,13 +36,16 @@
#include <AMReX_LayoutData.H>
#include <AMReX_Interpolater.H>
#include <AMReX_FillPatchUtil.H>
+#include <WarpXParserWrapper.H>
+
+#include "GuardCellManager.H"
#ifdef _OPENMP
# include <omp.h>
#endif
#ifdef WARPX_USE_OPENPMD
-#include <WarpXOpenPMD.H>
+# include <WarpXOpenPMD.H>
#endif
#include <iostream>
@@ -62,8 +77,8 @@ public:
WarpX ();
~WarpX ();
- static std::string Version ();
- static std::string PicsarVersion ();
+ static std::string Version (); //! Version of WarpX executable
+ static std::string PicsarVersion (); //! Version of PICSAR dependency
int Verbose () const { return verbose; }
@@ -73,19 +88,42 @@ public:
MultiParticleContainer& GetPartContainer () { return *mypc; }
- static void shiftMF(amrex::MultiFab& mf, const amrex::Geometry& geom, int num_shift, int dir,
- amrex::Real external_field = 0.);
+ static void shiftMF (amrex::MultiFab& mf, const amrex::Geometry& geom,
+ int num_shift, int dir, amrex::IntVect ng_extra,
+ amrex::Real external_field=0.0, bool useparser = false,
+ ParserWrapper *field_parser=nullptr);
static void GotoNextLine (std::istream& is);
- // External fields added to particle fields.
- static amrex::Vector<amrex::Real> B_external_particle;
- static amrex::Vector<amrex::Real> E_external_particle;
+ //! Author of an input file / simulation setup
+ static std::string authors;
// Initial field on the grid.
static amrex::Vector<amrex::Real> E_external_grid;
static amrex::Vector<amrex::Real> B_external_grid;
+ // Initialization Type for External E and B on grid
+ static std::string B_ext_grid_s;
+ static std::string E_ext_grid_s;
+
+ // Parser for B_external on the grid
+ static std::string str_Bx_ext_grid_function;
+ static std::string str_By_ext_grid_function;
+ static std::string str_Bz_ext_grid_function;
+ // Parser for E_external on the grid
+ static std::string str_Ex_ext_grid_function;
+ static std::string str_Ey_ext_grid_function;
+ static std::string str_Ez_ext_grid_function;
+
+ // ParserWrapper for B_external on the grid
+ std::unique_ptr<ParserWrapper> Bxfield_parser;
+ std::unique_ptr<ParserWrapper> Byfield_parser;
+ std::unique_ptr<ParserWrapper> Bzfield_parser;
+ // ParserWrapper for E_external on the grid
+ std::unique_ptr<ParserWrapper> Exfield_parser;
+ std::unique_ptr<ParserWrapper> Eyfield_parser;
+ std::unique_ptr<ParserWrapper> Ezfield_parser;
+
// Algorithms
static long current_deposition_algo;
static long charge_deposition_algo;
@@ -93,6 +131,9 @@ public:
static long particle_pusher_algo;
static int maxwell_fdtd_solver_id;
+ // div E cleaning
+ static int do_dive_cleaning;
+
// Interpolation order
static long nox;
static long noy;
@@ -130,6 +171,8 @@ public:
static int do_subcycling;
+ static bool exchange_all_guard_cells;
+
// buffers
static int n_field_gather_buffer; //! in number of cells from the edge (identical for each dimension)
static int n_current_deposition_buffer; //! in number of cells from the edge (identical for each dimension)
@@ -149,6 +192,9 @@ public:
const amrex::MultiFab& getEfield_fp (int lev, int direction) {return *Efield_fp[lev][direction];}
const amrex::MultiFab& getBfield_fp (int lev, int direction) {return *Bfield_fp[lev][direction];}
+ /** get low-high-low-high-... vector for each direction indicating if mother grid PMLs are enabled */
+ std::vector<bool> getPMLdirections() const;
+
static amrex::MultiFab* getCosts (int lev) {
if (m_instance) {
return m_instance->costs[lev].get();
@@ -167,6 +213,9 @@ public:
amrex::Vector<amrex::Real> mirror_z_width;
amrex::Vector<int> mirror_z_npoints;
+ /// object with all reduced diagnotics, similar to MultiParticleContainer for species.
+ MultiReducedDiags* reduced_diags;
+
void applyMirrors(amrex::Real time);
void ComputeDt ();
@@ -219,12 +268,14 @@ public:
void UpdateAuxilaryDataSameType ();
// Fill boundary cells including coarse/fine boundaries
- void FillBoundaryB ();
- void FillBoundaryE ();
- void FillBoundaryF ();
- void FillBoundaryE (int lev);
- void FillBoundaryB (int lev);
- void FillBoundaryF (int lev);
+ void FillBoundaryB (amrex::IntVect ng, amrex::IntVect ng_extra_fine=amrex::IntVect::TheZeroVector());
+ void FillBoundaryE (amrex::IntVect ng, amrex::IntVect ng_extra_fine=amrex::IntVect::TheZeroVector());
+ void FillBoundaryF (amrex::IntVect ng);
+ void FillBoundaryAux (amrex::IntVect ng);
+ void FillBoundaryE (int lev, amrex::IntVect ng, amrex::IntVect ng_extra_fine=amrex::IntVect::TheZeroVector());
+ void FillBoundaryB (int lev, amrex::IntVect ng, amrex::IntVect ng_extra_fine=amrex::IntVect::TheZeroVector());
+ void FillBoundaryF (int lev, amrex::IntVect ng);
+ void FillBoundaryAux (int lev, amrex::IntVect ng);
void SyncCurrent ();
void SyncRho ();
@@ -241,12 +292,18 @@ public:
int checkInt () const {return check_int;}
int plotInt () const {return plot_int;}
+ int openpmdInt () const {return openpmd_int;}
void WriteCheckPointFile () const;
+ void WriteOpenPMDFile () const;
void WritePlotFile () const;
void UpdateInSitu () const;
void AverageAndPackFields( amrex::Vector<std::string>& varnames,
amrex::Vector<amrex::MultiFab>& mf_avg, const int ngrow) const;
+ void prepareFields( int const step, amrex::Vector<std::string>& varnames,
+ amrex::Vector<amrex::MultiFab>& mf_avg,
+ amrex::Vector<const amrex::MultiFab*>& output_mf,
+ amrex::Vector<amrex::Geometry>& output_geom ) const;
void WritePlotFileES(const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rho,
const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& phi,
@@ -308,6 +365,8 @@ public:
const std::array<const amrex::MultiFab*, 3>& B,
const std::array<amrex::Real,3>& dx, int ngrow);
+ const amrex::IntVect getngE() const { return guard_cells.ng_alloc_EB; };
+ const amrex::IntVect getngF() const { return guard_cells.ng_alloc_F; };
void InitSpaceChargeField (WarpXParticleContainer& pc);
void computePhi (const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& rho,
@@ -321,8 +380,50 @@ public:
const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& phi,
std::array<amrex::Real, 3> const beta = {{0,0,0}} ) const;
+ /**
+ * \brief
+ * This function initializes the E and B fields on each level
+ * using the parser and the user-defined function for the external fields.
+ * The subroutine will parse the x_/y_z_external_grid_function and
+ * then, the B or E multifab is initialized based on the (x,y,z) position
+ * on the staggered yee-grid or cell-centered grid.
+ */
+ void InitializeExternalFieldsOnGridUsingParser (
+ amrex::MultiFab *mfx, amrex::MultiFab *mfy, amrex::MultiFab *mfz,
+ ParserWrapper *xfield_parser, ParserWrapper *yfield_parser,
+ ParserWrapper *zfield_parser, amrex::IntVect x_nodal_flag,
+ amrex::IntVect y_nodal_flag, amrex::IntVect z_nodal_flag,
+ const int lev);
+
protected:
+ /**
+ * \brief
+ * This function initializes E, B, rho, and F, at all the levels
+ * of the multifab. rho and F are initialized with 0.
+ * The E and B fields are initialized using user-defined inputs.
+ * The initialization type is set using "B_ext_grid_init_style"
+ * and "E_ext_grid_init_style". The initialization style is set to "default"
+ * if not explicitly defined by the user, and the E and B fields are
+ * initialized with E_external_grid and B_external_grid, respectively, each with
+ * a default value of 0.
+ * If the initialization type for the E and B field is "constant",
+ * then, the E and B fields at all the levels are initialized with
+ * user-defined values for E_external_grid and B_external_grid.
+ * If the initialization type for B-field is set to
+ * "parse_B_ext_grid_function", then, the parser is used to read
+ * Bx_external_grid_function(x,y,z), By_external_grid_function(x,y,z),
+ * and Bz_external_grid_function(x,y,z).
+ * Similarly, if the E-field initialization type is set to
+ * "parse_E_ext_grid_function", then, the parser is used to read
+ * Ex_external_grid_function(x,y,z), Ey_external_grid_function(x,y,z),
+ * and Ex_external_grid_function(x,y,z). The parser for the E and B
+ * initialization assumes that the function has three independent
+ * variables, at max, namely, x, y, z. However, any number of constants
+ * can be used in the function used to define the E and B fields on the grid.
+ */
+ void InitLevelData (int lev, amrex::Real time);
+
//! Tagging cells for refinement
virtual void ErrorEst (int lev, amrex::TagBoxArray& tags, amrex::Real time, int /*ngrow*/) final;
@@ -358,9 +459,9 @@ private:
///
void EvolveEM(int numsteps);
- void FillBoundaryB (int lev, PatchType patch_type);
- void FillBoundaryE (int lev, PatchType patch_type);
- void FillBoundaryF (int lev, PatchType patch_type);
+ void FillBoundaryB (int lev, PatchType patch_type, amrex::IntVect ng);
+ void FillBoundaryE (int lev, PatchType patch_type, amrex::IntVect ng);
+ void FillBoundaryF (int lev, PatchType patch_type, amrex::IntVect ng);
void OneStep_nosub (amrex::Real t);
void OneStep_sub1 (amrex::Real t);
@@ -410,7 +511,6 @@ private:
void AllocLevelData (int lev, const amrex::BoxArray& new_grids,
const amrex::DistributionMapping& new_dmap);
- void InitLevelData (int lev, amrex::Real time);
void InitFromCheckpoint ();
void PostRestart ();
@@ -449,7 +549,8 @@ private:
void AllocLevelMFs (int lev, const amrex::BoxArray& ba, const amrex::DistributionMapping& dm,
const amrex::IntVect& ngE, const amrex::IntVect& ngJ,
- const amrex::IntVect& ngRho, int ngF);
+ const amrex::IntVect& ngRho, const amrex::IntVect& ngF,
+ const amrex::IntVect& ngextra, const bool aux_is_nodal);
amrex::Vector<int> istep; // which step?
amrex::Vector<int> nsubsteps; // how many substeps on each level?
@@ -499,9 +600,6 @@ private:
amrex::Vector<std::array< std::unique_ptr<amrex::MultiFab>, 3 > > current_buf;
amrex::Vector<std::unique_ptr<amrex::MultiFab> > charge_buf;
- // div E cleaning
- int do_dive_cleaning = 0;
-
// PML
int do_pml = 1;
int pml_ncell = 10;
@@ -551,18 +649,13 @@ private:
int check_int = -1;
int plot_int = -1;
- std::string openpmd_backend {"bp"};
+ std::string openpmd_backend {"default"};
+ int openpmd_int = -1;
+ bool openpmd_tspf = true; //!< one file per timestep (or one file for all steps)
#ifdef WARPX_USE_OPENPMD
- bool dump_plotfiles = false;
- bool dump_openpmd = true;
- bool openpmd_tspf = true; // one file per timestep
- //bool openpmd_tspf = false; // one file all timesteps
WarpXOpenPMDPlot* m_OpenPMDPlotWriter = nullptr;
-
-#else
- bool dump_plotfiles = true;
- bool dump_openpmd = false;
#endif
+
bool plot_rho = false;
bool plot_costs = true;
bool plot_finepatch = false;
@@ -587,6 +680,8 @@ private:
bool is_synchronized = true;
+ guardCellManager guard_cells;
+
//Slice Parameters
int slice_max_grid_size;
int slice_plot_int = -1;
@@ -612,18 +707,19 @@ private:
amrex::Vector< std::unique_ptr<amrex::MultiFab> > rho_cp_fft;
#endif
+ bool fft_hybrid_mpi_decomposition = false;
+ int nox_fft = 16;
+ int noy_fft = 16;
+ int noz_fft = 16;
+
#ifdef WARPX_USE_PSATD
private:
void EvolvePSATD (int numsteps);
void PushPSATD (amrex::Real dt);
void PushPSATD_localFFT (int lev, amrex::Real dt);
- bool fft_hybrid_mpi_decomposition = false;
int ngroups_fft = 4;
int fftw_plan_measure = 1;
- int nox_fft = 16;
- int noy_fft = 16;
- int noz_fft = 16;
amrex::Vector<std::unique_ptr<SpectralSolver>> spectral_solver_fp;
amrex::Vector<std::unique_ptr<SpectralSolver>> spectral_solver_cp;
@@ -665,4 +761,5 @@ private:
int insitu_pin_mesh;
};
+
#endif
diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp
index 377d103d1..d93fab7df 100644
--- a/Source/WarpX.cpp
+++ b/Source/WarpX.cpp
@@ -1,3 +1,14 @@
+/* Copyright 2016-2020 Andrew Myers, Ann Almgren, Aurore Blelly
+ * Axel Huebl, Burlen Loring, David Grote
+ * Glenn Richardson, Jean-Luc Vay, Junmin Gu
+ * Mathieu Lobet, Maxence Thevenet, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang, Yinjian Zhao
+ * levinem
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpX_f.H>
#include <WarpXConst.H>
@@ -24,12 +35,22 @@
using namespace amrex;
-Vector<Real> WarpX::B_external_particle(3, 0.0);
-Vector<Real> WarpX::E_external_particle(3, 0.0);
-
Vector<Real> WarpX::E_external_grid(3, 0.0);
Vector<Real> WarpX::B_external_grid(3, 0.0);
+std::string WarpX::authors = "";
+std::string WarpX::B_ext_grid_s = "default";
+std::string WarpX::E_ext_grid_s = "default";
+
+// Parser for B_external on the grid
+std::string WarpX::str_Bx_ext_grid_function;
+std::string WarpX::str_By_ext_grid_function;
+std::string WarpX::str_Bz_ext_grid_function;
+// Parser for E_external on the grid
+std::string WarpX::str_Ex_ext_grid_function;
+std::string WarpX::str_Ey_ext_grid_function;
+std::string WarpX::str_Ez_ext_grid_function;
+
int WarpX::do_moving_window = 0;
int WarpX::moving_window_dir = -1;
Real WarpX::moving_window_v = std::numeric_limits<amrex::Real>::max();
@@ -45,6 +66,7 @@ long WarpX::charge_deposition_algo;
long WarpX::field_gathering_algo;
long WarpX::particle_pusher_algo;
int WarpX::maxwell_fdtd_solver_id;
+int WarpX::do_dive_cleaning = 0;
long WarpX::n_rz_azimuthal_modes = 1;
long WarpX::ncomps = 1;
@@ -78,6 +100,7 @@ Real WarpX::particle_slice_width_lab = 0.0;
bool WarpX::do_dynamic_scheduling = true;
int WarpX::do_subcycling = 0;
+bool WarpX::exchange_all_guard_cells = 0;
#if (AMREX_SPACEDIM == 3)
IntVect WarpX::Bx_nodal_flag(1,0,0);
@@ -141,7 +164,7 @@ WarpX::WarpX ()
ReadParameters();
#ifdef WARPX_USE_OPENPMD
- m_OpenPMDPlotWriter = new WarpXOpenPMDPlot(openpmd_tspf, openpmd_backend);
+ m_OpenPMDPlotWriter = new WarpXOpenPMDPlot(openpmd_tspf, openpmd_backend, WarpX::getPMLdirections());
#endif
// Geometry on all levels has been defined already.
@@ -178,6 +201,9 @@ WarpX::WarpX ()
}
do_back_transformed_particles = mypc->doBackTransformedDiagnostics();
+ /** create object for reduced diagnostics */
+ reduced_diags = new MultiReducedDiags();
+
Efield_aux.resize(nlevs_max);
Bfield_aux.resize(nlevs_max);
@@ -247,6 +273,25 @@ WarpX::WarpX ()
// at different levels (the stencil depends on c*dt/dz)
nci_godfrey_filter_exeybz.resize(nlevs_max);
nci_godfrey_filter_bxbyez.resize(nlevs_max);
+
+ // Sanity checks. Must be done after calling the MultiParticleContainer
+ // constructor, as it reads additional parameters
+ // (e.g., use_fdtd_nci_corr)
+
+#ifndef WARPX_USE_PSATD
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ not ( do_pml && do_nodal ),
+ "PML + do_nodal for finite-difference not implemented"
+ );
+#endif
+ AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
+ not ( do_dive_cleaning && do_nodal ),
+ "divE cleaning + do_nodal not implemented"
+ );
+#ifdef WARPX_USE_PSATD
+ AMREX_ALWAYS_ASSERT(use_fdtd_nci_corr == 0);
+ AMREX_ALWAYS_ASSERT(do_subcycling == 0);
+#endif
}
WarpX::~WarpX ()
@@ -256,6 +301,8 @@ WarpX::~WarpX ()
ClearLevel(lev);
}
+ delete reduced_diags;
+
#ifdef BL_USE_SENSEI_INSITU
delete insitu_bridge;
#endif
@@ -272,6 +319,7 @@ WarpX::ReadParameters ()
ParmParse pp;// Traditionally, max_step and stop_time do not have prefix.
pp.query("max_step", max_step);
pp.query("stop_time", stop_time);
+ pp.query("authors", authors);
}
{
@@ -293,6 +341,7 @@ WarpX::ReadParameters ()
pp.query("verbose", verbose);
pp.query("regrid_int", regrid_int);
pp.query("do_subcycling", do_subcycling);
+ pp.query("exchange_all_guard_cells", exchange_all_guard_cells);
pp.query("override_sync_int", override_sync_int);
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(do_subcycling != 1 || max_level <= 1,
@@ -306,12 +355,6 @@ WarpX::ReadParameters ()
pp.query("zmax_plasma_to_compute_max_step",
zmax_plasma_to_compute_max_step);
- pp.queryarr("B_external_particle", B_external_particle);
- pp.queryarr("E_external_particle", E_external_particle);
-
- pp.queryarr("E_external_grid", E_external_grid);
- pp.queryarr("B_external_grid", B_external_grid);
-
pp.query("do_moving_window", do_moving_window);
if (do_moving_window)
{
@@ -439,12 +482,11 @@ WarpX::ReadParameters ()
amrex::Abort("J-damping can only be done when PML are inside simulation domain (do_pml_in_domain=1)");
}
- pp.query("dump_openpmd", dump_openpmd);
+ pp.query("openpmd_int", openpmd_int);
pp.query("openpmd_backend", openpmd_backend);
#ifdef WARPX_USE_OPENPMD
pp.query("openpmd_tspf", openpmd_tspf);
#endif
- pp.query("dump_plotfiles", dump_plotfiles);
pp.query("plot_costs", plot_costs);
pp.query("plot_raw_fields", plot_raw_fields);
pp.query("plot_raw_fields_guards", plot_raw_fields_guards);
@@ -633,7 +675,6 @@ WarpX::ReadParameters ()
}
}
-
}
// This is a virtual function.
@@ -717,58 +758,23 @@ WarpX::ClearLevel (int lev)
void
WarpX::AllocLevelData (int lev, const BoxArray& ba, const DistributionMapping& dm)
{
- // When using subcycling, the particles on the fine level perform two pushes
- // before being redistributed ; therefore, we need one extra guard cell
- // (the particles may move by 2*c*dt)
- const int ngx_tmp = (maxLevel() > 0 && do_subcycling == 1) ? WarpX::nox+1 : WarpX::nox;
- const int ngy_tmp = (maxLevel() > 0 && do_subcycling == 1) ? WarpX::noy+1 : WarpX::noy;
- const int ngz_tmp = (maxLevel() > 0 && do_subcycling == 1) ? WarpX::noz+1 : WarpX::noz;
-
- // Ex, Ey, Ez, Bx, By, and Bz have the same number of ghost cells.
- // jx, jy, jz and rho have the same number of ghost cells.
- // E and B have the same number of ghost cells as j and rho if NCI filter is not used,
- // but different number of ghost cells in z-direction if NCI filter is used.
- // The number of cells should be even, in order to easily perform the
- // interpolation from coarse grid to fine grid.
- int ngx = (ngx_tmp % 2) ? ngx_tmp+1 : ngx_tmp; // Always even number
- int ngy = (ngy_tmp % 2) ? ngy_tmp+1 : ngy_tmp; // Always even number
- 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 + NCIGodfreyFilter::m_stencil_width;
- ngz = (ng % 2) ? ng+1 : ng;
- } else {
- ngz = ngz_nonci;
- }
-
- // J is only interpolated from fine to coarse (not coarse to fine)
- // and therefore does not need to be even.
- int ngJx = ngx_tmp;
- int ngJy = ngy_tmp;
- int ngJz = ngz_tmp;
-
- // When calling the moving window (with one level of refinement), we shift
- // the fine grid by 2 cells ; therefore, we need at least 2 guard cells
- // on level 1. This may not be necessary for level 0.
- if (do_moving_window) {
- ngx = std::max(ngx,2);
- ngy = std::max(ngy,2);
- ngz = std::max(ngz,2);
- ngJx = std::max(ngJx,2);
- ngJy = std::max(ngJy,2);
- ngJz = std::max(ngJz,2);
- }
-#if (AMREX_SPACEDIM == 3)
- IntVect ngE(ngx,ngy,ngz);
- IntVect ngJ(ngJx,ngJy,ngJz);
-#elif (AMREX_SPACEDIM == 2)
- IntVect ngE(ngx,ngz);
- IntVect ngJ(ngJx,ngJz);
-#endif
+ bool aux_is_nodal = (field_gathering_algo == GatheringAlgo::MomentumConserving);
- IntVect ngRho = ngJ+1; //One extra ghost cell, so that it's safe to deposit charge density
- // after pushing particle.
+ guard_cells.Init(
+ do_subcycling,
+ WarpX::use_fdtd_nci_corr,
+ do_nodal,
+ do_moving_window,
+ fft_hybrid_mpi_decomposition,
+ aux_is_nodal,
+ moving_window_dir,
+ WarpX::nox,
+ nox_fft, noy_fft, noz_fft,
+ NCIGodfreyFilter::m_stencil_width,
+ maxwell_fdtd_solver_id,
+ maxLevel(),
+ exchange_all_guard_cells);
if (mypc->nSpeciesDepositOnMainGrid() && n_current_deposition_buffer == 0) {
n_current_deposition_buffer = 1;
@@ -779,54 +785,22 @@ WarpX::AllocLevelData (int lev, const BoxArray& ba, const DistributionMapping& d
}
if (n_current_deposition_buffer < 0) {
- n_current_deposition_buffer = ngJ.max();
+ n_current_deposition_buffer = guard_cells.ng_alloc_J.max();
}
if (n_field_gather_buffer < 0) {
// Field gather buffer should be larger than current deposition buffers
n_field_gather_buffer = n_current_deposition_buffer + 1;
}
- int ngF = (do_moving_window) ? 2 : 0;
- // CKC solver requires one additional guard cell
- if (maxwell_fdtd_solver_id == 1) ngF = std::max( ngF, 1 );
-
-#ifdef WARPX_USE_PSATD
- if (fft_hybrid_mpi_decomposition == false){
- // All boxes should have the same number of guard cells
- // (to avoid temporary parallel copies)
- // Thus take the max of the required number of guards for each field
- // Also: the number of guard cell should be enough to contain
- // the stencil of the FFT solver. Here, this number (`ngFFT`)
- // is determined *empirically* to be the order of the solver
- // for nodal, and half the order of the solver for staggered.
- IntVect ngFFT;
- if (do_nodal) {
- ngFFT = IntVect(AMREX_D_DECL(nox_fft, noy_fft, noz_fft));
- } else {
- ngFFT = IntVect(AMREX_D_DECL(nox_fft/2, noy_fft/2, noz_fft/2));
- }
- for (int i_dim=0; i_dim<AMREX_SPACEDIM; i_dim++ ){
- int ng_required = ngFFT[i_dim];
- // Get the max
- ng_required = std::max( ng_required, ngE[i_dim] );
- ng_required = std::max( ng_required, ngJ[i_dim] );
- ng_required = std::max( ng_required, ngRho[i_dim] );
- ng_required = std::max( ng_required, ngF );
- // Set the guard cells to this max
- ngE[i_dim] = ng_required;
- ngJ[i_dim] = ng_required;
- ngRho[i_dim] = ng_required;
- ngF = ng_required;
- }
- }
-#endif
-
- AllocLevelMFs(lev, ba, dm, ngE, ngJ, ngRho, ngF);
+ AllocLevelMFs(lev, ba, dm, guard_cells.ng_alloc_EB, guard_cells.ng_alloc_J,
+ guard_cells.ng_alloc_Rho, guard_cells.ng_alloc_F,
+ guard_cells.ng_Extra, aux_is_nodal);
}
void
WarpX::AllocLevelMFs (int lev, const BoxArray& ba, const DistributionMapping& dm,
- const IntVect& ngE, const IntVect& ngJ, const IntVect& ngRho, int ngF)
+ const IntVect& ngE, const IntVect& ngJ, const IntVect& ngRho,
+ const IntVect& ngF, const IntVect& ngextra, const bool aux_is_nodal)
{
#if defined WARPX_DIM_RZ
@@ -838,9 +812,6 @@ WarpX::AllocLevelMFs (int lev, const BoxArray& ba, const DistributionMapping& dm
ncomps = n_rz_azimuthal_modes*2 - 1;
#endif
- bool aux_is_nodal = (field_gathering_algo == GatheringAlgo::MomentumConserving);
- IntVect ngextra(static_cast<int>(aux_is_nodal and !do_nodal));
-
//
// The fine patch
//
@@ -870,7 +841,7 @@ WarpX::AllocLevelMFs (int lev, const BoxArray& ba, const DistributionMapping& dm
if (do_dive_cleaning)
{
- F_fp[lev].reset (new MultiFab(amrex::convert(ba,IntVect::TheUnitVector()),dm,ncomps, ngF));
+ F_fp[lev].reset (new MultiFab(amrex::convert(ba,IntVect::TheUnitVector()),dm,ncomps, ngF.max()));
}
#ifdef WARPX_USE_PSATD
else
@@ -955,7 +926,7 @@ WarpX::AllocLevelMFs (int lev, const BoxArray& ba, const DistributionMapping& dm
}
if (do_dive_cleaning)
{
- F_cp[lev].reset (new MultiFab(amrex::convert(cba,IntVect::TheUnitVector()),dm,ncomps, ngF));
+ F_cp[lev].reset (new MultiFab(amrex::convert(cba,IntVect::TheUnitVector()),dm,ncomps, ngF.max()));
}
#ifdef WARPX_USE_PSATD
else
@@ -1262,6 +1233,24 @@ WarpX::GetPML (int lev)
}
}
+std::vector< bool >
+WarpX::getPMLdirections() const
+{
+ std::vector< bool > dirsWithPML( 6, false );
+#if AMREX_SPACEDIM!=3
+ dirsWithPML.resize( 4 );
+#endif
+ if( do_pml )
+ {
+ for( auto i = 0u; i < dirsWithPML.size() / 2u; ++i )
+ {
+ dirsWithPML.at( 2u*i ) = bool(do_pml_Lo[i]);
+ dirsWithPML.at( 2u*i + 1u ) = bool(do_pml_Hi[i]);
+ }
+ }
+ return dirsWithPML;
+}
+
void
WarpX::BuildBufferMasks ()
{
@@ -1344,7 +1333,7 @@ WarpX::Version ()
std::string
WarpX::PicsarVersion ()
{
-#ifdef WARPX_GIT_VERSION
+#ifdef PICSAR_GIT_VERSION
return std::string(PICSAR_GIT_VERSION);
#else
return std::string("Unknown");
diff --git a/Source/main.cpp b/Source/main.cpp
index 19413da7a..fc705bdf0 100644
--- a/Source/main.cpp
+++ b/Source/main.cpp
@@ -1,3 +1,11 @@
+/* Copyright 2016-2020 Andrew Myers, Ann Almgren, Axel Huebl
+ * David Grote, Jean-Luc Vay, Remi Lehe
+ * Revathi Jambunathan, Weiqun Zhang
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
#include <WarpX.H>
#include <WarpXUtil.H>