#include "io_silo.hxx"
#include "driver.hxx"
#include "timer.hxx"
#include <cctk.h>
#include <cctk_Arguments.h>
#include <cctk_Parameters.h>
#include <AMReX.H>
#include <AMReX_IntVect.H>
#include <mpi.h>
#ifdef HAVE_CAPABILITY_Silo
#include <silo.hxx>
#endif
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <regex>
#include <set>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#ifdef HAVE_CAPABILITY_Silo
namespace CarpetX {
using namespace std;
constexpr bool io_verbose = true;
struct mesh_props_t {
amrex::IntVect ngrow;
auto to_tuple() const { return make_tuple(ngrow); }
friend bool operator==(const mesh_props_t &p, const mesh_props_t &q) {
return p.to_tuple() == q.to_tuple();
}
friend bool operator<(const mesh_props_t &p, const mesh_props_t &q) {
return p.to_tuple() < q.to_tuple();
}
};
string make_subdirname(const string &simulation_name, const int iteration) {
ostringstream buf;
buf << simulation_name << ".it" << setw(8) << setfill('0') << iteration << ".silo.dir";
return buf.str();
}
string make_filename(const string &simulation_name, const int iteration,
const int ioserver = -1) {
ostringstream buf;
buf << simulation_name << ".it" << setw(8) << setfill('0') << iteration;
if (ioserver >= 0)
buf << ".p" << setw(6) << setfill('0') << ioserver;
buf << ".silo";
return buf.str();
}
string make_meshname(const int reflevel = -1, const int component = -1) {
assert((reflevel == -1) == (component == -1));
ostringstream buf;
if (reflevel < 0)
buf << "gh";
else
buf << "box" << ".rl" << setw(2) << setfill('0') << reflevel << ".c" << setw(8) << setfill('0') << component;
return DB::legalize_name(buf.str());
}
string make_varname(const int gi, const int vi, const int reflevel = -1,
const int component = -1) {
assert((reflevel == -1) == (component == -1));
string varname;
if (vi < 0) {
assert(0);
char *const groupname = CCTK_GroupName(gi);
varname = groupname;
free(groupname);
} else {
const int v0 = CCTK_FirstVarIndexI(gi);
varname = CCTK_FullVarName(v0 + vi);
varname = regex_replace(varname, regex("::"), "-");
for (auto &ch : varname)
ch = tolower(ch);
}
ostringstream buf;
buf << varname;
if (reflevel >= 0)
buf << ".rl" << setw(2) << setfill('0') << reflevel << ".c" << setw(8) << setfill('0') << component;
return DB::legalize_name(buf.str());
}
const string driver_name = "CarpetX";
string make_fabarraybasename(const int reflevel) {
ostringstream buf;
buf << "FabArrayBase.rl" << setw(2) << setfill('0') << reflevel;
return DB::legalize_name(buf.str());
}
void InputSilo(const cGH *restrict const cctkGH) {
DECLARE_CCTK_ARGUMENTS;
DECLARE_CCTK_PARAMETERS;
int ierr;
static Timer timer("InputSilo");
Interval interval(timer);
static Timer timer_setup("InputSilo.setup");
auto interval_setup = make_unique<Interval>(timer_setup);
const MPI_Comm mpi_comm = MPI_COMM_WORLD;
const int myproc = CCTK_MyProc(cctkGH);
const int nprocs = CCTK_nProcs(cctkGH);
const int ioproc_every = [&]() {
if (CCTK_EQUALS(out_mode, "proc"))
return 1;
if (CCTK_EQUALS(out_mode, "np"))
return out_proc_every;
if (CCTK_EQUALS(out_mode, "onefile"))
return nprocs;
assert(0);
}();
assert(ioproc_every > 0);
const int myioproc = myproc / ioproc_every * ioproc_every;
assert(myioproc <= myproc);
assert(myproc < myioproc + ioproc_every);
const bool read_file = myproc % ioproc_every == 0;
assert((myioproc == myproc) == read_file);
const int metafile_ioproc = 0;
const bool read_metafile = myproc == metafile_ioproc;
DBShowErrors(DB_ALL_AND_DRVR, nullptr);
DBSetCompression("METHOD=GZIP");
DBSetEnableChecksums(1);
const string parfilename = [&]() {
string buf(1024, '\0');
const int len =
CCTK_ParameterFilename(buf.length(), const_cast<char *>(buf.data()));
buf.resize(len);
return buf;
}();
const string simulation_name = in_file;
const string pathname = string(in_dir);
const vector<bool> group_enabled = [&]() {
vector<bool> enabled(CCTK_NumGroups(), false);
const auto callback{
[](const int index, const char *const optstring, void *const arg) {
vector<bool> &enabled = *static_cast<vector<bool> *>(arg);
enabled.at(CCTK_GroupIndexFromVarI(index)) = true;
}};
CCTK_TraverseString(in_silo_vars, callback, &enabled, CCTK_GROUP_OR_VAR);
if (io_verbose) {
const bool have_silo_input = any_of(
group_enabled.begin(), group_enabled.end(), [](bool b) { return b; });
if (have_silo_input) {
CCTK_VINFO("Silo input for groups:");
for (int gi = 0; gi < CCTK_NumGroups(); ++gi) {
if (group_enabled.at(gi)) {
char *const groupname = CCTK_GroupName(gi);
CCTK_VINFO(" %s", groupname);
free(groupname);
}
}
} else {
CCTK_VINFO("No Silo input");
}
}
return enabled;
}();
const auto num_in_vars =
count(group_enabled.begin(), group_enabled.end(), true);
if (num_in_vars == 0)
return;
constexpr int ndims = dim;
interval_setup = nullptr;
static Timer timer_meta("InputSilo.meta");
auto interval_meta = make_unique<Interval>(timer_meta);
if (read_metafile) {
const string metafilename =
pathname + "/" + make_filename(simulation_name, cctk_iteration);
const DB::ptr<DBfile> metafile =
DB::make(DBOpen(metafilename.c_str(), DB_HDF5, DB_READ));
assert(metafile);
{
const string dirname = DB::legalize_name(driver_name);
const int nlevels = [&] {
const string varname = dirname + "/" + DB::legalize_name("nlevels");
const int vartype = DBGetVarType(metafile.get(), varname.c_str());
assert(vartype == DB_INT);
const int varlength = DBGetVarLength(metafile.get(), varname.c_str());
assert(varlength == 1);
int result;
ierr = DBReadVar(metafile.get(), varname.c_str(), &result);
assert(!ierr);
return result;
}();
vector<vector<amrex::Box> > boxes(nlevels);
for (int level = 0; level < nlevels; ++level) {
const string varname = dirname + "/" + make_fabarraybasename(level);
const int vartype = DBGetVarType(metafile.get(), varname.c_str());
assert(vartype == DB_INT);
int vardims[2];
const int varndims =
DBGetVarDims(metafile.get(), varname.c_str(), 2, vardims);
assert(varndims >= 0);
assert(varndims == 2);
assert(vardims[1] == 2 * ndims);
const int nfabs = vardims[0];
assert(nfabs >= 0);
vector<int> data(2 * ndims * nfabs);
ierr = DBReadVar(metafile.get(), varname.c_str(), data.data());
auto &levboxes = boxes.at(level);
levboxes.resize(nfabs);
assert(!ierr);
for (int component = 0; component < nfabs; ++component) {
const amrex::IntVect small(&data.at(2 * ndims * component));
const amrex::IntVect big(&data.at(ndims + 2 * ndims * component));
levboxes.at(component) = amrex::Box(small, big);
}
}
}
}
interval_meta = nullptr;
static Timer timer_data("InputSilo.data");
auto interval_data = make_unique<Interval>(timer_data);
{
DB::ptr<DBfile> file;
if (read_file) {
const string subdirname =
make_subdirname(simulation_name, cctk_iteration);
const string filename =
pathname + "/" + subdirname + "/" +
make_filename(simulation_name, cctk_iteration, myproc / ioproc_every);
file = DB::make(DBOpen(filename.c_str(), DB_HDF5, DB_READ));
assert(file);
}
for (const auto &leveldata : ghext->leveldata) {
if (io_verbose)
CCTK_VINFO("Reading level %d", leveldata.level);
set<mesh_props_t> have_meshes;
for (int gi = 0; gi < CCTK_NumGroups(); ++gi) {
if (!group_enabled.at(gi))
continue;
if (CCTK_GroupTypeI(gi) != CCTK_GF)
continue;
if (io_verbose) {
char *const groupname = CCTK_GroupName(gi);
CCTK_VINFO(" Reading group %s", groupname);
free(groupname);
}
auto &groupdata = *leveldata.groupdata.at(gi);
const int numvars = groupdata.numvars;
const int tl = 0;
amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::IndexType &indextype = mfab.ixType();
const amrex::IntVect &ngrow = mfab.nGrowVect();
const amrex::DistributionMapping &dm = mfab.DistributionMap();
const mesh_props_t mesh_props{ngrow};
const bool have_mesh = have_meshes.count(mesh_props);
const int nfabs = dm.size();
for (int component = 0; component < nfabs; ++component) {
if (io_verbose)
CCTK_VINFO(" Reading component %d", component);
const int proc = dm[component];
const int ioproc = proc / ioproc_every * ioproc_every;
const bool recv_this_fab = proc == myproc;
const bool read_this_fab = ioproc == myproc;
if (!(recv_this_fab || read_this_fab))
continue;
const amrex::Box &fabbox = mfab.fabbox(component);
array<int, ndims> dims;
for (int d = 0; d < ndims; ++d)
dims[d] = fabbox.length(d);
ptrdiff_t zonecount = 1;
for (int d = 0; d < ndims; ++d)
zonecount *= dims[d];
assert(zonecount >= 0 && zonecount <= INT_MAX);
static Timer timer_mpi("InputSilo.mpi");
auto interval_mpi = make_unique<Interval>(timer_mpi);
const int mpi_tag = 22901; vector<double> buffer;
MPI_Request mpi_req;
double *data = nullptr;
if (recv_this_fab && read_this_fab) {
amrex::FArrayBox &fab = mfab[component];
data = fab.dataPtr();
} else if (recv_this_fab) {
amrex::FArrayBox &fab = mfab[component];
assert(numvars * zonecount <= INT_MAX);
MPI_Irecv(fab.dataPtr(), numvars * zonecount, MPI_DOUBLE, ioproc,
mpi_tag, mpi_comm, &mpi_req);
} else {
buffer.resize(numvars * zonecount);
assert(numvars * zonecount <= INT_MAX);
data = buffer.data();
}
interval_mpi = nullptr;
if (read_file) {
static Timer timer_var("InputSilo.var");
Interval interval_var(timer_var);
const string meshname = make_meshname(leveldata.level, component);
const int centering = [&]() {
if (indextype.nodeCentered())
return DB_NODECENT;
if (indextype.cellCentered())
return DB_ZONECENT;
assert(0);
}();
for (int vi = 0; vi < numvars; ++vi) {
const string varname =
make_varname(gi, vi, leveldata.level, component);
if (io_verbose)
CCTK_VINFO(" Reading variable %s", varname.c_str());
const DB::ptr<DBquadvar> quadvar =
DB::make(DBGetQuadvar(file.get(), varname.c_str()));
assert(quadvar);
assert(quadvar->ndims == ndims);
assert(ndims <= 3);
for (int d = 0; d < ndims; ++d)
assert(quadvar->dims[d] == dims[d]);
assert(quadvar->datatype == DB_DOUBLE);
assert(quadvar->centering == centering);
assert(quadvar->nvals == 1);
const int column_major = 0;
assert(quadvar->major_order == column_major);
const void *const read_ptr = quadvar->vals[0];
void *const data_ptr = data + vi * zonecount;
memcpy(data_ptr, read_ptr, zonecount * sizeof(double));
} }
static Timer timer_wait("InputSilo.wait");
auto interval_wait = make_unique<Interval>(timer_wait);
if (recv_this_fab && read_this_fab) {
} else if (recv_this_fab) {
MPI_Wait(&mpi_req, MPI_STATUS_IGNORE);
} else {
buffer.resize(numvars * zonecount);
assert(numvars * zonecount <= INT_MAX);
MPI_Send(buffer.data(), numvars * zonecount, MPI_DOUBLE, proc,
mpi_tag, mpi_comm);
}
if (recv_this_fab)
for (int vi = 0; vi < numvars; ++vi)
groupdata.valid.at(tl).at(vi).set(
valid_t(true), [] { return "read from file"; });
interval_wait = nullptr;
}
} } }
interval_data = nullptr;
}
void OutputSilo(const cGH *restrict const cctkGH) {
DECLARE_CCTK_ARGUMENTS;
DECLARE_CCTK_PARAMETERS;
int ierr;
static Timer timer("OutputSilo");
Interval interval(timer);
static Timer timer_setup("OutputSilo.setup");
auto interval_setup = make_unique<Interval>(timer_setup);
const MPI_Comm mpi_comm = MPI_COMM_WORLD;
const int myproc = CCTK_MyProc(cctkGH);
const int nprocs = CCTK_nProcs(cctkGH);
const int ioproc_every = [&]() {
if (CCTK_EQUALS(out_mode, "proc"))
return 1;
if (CCTK_EQUALS(out_mode, "np"))
return out_proc_every;
if (CCTK_EQUALS(out_mode, "onefile"))
return nprocs;
assert(0);
}();
assert(ioproc_every > 0);
const int myioproc = myproc / ioproc_every * ioproc_every;
assert(myioproc <= myproc);
assert(myproc < myioproc + ioproc_every);
const bool write_file = myproc % ioproc_every == 0;
assert((myioproc == myproc) == write_file);
const int metafile_ioproc = nprocs == 1 || ioproc_every == 1 ? 0 : 1;
const bool write_metafile = myproc == metafile_ioproc;
DBShowErrors(DB_ALL_AND_DRVR, nullptr);
DBSetCompression("METHOD=GZIP");
DBSetEnableChecksums(1);
const string parfilename = [&]() {
string buf(1024, '\0');
const int len =
CCTK_ParameterFilename(buf.length(), const_cast<char *>(buf.data()));
buf.resize(len);
return buf;
}();
const string simulation_name = [&]() {
string name = parfilename;
const size_t last_slash = name.rfind('/');
if (last_slash != string::npos && last_slash < name.length())
name = name.substr(last_slash + 1);
const size_t last_dot = name.rfind('.');
if (last_dot != string::npos && last_dot > 0)
name = name.substr(0, last_dot);
return name;
}();
const vector<bool> group_enabled = [&] {
vector<bool> enabled(CCTK_NumGroups(), false);
const auto callback{
[](const int index, const char *const optstring, void *const arg) {
vector<bool> &enabled = *static_cast<vector<bool> *>(arg);
enabled.at(CCTK_GroupIndexFromVarI(index)) = true;
}};
CCTK_TraverseString(out_silo_vars, callback, &enabled, CCTK_GROUP_OR_VAR);
if (io_verbose) {
CCTK_VINFO("Silo output for groups:");
for (int gi = 0; gi < CCTK_NumGroups(); ++gi) {
if (group_enabled.at(gi)) {
char *const groupname = CCTK_GroupName(gi);
CCTK_VINFO(" %s", groupname);
free(groupname);
}
}
}
return enabled;
}();
const auto num_out_vars =
count(group_enabled.begin(), group_enabled.end(), true);
if (num_out_vars == 0)
return;
constexpr int ndims = dim;
interval_setup = nullptr;
static Timer timer_data("OutputSilo.data");
auto interval_data = make_unique<Interval>(timer_data);
{
static Timer timer_mkdir("OutputSilo.mkdir");
auto interval_mkdir = make_unique<Interval>(timer_mkdir);
const string subdirname = make_subdirname(simulation_name, cctk_iteration);
const string pathname = string(out_dir) + "/" + subdirname;
const int mode = 0755;
static bool did_create_directory = false;
if (!did_create_directory) {
ierr = CCTK_CreateDirectory(mode, out_dir);
assert(ierr >= 0);
did_create_directory = true;
}
ierr = CCTK_CreateDirectory(mode, pathname.c_str());
assert(ierr >= 0);
interval_mkdir = nullptr;
DB::ptr<DBfile> file;
if (write_file) {
const string filename =
pathname + "/" +
make_filename(simulation_name, cctk_iteration, myproc / ioproc_every);
file = DB::make(DBCreate(filename.c_str(), DB_CLOBBER, DB_LOCAL,
simulation_name.c_str(), DB_HDF5));
assert(file);
}
{
const int dims = 1;
const int value = 1;
ierr = DBWrite(file.get(), "MetadataIsTimeVarying", &value, &dims, 1,
DB_INT);
assert(!ierr);
}
for (const auto &leveldata : ghext->leveldata) {
set<mesh_props_t> have_meshes;
for (int gi = 0; gi < CCTK_NumGroups(); ++gi) {
if (!group_enabled.at(gi))
continue;
if (CCTK_GroupTypeI(gi) != CCTK_GF)
continue;
const auto &groupdata = *leveldata.groupdata.at(gi);
const int numvars = groupdata.numvars;
const int tl = 0;
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::IndexType &indextype = mfab.ixType();
const amrex::IntVect &ngrow = mfab.nGrowVect();
const amrex::DistributionMapping &dm = mfab.DistributionMap();
const mesh_props_t mesh_props{ngrow};
const bool have_mesh = have_meshes.count(mesh_props);
const int nfabs = dm.size();
for (int component = 0; component < nfabs; ++component) {
const int proc = dm[component];
const int ioproc = proc / ioproc_every * ioproc_every;
const bool send_this_fab = proc == myproc;
const bool write_this_fab = ioproc == myproc;
if (!(send_this_fab || write_this_fab))
continue;
const amrex::Box &fabbox = mfab.fabbox(component);
array<int, ndims> dims;
for (int d = 0; d < ndims; ++d)
dims[d] = fabbox.length(d);
ptrdiff_t zonecount = 1;
for (int d = 0; d < ndims; ++d)
zonecount *= dims[d];
assert(zonecount >= 0 && zonecount <= INT_MAX);
if (write_file && !have_mesh) {
static Timer timer_mesh("OutputSilo.mesh");
Interval interval_mesh(timer_mesh);
const string meshname = make_meshname(leveldata.level, component);
array<int, ndims> dims_vc;
for (int d = 0; d < ndims; ++d)
dims_vc[d] = dims[d] + int(indextype.cellCentered(d));
const amrex::Geometry &geom = ghext->amrcore->Geom(leveldata.level);
const double *const x0 = geom.ProbLo();
const double *const dx = geom.CellSize();
array<vector<double>, ndims> coords;
for (int d = 0; d < ndims; ++d) {
coords[d].resize(dims_vc[d]);
for (int i = 0; i < dims_vc[d]; ++i)
coords[d][i] = x0[d] + (fabbox.smallEnd(d) + i) * dx[d];
}
array<void *, ndims> coord_ptrs;
for (int d = 0; d < ndims; ++d)
coord_ptrs[d] = coords[d].data();
const DB::ptr<DBoptlist> optlist = DB::make(DBMakeOptlist(10));
assert(optlist);
int cartesian = DB_CARTESIAN;
ierr = DBAddOption(optlist.get(), DBOPT_COORDSYS, &cartesian);
assert(!ierr);
int cycle = cctk_iteration;
ierr = DBAddOption(optlist.get(), DBOPT_CYCLE, &cycle);
assert(!ierr);
array<int, ndims> min_index, max_index;
for (int d = 0; d < ndims; ++d) {
min_index[d] = ngrow[d];
max_index[d] = ngrow[d];
}
ierr =
DBAddOption(optlist.get(), DBOPT_LO_OFFSET, min_index.data());
assert(!ierr);
ierr =
DBAddOption(optlist.get(), DBOPT_HI_OFFSET, max_index.data());
assert(!ierr);
int column_major = 0;
ierr = DBAddOption(optlist.get(), DBOPT_MAJORORDER, &column_major);
assert(!ierr);
double dtime = cctk_time;
ierr = DBAddOption(optlist.get(), DBOPT_DTIME, &dtime);
assert(!ierr);
int hide_from_gui = 1;
ierr =
DBAddOption(optlist.get(), DBOPT_HIDE_FROM_GUI, &hide_from_gui);
assert(!ierr);
ierr = DBPutQuadmesh(file.get(), meshname.c_str(), nullptr,
coord_ptrs.data(), dims_vc.data(), ndims,
DB_DOUBLE, DB_COLLINEAR, optlist.get());
assert(!ierr);
}
static Timer timer_mpi("OutputSilo.mpi");
auto interval_mpi = make_unique<Interval>(timer_mpi);
const int mpi_tag = 22900; vector<double> buffer;
const double *data = nullptr;
if (send_this_fab && write_this_fab) {
const amrex::FArrayBox &fab = mfab[component];
data = fab.dataPtr();
} else if (send_this_fab) {
const amrex::FArrayBox &fab = mfab[component];
assert(numvars * zonecount <= INT_MAX);
MPI_Send(fab.dataPtr(), numvars * zonecount, MPI_DOUBLE, ioproc,
mpi_tag, mpi_comm);
} else {
buffer.resize(numvars * zonecount);
assert(numvars * zonecount <= INT_MAX);
MPI_Recv(buffer.data(), numvars * zonecount, MPI_DOUBLE, proc,
mpi_tag, mpi_comm, MPI_STATUS_IGNORE);
data = buffer.data();
}
interval_mpi = nullptr;
if (write_file) {
static Timer timer_var("OutputSilo.var");
Interval interval_var(timer_var);
const string meshname = make_meshname(leveldata.level, component);
const int centering = [&]() {
if (indextype.nodeCentered())
return DB_NODECENT;
if (indextype.cellCentered())
return DB_ZONECENT;
assert(0);
}();
const DB::ptr<DBoptlist> optlist = DB::make(DBMakeOptlist(10));
assert(optlist);
int cartesian = DB_CARTESIAN;
ierr = DBAddOption(optlist.get(), DBOPT_COORDSYS, &cartesian);
assert(!ierr);
int cycle = cctk_iteration;
ierr = DBAddOption(optlist.get(), DBOPT_CYCLE, &cycle);
assert(!ierr);
int column_major = 0;
ierr = DBAddOption(optlist.get(), DBOPT_MAJORORDER, &column_major);
assert(!ierr);
double dtime = cctk_time;
ierr = DBAddOption(optlist.get(), DBOPT_DTIME, &dtime);
assert(!ierr);
int hide_from_gui = 1;
ierr =
DBAddOption(optlist.get(), DBOPT_HIDE_FROM_GUI, &hide_from_gui);
assert(!ierr);
for (int vi = 0; vi < numvars; ++vi) {
const string varname =
make_varname(gi, vi, leveldata.level, component);
const void *const data_ptr = data + vi * zonecount;
ierr =
DBPutQuadvar1(file.get(), varname.c_str(), meshname.c_str(),
data_ptr, dims.data(), ndims, nullptr, 0,
DB_DOUBLE, centering, optlist.get());
assert(!ierr);
} }
}
} } }
interval_data = nullptr;
static Timer timer_meta("OutputSilo.meta");
auto interval_meta = make_unique<Interval>(timer_meta);
if (write_metafile) {
const string metafilename =
string(out_dir) + "/" + make_filename(simulation_name, cctk_iteration);
const DB::ptr<DBfile> metafile =
DB::make(DBCreate(metafilename.c_str(), DB_CLOBBER, DB_LOCAL,
simulation_name.c_str(), DB_HDF5));
assert(metafile);
{
const int dims = 1;
const int value = 1;
ierr = DBWrite(metafile.get(), "MetadataIsTimeVarying", &value, &dims, 1,
DB_INT);
assert(!ierr);
}
set<mesh_props_t> have_meshes;
for (int gi = 0; gi < CCTK_NumGroups(); ++gi) {
if (!group_enabled.at(gi))
continue;
if (CCTK_GroupTypeI(gi) != CCTK_GF)
continue;
const auto &leveldata0 = ghext->leveldata.at(0);
const auto &groupdata0 = *leveldata0.groupdata.at(gi);
const int numvars = groupdata0.numvars;
const int tl = 0;
const amrex::MultiFab &mfab0 = *groupdata0.mfab[tl];
const amrex::IndexType &indextype = mfab0.ixType();
const amrex::IntVect &ngrow = mfab0.nGrowVect();
const mesh_props_t mesh_props{ngrow};
const bool have_mesh = have_meshes.count(mesh_props);
if (!have_mesh) {
const string multimeshname = make_meshname();
const int nlevels = ghext->leveldata.size();
vector<int> ncomps_level;
for (const auto &leveldata : ghext->leveldata) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::DistributionMapping &dm = mfab.DistributionMap();
const int nfabs = dm.size();
ncomps_level.push_back(nfabs);
}
vector<int> firstcomp_level;
int ncomps_total = 0;
for (const int ncomps : ncomps_level) {
firstcomp_level.push_back(ncomps_total);
ncomps_total += ncomps;
}
const string levelmaps_name = multimeshname + "_wmrgtree_lvlMaps";
{
vector<int> segment_types;
vector<vector<int> > segment_data;
segment_types.reserve(nlevels);
segment_data.reserve(nlevels);
for (int l = 0; l < nlevels; ++l) {
const int comp0 = firstcomp_level.at(l);
const int ncomps = ncomps_level.at(l);
vector<int> data;
data.reserve(ncomps);
for (int c = 0; c < ncomps; ++c)
data.push_back(comp0 + c);
segment_types.push_back(DB_BLOCKCENT);
segment_data.push_back(move(data));
}
vector<int> segment_lengths;
vector<const int *> segment_data_ptrs;
segment_lengths.reserve(segment_data.size());
segment_data_ptrs.reserve(segment_data.size());
for (const auto &data : segment_data) {
segment_lengths.push_back(data.size());
segment_data_ptrs.push_back(data.data());
}
ierr = DBPutGroupelmap(metafile.get(), levelmaps_name.c_str(),
nlevels, segment_types.data(),
segment_lengths.data(), nullptr,
segment_data_ptrs.data(), nullptr, 0, nullptr);
assert(!ierr);
}
const string childmaps_name = multimeshname + "_wmrgtree_chldMaps";
vector<int> num_children;
{
vector<int> segment_types;
vector<vector<int> > segment_data;
segment_types.reserve(ncomps_total);
segment_data.reserve(ncomps_total);
for (const auto &leveldata : ghext->leveldata) {
const int level = leveldata.level;
const int fine_level = level + 1;
if (fine_level < nlevels) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const auto &fine_leveldata = ghext->leveldata.at(fine_level);
const auto &fine_groupdata = *fine_leveldata.groupdata.at(gi);
const amrex::MultiFab &fine_mfab = *fine_groupdata.mfab[tl];
const int ncomps = ncomps_level.at(level);
const int fine_comp0 = firstcomp_level.at(fine_level);
const amrex::BoxArray &fine_boxarray = fine_mfab.boxarray;
for (int component = 0; component < ncomps; ++component) {
const amrex::Box &box = mfab.box(component); amrex::Box refined_box(box);
refined_box.refine(2);
const vector<pair<int, amrex::Box> > child_boxes =
fine_boxarray.intersections(refined_box);
vector<int> children;
children.reserve(child_boxes.size());
for (const auto &ib : child_boxes) {
const int fine_component = ib.first;
children.push_back(fine_comp0 + fine_component);
}
segment_types.push_back(DB_BLOCKCENT);
segment_data.push_back(move(children));
}
} else {
const int ncomps = ncomps_level.at(level);
for (int component = 0; component < ncomps; ++component) {
segment_types.push_back(DB_BLOCKCENT);
segment_data.emplace_back();
}
}
}
vector<int> &segment_lengths = num_children;
vector<const int *> segment_data_ptrs;
segment_lengths.reserve(segment_data.size());
segment_data_ptrs.reserve(segment_data.size());
for (const auto &data : segment_data) {
segment_lengths.push_back(data.size());
segment_data_ptrs.push_back(data.data());
}
ierr = DBPutGroupelmap(metafile.get(), childmaps_name.c_str(),
ncomps_total, segment_types.data(),
segment_lengths.data(), nullptr,
segment_data_ptrs.data(), nullptr, 0, nullptr);
assert(!ierr);
}
{
const int max_mgrtree_children = 2;
const DB::ptr<DBmrgtree> mrgtree = DB::make(
DBMakeMrgtree(DB_MULTIMESH, 0, max_mgrtree_children, nullptr));
assert(mrgtree);
const int max_amr_decomp_children = 2;
ierr = DBAddRegion(mrgtree.get(), "amr_decomp", 0,
max_amr_decomp_children, nullptr, 0, nullptr,
nullptr, nullptr, nullptr);
assert(!ierr);
ierr = DBSetCwr(mrgtree.get(), "amr_decomp");
assert(ierr >= 0);
{
ierr = DBAddRegion(mrgtree.get(), "levels", 0, nlevels, nullptr, 0,
nullptr, nullptr, nullptr, nullptr);
assert(!ierr);
ierr = DBSetCwr(mrgtree.get(), "levels");
assert(ierr >= 0);
const vector<string> region_names{"@level%d@n"};
vector<const char *> region_name_ptrs;
region_name_ptrs.reserve(region_names.size());
for (const string &name : region_names)
region_name_ptrs.push_back(name.c_str());
vector<int> segment_ids;
vector<int> segment_types;
segment_ids.reserve(nlevels);
segment_types.reserve(nlevels);
for (int l = 0; l < nlevels; ++l) {
segment_ids.push_back(l);
segment_types.push_back(DB_BLOCKCENT);
}
ierr = DBAddRegionArray(
mrgtree.get(), nlevels, region_name_ptrs.data(), 0,
levelmaps_name.c_str(), 1, segment_ids.data(),
ncomps_level.data(), segment_types.data(), nullptr);
assert(!ierr);
ierr = DBSetCwr(mrgtree.get(), "..");
assert(ierr >= 0);
}
{
ierr = DBAddRegion(mrgtree.get(), "patches", 0, ncomps_total,
nullptr, 0, nullptr, nullptr, nullptr, nullptr);
assert(ierr >= 0);
ierr = DBSetCwr(mrgtree.get(), "patches");
assert(ierr >= 0);
const vector<string> region_names{"@patch%d@n"};
vector<const char *> region_name_ptrs;
region_name_ptrs.reserve(region_names.size());
for (const string &name : region_names)
region_name_ptrs.push_back(name.c_str());
vector<int> segment_types;
vector<int> segment_ids;
segment_types.reserve(ncomps_total);
segment_ids.reserve(ncomps_total);
for (int c = 0; c < ncomps_total; ++c) {
segment_ids.push_back(c);
segment_types.push_back(DB_BLOCKCENT);
}
ierr = DBAddRegionArray(
mrgtree.get(), ncomps_total, region_name_ptrs.data(), 0,
childmaps_name.c_str(), 1, segment_ids.data(),
num_children.data(), segment_types.data(), nullptr);
ierr = DBSetCwr(mrgtree.get(), "..");
assert(ierr >= 0);
}
{
const vector<string> mrgv_onames{
multimeshname + "_wmrgtree_lvlRatios",
multimeshname + "_wmrgtree_ijkExts",
multimeshname + "_wmrgtree_xyzExts", "rank"};
vector<const char *> mrgv_oname_ptrs;
mrgv_oname_ptrs.reserve(mrgv_onames.size() + 1);
for (const string &name : mrgv_onames)
mrgv_oname_ptrs.push_back(name.c_str());
mrgv_oname_ptrs.push_back(nullptr);
const DB::ptr<DBoptlist> optlist = DB::make(DBMakeOptlist(10));
assert(optlist);
ierr = DBAddOption(optlist.get(), DBOPT_MRGV_ONAMES,
mrgv_oname_ptrs.data());
assert(!ierr);
ierr = DBPutMrgtree(metafile.get(), "mrgTree", "amr_mesh",
mrgtree.get(), optlist.get());
assert(!ierr);
}
}
{
const string levelrationame = multimeshname + "_wmrgtree_lvlRatios";
const vector<string> compnames{"iRatio", "jRatio", "kRatio"};
vector<const char *> compname_ptrs;
compname_ptrs.reserve(compnames.size());
for (const string &name : compnames)
compname_ptrs.push_back(name.c_str());
const vector<string> regionnames{"@level%d@n"};
vector<const char *> regionname_ptrs;
regionname_ptrs.reserve(regionnames.size());
for (const string &name : regionnames)
regionname_ptrs.push_back(name.c_str());
array<vector<int>, ndims> data;
for (int d = 0; d < ndims; ++d) {
data[d].reserve(1);
data[d].push_back(2);
}
array<const void *, ndims> data_ptrs;
for (int d = 0; d < ndims; ++d)
data_ptrs[d] = data[d].data();
ierr = DBPutMrgvar(metafile.get(), levelrationame.c_str(), "mrgTree",
ndims, compname_ptrs.data(), nlevels,
regionname_ptrs.data(), DB_INT, data_ptrs.data(),
nullptr);
assert(!ierr);
}
typedef array<array<int, ndims>, 2> iextent_t;
typedef array<array<double, ndims>, 2> extent_t;
vector<iextent_t> iextents;
vector<extent_t> extents;
iextents.reserve(ncomps_total);
extents.reserve(ncomps_total);
for (const auto &leveldata : ghext->leveldata) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const int tl = 0;
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::Geometry &geom = ghext->amrcore->Geom(leveldata.level);
const double *const x0 = geom.ProbLo();
const double *const dx = geom.CellSize();
const int nfabs = mfab.size();
for (int c = 0; c < nfabs; ++c) {
const amrex::Box &fabbox = mfab.fabbox(c); iextent_t iextent;
extent_t extent;
for (int d = 0; d < ndims; ++d) {
iextent[0][d] = fabbox.smallEnd(d);
iextent[1][d] = fabbox.bigEnd(d);
extent[0][d] = x0[d] + fabbox.smallEnd(d) * dx[d];
extent[1][d] = x0[d] + fabbox.bigEnd(d) * dx[d];
}
iextents.push_back(iextent);
extents.push_back(extent);
}
}
{
const string iextentsname = multimeshname + "_wmrgtree_ijkExts";
const string extentsname = multimeshname + "_wmrgtree_xyzExts";
const vector<string> icompnames{"iMin", "iMax", "jMin",
"jMax", "kMin", "kMax"};
const vector<string> compnames{"xMin", "xMax", "yMin",
"yMax", "zMin", "zMax"};
vector<const char *> icompname_ptrs;
icompname_ptrs.reserve(icompnames.size());
for (const string &name : icompnames)
icompname_ptrs.push_back(name.c_str());
vector<const char *> compname_ptrs;
compname_ptrs.reserve(compnames.size());
for (const string &name : compnames)
compname_ptrs.push_back(name.c_str());
const vector<string> regionnames{"@patch%d@n"};
vector<const char *> regionname_ptrs;
regionname_ptrs.reserve(regionnames.size());
for (const string &name : regionnames)
regionname_ptrs.push_back(name.c_str());
array<array<vector<int>, 2>, ndims> idata;
array<array<vector<double>, 2>, ndims> data;
for (int d = 0; d < ndims; ++d) {
for (int f = 0; f < 2; ++f) {
idata[d][f].reserve(ncomps_total);
data[d][f].reserve(ncomps_total);
}
}
for (int c = 0; c < ncomps_total; ++c) {
for (int d = 0; d < ndims; ++d) {
for (int f = 0; f < 2; ++f) {
idata[d][f].push_back(iextents[c][f][d]);
data[d][f].push_back(extents[c][f][d]);
}
}
}
array<array<const void *, 2>, ndims> idata_ptrs;
array<array<const void *, 2>, ndims> data_ptrs;
for (int d = 0; d < ndims; ++d) {
for (int f = 0; f < 2; ++f) {
idata_ptrs[d][f] = idata[d][f].data();
data_ptrs[d][f] = data[d][f].data();
}
}
ierr = DBPutMrgvar(metafile.get(), iextentsname.c_str(), "mrgTree",
2 * ndims, icompname_ptrs.data(), ncomps_total,
regionname_ptrs.data(), DB_INT, idata_ptrs.data(),
nullptr);
assert(!ierr);
ierr = DBPutMrgvar(metafile.get(), extentsname.c_str(), "mrgTree",
2 * ndims, compname_ptrs.data(), ncomps_total,
regionname_ptrs.data(), DB_DOUBLE,
data_ptrs.data(), nullptr);
assert(!ierr);
const vector<int> ranks(ncomps_total, ndims);
const vector<const void *> rank_ptrs{ranks.data()};
ierr = DBPutMrgvar(metafile.get(), "rank", "mrgTree", 1, nullptr,
ncomps_total, regionname_ptrs.data(), DB_INT,
rank_ptrs.data(), nullptr);
assert(!ierr);
}
vector<string> meshnames;
for (const auto &leveldata : ghext->leveldata) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::DistributionMapping &dm = mfab.DistributionMap();
const int nfabs = dm.size();
for (int c = 0; c < nfabs; ++c) {
const int proc = dm[c];
const string proc_filename =
make_subdirname(simulation_name, cctk_iteration) + "/" +
make_filename(simulation_name, cctk_iteration,
proc / ioproc_every);
const string meshname =
proc_filename + ":" + make_meshname(leveldata.level, c);
meshnames.push_back(meshname);
}
}
vector<const char *> meshname_ptrs;
meshname_ptrs.reserve(meshnames.size());
for (const auto &meshname : meshnames)
meshname_ptrs.push_back(meshname.c_str());
const DB::ptr<DBoptlist> optlist = DB::make(DBMakeOptlist(10));
assert(optlist);
int cycle = cctk_iteration;
ierr = DBAddOption(optlist.get(), DBOPT_CYCLE, &cycle);
assert(!ierr);
double dtime = cctk_time;
ierr = DBAddOption(optlist.get(), DBOPT_DTIME, &dtime);
assert(!ierr);
int quadmesh = DB_QUADMESH;
ierr = DBAddOption(optlist.get(), DBOPT_MB_BLOCK_TYPE, &quadmesh);
assert(!ierr);
int extents_size = 2 * ndims;
ierr = DBAddOption(optlist.get(), DBOPT_EXTENTS_SIZE, &extents_size);
assert(!ierr);
assert(extents.size() == meshname_ptrs.size());
ierr = DBAddOption(optlist.get(), DBOPT_EXTENTS, extents.data());
assert(!ierr);
vector<int> zonecounts;
zonecounts.reserve(meshnames.size());
for (const auto &leveldata : ghext->leveldata) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const int tl = 0;
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const int nfabs = mfab.size();
for (int c = 0; c < nfabs; ++c) {
const amrex::Box &fabbox = mfab.fabbox(c); array<int, ndims> dims_vc;
for (int d = 0; d < ndims; ++d)
dims_vc[d] = fabbox.length(d) + int(indextype.cellCentered(d));
int zonecount = 1;
for (int d = 0; d < ndims; ++d)
zonecount *= dims_vc[d];
zonecounts.push_back(zonecount);
}
}
assert(zonecounts.size() == meshname_ptrs.size());
ierr = DBAddOption(optlist.get(), DBOPT_ZONECOUNTS, zonecounts.data());
assert(!ierr);
const string mrgtreename = "mrgtree";
ierr = DBAddOption(optlist.get(), DBOPT_MRGTREE_NAME,
const_cast<char *>(mrgtreename.c_str()));
assert(!ierr);
ierr = DBPutMultimesh(metafile.get(), multimeshname.c_str(),
meshname_ptrs.size(), meshname_ptrs.data(),
nullptr, optlist.get());
assert(!ierr);
have_meshes.insert(mesh_props);
}
{
const string multimeshname = make_meshname();
const DB::ptr<DBoptlist> optlist = DB::make(DBMakeOptlist(10));
assert(optlist);
int cycle = cctk_iteration;
ierr = DBAddOption(optlist.get(), DBOPT_CYCLE, &cycle);
assert(!ierr);
double dtime = cctk_time;
ierr = DBAddOption(optlist.get(), DBOPT_DTIME, &dtime);
assert(!ierr);
ierr = DBAddOption(optlist.get(), DBOPT_MMESH_NAME,
const_cast<char *>(multimeshname.c_str()));
assert(!ierr);
int vartype_scalar = DB_VARTYPE_SCALAR;
ierr = DBAddOption(optlist.get(), DBOPT_TENSOR_RANK, &vartype_scalar);
assert(!ierr);
int quadvar = DB_QUADVAR;
ierr = DBAddOption(optlist.get(), DBOPT_MB_BLOCK_TYPE, &quadvar);
assert(!ierr);
for (int vi = 0; vi < numvars; ++vi) {
const string multivarname = make_varname(gi, vi);
vector<string> varnames;
for (const auto &leveldata : ghext->leveldata) {
const auto &groupdata = *leveldata.groupdata.at(gi);
const int tl = 0;
const amrex::MultiFab &mfab = *groupdata.mfab[tl];
const amrex::DistributionMapping &dm = mfab.DistributionMap();
const int nfabs = dm.size();
for (int c = 0; c < nfabs; ++c) {
const int proc = dm[c];
const string proc_filename =
make_subdirname(simulation_name, cctk_iteration) + "/" +
make_filename(simulation_name, cctk_iteration,
proc / ioproc_every);
const string varname = proc_filename + ":" +
make_varname(gi, vi, leveldata.level, c);
varnames.push_back(varname);
}
}
vector<const char *> varname_ptrs;
varname_ptrs.reserve(varnames.size());
for (const auto &varname : varnames)
varname_ptrs.push_back(varname.c_str());
ierr = DBPutMultivar(metafile.get(), multivarname.c_str(),
varname_ptrs.size(), varname_ptrs.data(),
nullptr, optlist.get());
assert(!ierr);
} }
}
{
const string dirname = DB::legalize_name(driver_name);
ierr = DBMkDir(metafile.get(), dirname.c_str());
assert(!ierr);
{
const int dims = 1;
const int value = ghext->leveldata.size();
const string varname = dirname + "/" + DB::legalize_name("nlevels");
ierr =
DBWrite(metafile.get(), varname.c_str(), &value, &dims, 1, DB_INT);
assert(!ierr);
}
for (const auto &leveldata : ghext->leveldata) {
const amrex::FabArrayBase &fab = *leveldata.fab;
const int nfabs = fab.size();
vector<int> boxes(2 * ndims * nfabs);
for (int component = 0; component < nfabs; ++component) {
const amrex::Box &fabbox = fab.box(component); for (int d = 0; d < ndims; ++d)
boxes[d + 2 * ndims * component] = fabbox.smallEnd(d);
for (int d = 0; d < ndims; ++d)
boxes[d + ndims + 2 * ndims * component] = fabbox.bigEnd(d);
}
const int dims[2] = {nfabs, 2 * ndims};
const string varname =
dirname + "/" + make_fabarraybasename(leveldata.level);
ierr = DBWrite(metafile.get(), varname.c_str(), boxes.data(), dims, 2,
DB_INT);
assert(!ierr);
}
}
{
const string visitname = [&]() {
ostringstream buf;
buf << out_dir << "/" << simulation_name << ".visit";
return buf.str();
}();
ofstream visit(visitname, ios::app);
assert(visit.good());
visit << make_filename(simulation_name, cctk_iteration) << "\n";
}
}
interval_meta = nullptr;
}
}
#endif