aboutsummaryrefslogtreecommitdiff
path: root/Source/Diagnostics/FieldIO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Diagnostics/FieldIO.cpp')
-rw-r--r--Source/Diagnostics/FieldIO.cpp196
1 files changed, 156 insertions, 40 deletions
diff --git a/Source/Diagnostics/FieldIO.cpp b/Source/Diagnostics/FieldIO.cpp
index b1181f22f..0926a327e 100644
--- a/Source/Diagnostics/FieldIO.cpp
+++ b/Source/Diagnostics/FieldIO.cpp
@@ -189,6 +189,20 @@ WriteOpenPMDFields( const std::string& filename,
}
#endif // WARPX_USE_OPENPMD
+void
+ConstructTotalRZField(std::array< std::unique_ptr<MultiFab>, 3 >& mf_total,
+ const std::array< std::unique_ptr<MultiFab>, 3 >& vector_field)
+{
+ // Sum over the real components, giving quantity at theta=0
+ MultiFab::Copy(*mf_total[0], *vector_field[0], 0, 0, 1, vector_field[0]->nGrowVect());
+ MultiFab::Copy(*mf_total[1], *vector_field[1], 0, 0, 1, vector_field[1]->nGrowVect());
+ MultiFab::Copy(*mf_total[2], *vector_field[2], 0, 0, 1, vector_field[2]->nGrowVect());
+ for (int ic=2 ; ic < vector_field[0]->nComp() ; ic += 2) {
+ MultiFab::Add(*mf_total[0], *vector_field[0], ic, 0, 1, vector_field[0]->nGrowVect());
+ MultiFab::Add(*mf_total[1], *vector_field[1], ic, 0, 1, vector_field[1]->nGrowVect());
+ MultiFab::Add(*mf_total[2], *vector_field[2], ic, 0, 1, vector_field[2]->nGrowVect());
+ }
+}
void
PackPlotDataPtrs (Vector<const MultiFab*>& pmf,
@@ -213,6 +227,7 @@ PackPlotDataPtrs (Vector<const MultiFab*>& pmf,
void
AverageAndPackVectorField( MultiFab& mf_avg,
const std::array< std::unique_ptr<MultiFab>, 3 >& vector_field,
+ const DistributionMapping& dm,
const int dcomp, const int ngrow )
{
// The object below is temporary, and is needed because
@@ -241,23 +256,89 @@ AverageAndPackVectorField( MultiFab& mf_avg,
// - Face centered, in the same way as B on a Yee grid
} else if ( vector_field[0]->is_nodal(0) ){
- PackPlotDataPtrs(srcmf, vector_field);
- amrex::average_face_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
+ // Note that average_face_to_cellcenter operates only on the number of
+ // arrays equal to the number of dimensions. So, for 2D, PackPlotDataPtrs
+ // packs in the x and z (or r and z) arrays, which are then cell averaged.
+ // The Copy code then copies the z from the 2nd to the 3rd field,
+ // and copies over directly the y (or theta) component (which is
+ // already cell centered).
+ if (vector_field[0]->nComp() > 1) {
+ // When there are more than one components, the total
+ // fields needs to be constructed in temporary MultiFabs
+ // Note that mf_total is declared in the same way as
+ // vector_field so that it can be passed into PackPlotDataPtrs.
+ std::array<std::unique_ptr<MultiFab>,3> mf_total;
+ mf_total[0].reset(new MultiFab(vector_field[0]->boxArray(), dm, 1, vector_field[0]->nGrowVect()));
+ mf_total[1].reset(new MultiFab(vector_field[1]->boxArray(), dm, 1, vector_field[1]->nGrowVect()));
+ mf_total[2].reset(new MultiFab(vector_field[2]->boxArray(), dm, 1, vector_field[2]->nGrowVect()));
+ ConstructTotalRZField(mf_total, vector_field);
+ PackPlotDataPtrs(srcmf, mf_total);
+ amrex::average_face_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
+ MultiFab::Copy( mf_avg, *mf_total[1], 0, dcomp+1, 1, ngrow);
+ // Also add the real and imaginary parts of each mode.
+ for (int i=0 ; i < vector_field[0]->nComp() ; i++) {
+ MultiFab v_comp0(*vector_field[0], amrex::make_alias, i, 1);
+ MultiFab v_comp1(*vector_field[1], amrex::make_alias, i, 1);
+ MultiFab v_comp2(*vector_field[2], amrex::make_alias, i, 1);
+ srcmf[0] = &v_comp0;
+ srcmf[1] = &v_comp2;
+ int id = dcomp + 3*(i + 1);
+ amrex::average_face_to_cellcenter( mf_avg, id, srcmf, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, id+1, id+2, 1, ngrow);
+ MultiFab::Copy( mf_avg, v_comp1, 0, id+1, 1, ngrow);
+ }
+ } else {
+ PackPlotDataPtrs(srcmf, vector_field);
+ amrex::average_face_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
#if (AMREX_SPACEDIM == 2)
- MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
- MultiFab::Copy( mf_avg, *vector_field[1], 0, dcomp+1, 1, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
+ MultiFab::Copy( mf_avg, *vector_field[1], 0, dcomp+1, 1, ngrow);
#endif
+ }
// - Edge centered, in the same way as E on a Yee grid
} else if ( !vector_field[0]->is_nodal(0) ){
- PackPlotDataPtrs(srcmf, vector_field);
- amrex::average_edge_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
+ // See comment above, though here, the y (or theta) component
+ // has node centering.
+ if (vector_field[0]->nComp() > 1) {
+ // When there are more than one components, the total
+ // fields needs to be constructed in temporary MultiFabs
+ // Note that mf_total is declared in the same way as
+ // vector_field so that it can be passed into PackPlotDataPtrs.
+ std::array<std::unique_ptr<MultiFab>,3> mf_total;
+ mf_total[0].reset(new MultiFab(vector_field[0]->boxArray(), dm, 1, vector_field[0]->nGrowVect()));
+ mf_total[1].reset(new MultiFab(vector_field[1]->boxArray(), dm, 1, vector_field[1]->nGrowVect()));
+ mf_total[2].reset(new MultiFab(vector_field[2]->boxArray(), dm, 1, vector_field[2]->nGrowVect()));
+ ConstructTotalRZField(mf_total, vector_field);
+ PackPlotDataPtrs(srcmf, mf_total);
+ amrex::average_edge_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
+ amrex::average_node_to_cellcenter( mf_avg, dcomp+1,
+ *mf_total[1], 0, 1, ngrow);
+ // Also add the real and imaginary parts of each mode.
+ for (int i=0 ; i < vector_field[0]->nComp() ; i++) {
+ MultiFab v_comp0(*vector_field[0], amrex::make_alias, i, 1);
+ MultiFab v_comp1(*vector_field[1], amrex::make_alias, i, 1);
+ MultiFab v_comp2(*vector_field[2], amrex::make_alias, i, 1);
+ srcmf[0] = &v_comp0;
+ srcmf[1] = &v_comp2;
+ int id = dcomp + 3*(i + 1);
+ amrex::average_edge_to_cellcenter( mf_avg, id, srcmf, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, id+1, id+2, 1, ngrow);
+ amrex::average_node_to_cellcenter( mf_avg, id+1,
+ v_comp1, 0, 1, ngrow);
+ }
+ } else {
+ PackPlotDataPtrs(srcmf, vector_field);
+ amrex::average_edge_to_cellcenter( mf_avg, dcomp, srcmf, ngrow);
#if (AMREX_SPACEDIM == 2)
- MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
- amrex::average_node_to_cellcenter( mf_avg, dcomp+1,
- *vector_field[1], 0, 1, ngrow);
+ MultiFab::Copy( mf_avg, mf_avg, dcomp+1, dcomp+2, 1, ngrow);
+ amrex::average_node_to_cellcenter( mf_avg, dcomp+1,
+ *vector_field[1], 0, 1, ngrow);
#endif
+ }
} else {
amrex::Abort("Unknown staggering.");
@@ -290,6 +371,33 @@ AverageAndPackScalarField( MultiFab& mf_avg,
}
}
+/** \brief Add variable names to the list.
+ * If there are more that one mode, add the
+ * name of the total field and then the
+ * names of the real and imaginary parts of each
+ * mode.
+ */
+void
+AddToVarNames( Vector<std::string>& varnames,
+ std::string name, std::string suffix,
+ int nmodes ) {
+ auto coords = {"x", "y", "z"};
+ auto coordsRZ = {"r", "theta", "z"};
+ for(auto coord:coords) varnames.push_back(name+coord+suffix);
+ if (nmodes > 1) {
+ // Note that the names are added in the same order as the fields
+ // are packed in AverageAndPackVectorField
+ for (int i = 0 ; i < nmodes ; i++) {
+ for(auto coord:coordsRZ) {
+ varnames.push_back(name + coord + suffix + std::to_string(i) + "_real");
+ }
+ for(auto coord:coordsRZ) {
+ varnames.push_back(name + coord + suffix + std::to_string(i) + "_imag");
+ }
+ }
+ }
+}
+
/** \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.
@@ -298,21 +406,29 @@ void
WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
amrex::Vector<MultiFab>& mf_avg, const int ngrow) const
{
+ // Factor to account for quantities that have multiple components.
+ // If nmodes > 1, allow space for total field and the real and
+ // imaginary part of each node. For now, also include the
+ // imaginary part of mode 0 for code symmetry, even though
+ // it is always zero.
+ int modes_factor = 1;
+ if (nmodes > 1) modes_factor = 2*nmodes + 1;
+
// Count how many different fields should be written (ncomp)
const int ncomp = 0
- + static_cast<int>(plot_E_field)*3
- + static_cast<int>(plot_B_field)*3
- + static_cast<int>(plot_J_field)*3
+ + static_cast<int>(plot_E_field)*3*modes_factor
+ + static_cast<int>(plot_B_field)*3*modes_factor
+ + static_cast<int>(plot_J_field)*3*modes_factor
+ static_cast<int>(plot_part_per_cell)
+ static_cast<int>(plot_part_per_grid)
+ static_cast<int>(plot_part_per_proc)
+ static_cast<int>(plot_proc_number)
+ static_cast<int>(plot_divb)
+ static_cast<int>(plot_dive)
- + static_cast<int>(plot_rho)
- + static_cast<int>(plot_F)
- + static_cast<int>(plot_finepatch)*6
- + static_cast<int>(plot_crsepatch)*6
+ + static_cast<int>(plot_rho)*modes_factor
+ + static_cast<int>(plot_F)*modes_factor
+ + static_cast<int>(plot_finepatch)*6*modes_factor
+ + static_cast<int>(plot_crsepatch)*6*modes_factor
+ static_cast<int>(costs[0] != nullptr);
// Loop over levels of refinement
@@ -325,19 +441,19 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
// add the corresponding names to `varnames` and increment dcomp
int dcomp = 0;
if (plot_J_field) {
- AverageAndPackVectorField(mf_avg[lev], current_fp[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"jx","jy","jz"}) varnames.push_back(name);
- dcomp += 3;
+ AverageAndPackVectorField(mf_avg[lev], current_fp[lev], dmap[lev], dcomp, ngrow);
+ if (lev == 0) AddToVarNames(varnames, "j", "", nmodes);
+ dcomp += 3*modes_factor;
}
if (plot_E_field) {
- AverageAndPackVectorField(mf_avg[lev], Efield_aux[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"Ex","Ey","Ez"}) varnames.push_back(name);
- dcomp += 3;
+ AverageAndPackVectorField(mf_avg[lev], Efield_aux[lev], dmap[lev], dcomp, ngrow);
+ if (lev == 0) AddToVarNames(varnames, "E", "", nmodes);
+ dcomp += 3*modes_factor;
}
if (plot_B_field) {
- AverageAndPackVectorField(mf_avg[lev], Bfield_aux[lev], dcomp, ngrow);
- if(lev==0) for(auto name:{"Bx","By","Bz"}) varnames.push_back(name);
- dcomp += 3;
+ AverageAndPackVectorField(mf_avg[lev], Bfield_aux[lev], dmap[lev], dcomp, ngrow);
+ if (lev == 0) AddToVarNames(varnames, "B", "", nmodes);
+ dcomp += 3*modes_factor;
}
if (plot_part_per_cell)
@@ -444,12 +560,12 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
if (plot_finepatch)
{
- AverageAndPackVectorField( mf_avg[lev], Efield_fp[lev], dcomp, ngrow );
- if(lev==0) for(auto name:{"Ex_fp","Ey_fp","Ez_fp"}) varnames.push_back(name);
- dcomp += 3;
- AverageAndPackVectorField( mf_avg[lev], Bfield_fp[lev], dcomp, ngrow );
- if(lev==0) for(auto name:{"Bx_fp","By_fp","Bz_fp"}) varnames.push_back(name);
- dcomp += 3;
+ AverageAndPackVectorField( mf_avg[lev], Efield_fp[lev], dmap[lev], dcomp, ngrow );
+ if (lev == 0) AddToVarNames(varnames, "E", "_fp", nmodes);
+ dcomp += 3*modes_factor;
+ AverageAndPackVectorField( mf_avg[lev], Bfield_fp[lev], dmap[lev], dcomp, ngrow );
+ if (lev == 0) AddToVarNames(varnames, "B", "_fp", nmodes);
+ dcomp += 3*modes_factor;
}
if (plot_crsepatch)
@@ -462,11 +578,11 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
{
if (do_nodal) amrex::Abort("TODO: do_nodal && plot_crsepatch");
std::array<std::unique_ptr<MultiFab>, 3> E = getInterpolatedE(lev);
- AverageAndPackVectorField( mf_avg[lev], E, dcomp, ngrow );
+ AverageAndPackVectorField( mf_avg[lev], E, dmap[lev], dcomp, ngrow );
}
- if(lev==0) for(auto name:{"Ex_cp","Ey_cp","Ez_cp"}) varnames.push_back(name);
- dcomp += 3;
+ if (lev == 0) AddToVarNames(varnames, "E", "_cp", nmodes);
+ dcomp += 3*modes_factor;
// now the magnetic field
if (lev == 0)
@@ -477,10 +593,10 @@ WarpX::AverageAndPackFields ( Vector<std::string>& varnames,
{
if (do_nodal) amrex::Abort("TODO: do_nodal && plot_crsepatch");
std::array<std::unique_ptr<MultiFab>, 3> B = getInterpolatedB(lev);
- AverageAndPackVectorField( mf_avg[lev], B, dcomp, ngrow );
+ AverageAndPackVectorField( mf_avg[lev], B, dmap[lev], dcomp, ngrow );
}
- if(lev==0) for(auto name:{"Bx_cp","By_cp","Bz_cp"}) varnames.push_back(name);
- dcomp += 3;
+ if (lev == 0) AddToVarNames(varnames, "B", "_cp", nmodes);
+ dcomp += 3*modes_factor;
}
if (costs[0] != nullptr)
@@ -543,8 +659,8 @@ WriteRawField( const MultiFab& F, const DistributionMapping& dm,
VisMF::Write(F, prefix);
} else {
// Copy original MultiFab into one that does not have guard cells
- MultiFab tmpF( F.boxArray(), dm, 1, 0);
- MultiFab::Copy(tmpF, F, 0, 0, 1, 0);
+ MultiFab tmpF( F.boxArray(), dm, F.nComp(), 0);
+ MultiFab::Copy(tmpF, F, 0, 0, F.nComp(), 0);
VisMF::Write(tmpF, prefix);
}
@@ -566,7 +682,7 @@ WriteZeroRawField( const MultiFab& F, const DistributionMapping& dm,
std::string prefix = amrex::MultiFabFileFullPrefix(lev,
filename, level_prefix, field_name);
- MultiFab tmpF(F.boxArray(), dm, 1, ng);
+ MultiFab tmpF(F.boxArray(), dm, F.nComp(), ng);
tmpF.setVal(0.);
VisMF::Write(tmpF, prefix);
}