aboutsummaryrefslogtreecommitdiff
path: root/CarpetDev/CarpetIOF5/src/output.cc
diff options
context:
space:
mode:
Diffstat (limited to 'CarpetDev/CarpetIOF5/src/output.cc')
-rw-r--r--CarpetDev/CarpetIOF5/src/output.cc573
1 files changed, 573 insertions, 0 deletions
diff --git a/CarpetDev/CarpetIOF5/src/output.cc b/CarpetDev/CarpetIOF5/src/output.cc
new file mode 100644
index 000000000..0966e5dfb
--- /dev/null
+++ b/CarpetDev/CarpetIOF5/src/output.cc
@@ -0,0 +1,573 @@
+#include <cctk.h>
+#include <cctk_Arguments.h>
+#include <cctk_Parameters.h>
+#include <cctk_Version.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <hdf5.h>
+#include <F5/F5F.h>
+#include <F5/F5R.h>
+#include <F5/F5X.h>
+#include <F5/F5iterate.h>
+#include <F5/F5uniform.h>
+
+#include "CactusBase/IOUtil/src/ioutil_CheckpointRecovery.h"
+
+#include <bbox.hh>
+#include <vect.hh>
+
+#include <carpet.hh>
+
+#include "iof5.hh"
+
+
+
+namespace CarpetIOF5 {
+
+ using namespace std;
+ using namespace Carpet;
+
+
+
+ class output_iterator_t {
+ cGH *const cctkGH;
+
+ bool const is_multipatch;
+
+ string gridname;
+ string chartname;
+ string fragmentname;
+ string topologyname;
+
+ public:
+ output_iterator_t (cGH *const cctkGH_)
+ : cctkGH(cctkGH_),
+ is_multipatch
+ (CCTK_IsFunctionAliased("MultiPatch_GetSystemSpecification"))
+ {
+ }
+
+ void iterate (hid_t const file)
+ {
+ int const rl = 0;
+ ENTER_LEVEL_MODE(cctkGH, rl) {
+ output_simulation (file);
+ } LEAVE_LEVEL_MODE;
+ }
+
+
+
+ private:
+
+ void output_simulation (hid_t const file)
+ {
+ assert (is_level_mode() and reflevel==0);
+ DECLARE_CCTK_ARGUMENTS;
+ indent_t indent;
+
+ gridname = generate_gridname(cctkGH);
+ chartname = generate_chartname(cctkGH);
+
+ cout << indent << "simulation=" << gridname << "\n";
+
+ ivect const reffact = spacereffacts.AT(reflevel);
+ F5Path *const globalpath = F5Rcreate_vertex_refinement3D
+ (file, cctk_time, gridname.c_str(), &v2h(reffact)[0],
+ chartname.c_str());
+
+ // Choose (arbitrarily) the root level as default topology, for
+ // readers which don't understand AMR
+ F5Rlink_default_vertex_topology (globalpath, &v2h(reffact)[0]);
+
+ // Define iteration
+ F5Rset_timestep (globalpath, cctk_iteration);
+
+ // Attach Cactus/Carpet metadata
+ write_metadata (cctkGH, globalpath->Grid_hid);
+
+ // Close topology
+ F5close (globalpath);
+
+ // Iterate over all maps (on the root level)
+ BEGIN_MAP_LOOP(cctkGH, CCTK_GF) {
+ output_map (file);
+ } END_MAP_LOOP;
+ }
+
+
+
+ void output_map (hid_t const file)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ indent_t indent;
+
+ herr_t herr;
+
+ assert (is_singlemap_mode() and reflevel==0);
+
+ cout << indent << "map=" << Carpet::map << "\n";
+
+ fragmentname = generate_fragmentname(cctkGH, Carpet::map);
+
+ // Iterate over all refinement levels of this map
+ int const m = Carpet::map;
+ BEGIN_GLOBAL_MODE(cctkGH) {
+ BEGIN_REFLEVEL_LOOP(cctkGH) {
+ if (vhh.AT(m)->local_components(reflevel) > 0) {
+ // Continue only if this process owns a component of this
+ // map (on this level)
+ ENTER_SINGLEMAP_MODE(cctkGH, m, CCTK_GF) {
+ output_reflevel (file);
+ } LEAVE_SINGLEMAP_MODE;
+ }
+ } END_REFLEVEL_LOOP;
+ } END_GLOBAL_MODE;
+ }
+
+
+
+ void output_reflevel (hid_t const file)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ indent_t indent;
+
+ cout << indent << "reflevel=" << reflevel << "\n";
+
+ ivect const reffact = spacereffacts.AT(reflevel);
+ topologyname = generate_topologyname(cctkGH, Carpet::map, reffact);
+
+ // Define grid hierarchy
+ int const indexdepth = 0; // vertices
+ F5Path *const path =
+ F5Rcreate_coordinate_topology (file, &cctk_time,
+ gridname.c_str(), chartname.c_str(),
+ topologyname.c_str(),
+ indexdepth,
+ dim, dim, &v2h(reffact)[0]);
+
+ // Determine level coordinates
+ ivect gsh;
+ rvect origin, delta;
+ rvect lower, upper;
+ for (int d=0; d<dim; ++d) {
+ gsh[d] = cctk_gsh[d];
+ origin[d] = CCTK_ORIGIN_SPACE(d);
+ delta[d] = CCTK_DELTA_SPACE(d);
+ lower[d] = origin[d];
+ upper[d] = lower[d] + (gsh[d]-1) * delta[d];
+ }
+
+ if (not is_multipatch) {
+ // Define level geometry
+ F5Fwrite_linear (path, FIBER_HDF5_POSITIONS_STRING,
+ dim, &v2h(gsh)[0],
+ F5T_COORD3_DOUBLE,
+ &v2d(lower), &v2d(delta));
+ F5Fset_range (path, &v2d(lower), &v2d(upper));
+ }
+
+ BEGIN_LOCAL_COMPONENT_LOOP (cctkGH, CCTK_GF) {
+ output_component (path);
+ } END_LOCAL_COMPONENT_LOOP;
+
+ // Close topology
+ F5close (path);
+ }
+
+
+
+ void output_component (F5Path *const path)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ indent_t indent;
+
+ cout << indent << "component=" << component << "\n";
+
+ // Determine component coordinates
+ ivect gsh;
+ ivect lbnd, lsh, lghosts, ughosts;
+ rvect origin, delta;
+ rvect clower, cupper;
+ for (int d=0; d<dim; ++d) {
+ gsh[d] = cctk_gsh[d];
+ lbnd[d] = cctk_lbnd[d];
+ lsh[d] = cctk_lsh[d];
+ // F5 counts the total overlap, which is the sum of the ghost
+ // zones on this and the adjacent component
+ lghosts[d] = cctk_bbox[2*d ] ? 0 : 2*cctk_nghostzones[d];
+ ughosts[d] = cctk_bbox[2*d+1] ? 0 : 2*cctk_nghostzones[d];
+ origin[d] = CCTK_ORIGIN_SPACE(d);
+ delta[d] = CCTK_DELTA_SPACE(d);
+ clower[d] = origin[d] + cctk_lbnd[d] * delta[d];
+ cupper[d] = clower[d] + (lsh[d]-1) * delta[d];
+ }
+
+ // Define coordinates
+ if (not is_multipatch) {
+ // (This is redundant, since the level's overall bounding box
+ // was already defined above, but it provides the individual
+ // components' bounding boxes.)
+ F5Fwrite_linear_fraction (path, FIBER_HDF5_POSITIONS_STRING,
+ cctk_dim, &v2h(gsh)[0], &v2h(lsh)[0],
+ F5T_COORD3_DOUBLE,
+ &clower, &delta, &v2h(lbnd)[0],
+ fragmentname.c_str());
+ } else {
+ output_variable (path, CCTK_VarIndex("grid::x"), true);
+ }
+
+ // Output some variables
+ output_variable (path, CCTK_VarIndex("grid::r"));
+
+ output_variable (path, CCTK_VarIndex("grid::x"));
+ output_variable (path, CCTK_VarIndex("grid::y"));
+ output_variable (path, CCTK_VarIndex("grid::z"));
+ }
+
+
+
+ void output_variable (F5Path *const path, int const var,
+ bool const write_positions = false)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+ indent_t indent;
+
+ int ierr;
+
+ assert (var >= 0);
+ {
+ char *const fullname = CCTK_FullName(var);
+ cout << indent << "variable=" << fullname << "\n";
+ free (fullname);
+ }
+
+ int const group = CCTK_GroupIndexFromVarI(var);
+ int const v0 = CCTK_FirstVarIndexI(group);
+
+ cGroup groupdata;
+ ierr = CCTK_GroupData (group, &groupdata);
+ assert (not ierr);
+
+ // TODO
+ assert (groupdata.grouptype == CCTK_GF);
+ assert (groupdata.vartype == CCTK_VARIABLE_REAL);
+ assert (groupdata.disttype == CCTK_DISTRIB_DEFAULT);
+ assert (groupdata.stagtype == 0);
+ assert (groupdata.dim == cctk_dim);
+
+ int const timelevel = 0;
+
+ // Determine component coordinates
+ int const dim = cctk_dim;
+ ivect gsh;
+ ivect lbnd, lsh, lghosts, ughosts;
+ ivect imin, imax, ioff, ilen;
+ ivect const izero(0);
+ for (int d=0; d<dim; ++d) {
+ gsh[d] = cctk_gsh[d];
+ lbnd[d] = cctk_lbnd[d];
+ lsh[d] = cctk_lsh[d];
+ // F5 counts the total overlap, which is the sum of the ghost
+ // zones on this and the adjacent component
+ lghosts[d] = cctk_bbox[2*d ] ? 0 : 2*cctk_nghostzones[d];
+ ughosts[d] = cctk_bbox[2*d+1] ? 0 : 2*cctk_nghostzones[d];
+ imin[d] = 0;
+ imax[d] = lsh[d];
+ if (not output_ghost_points) {
+ imin[d] += lghosts[d] / 2;
+ imax[d] -= ughosts[d] / 2;
+ }
+ ioff[d] = lbnd[d] + imin[d];
+ ilen[d] = imax[d] - imin[d];
+ }
+
+#warning "TODO: Do not output symmetry zones (unless requested by the user)"
+#warning "TODO: Do not output buffer zones (is that easily possible?)"
+
+
+
+ enum tensortype_t {
+ tt_scalar, tt_vector, tt_error
+ };
+
+ tensortype_t tensortype = tt_error;
+
+ int const coordinates_group = CCTK_GroupIndex ("grid::coordinates");
+ assert (coordinates_group >= 0);
+
+ if (group == coordinates_group) {
+
+ // Special case
+ if (var >= v0 and var < v0+dim) {
+ tensortype = tt_vector;
+ } else if (var == v0+dim) {
+ tensortype = tt_scalar;
+ } else {
+ assert (0);
+ }
+
+ } else {
+
+ // TODO: use the tensor type instead
+ switch (groupdata.numvars) {
+ case 1:
+ tensortype = tt_scalar; break;
+ case 3:
+ tensortype = tt_vector; break;
+ default:
+ // fallback: output group as scalars
+ tensortype = tt_scalar; break;
+ }
+
+ }
+
+ if (tensortype != tt_scalar and var != v0) {
+ // TODO: don't do this; instead, keep track of which groups
+ // have been output
+ char *const fullname = CCTK_FullName(var);
+ indent_t indent;
+ cout << indent << "skipping output since it is not the first variable in its group\n";
+ free (fullname);
+ return;
+ }
+
+
+
+ switch (tensortype) {
+
+ case tt_scalar: {
+ // Scalar field
+ CCTK_REAL const *const rdata =
+ (CCTK_REAL const*)CCTK_VarDataPtrI (cctkGH, timelevel, var);
+ assert (rdata);
+
+ int const vartype = CCTK_VarTypeI(var);
+ assert (vartype == CCTK_VARIABLE_REAL);
+ vector<CCTK_REAL> idata (prod(ilen));
+ for (int k=0; k<ilen[2]; ++k) {
+ for (int j=0; j<ilen[1]; ++j) {
+ for (int i=0; i<ilen[0]; ++i) {
+ int const isrc =
+ CCTK_GFINDEX3D(cctkGH, imin[0]+i,imin[1]+j,imin[2]+k);
+ int const idst = i + ilen[0] * (j + ilen[1] * k);
+ idata[idst] = rdata[isrc];
+ }
+ }
+ }
+ void const *const data = &idata.front();
+
+ char *const groupname = CCTK_GroupName(group);
+ char *const fullname = CCTK_FullName(var);
+ // Use the variable name instead of the group name if we may
+ // output several variables per group
+ assert (not write_positions);
+ char const *const name = groupdata.numvars == 1 ? groupname : fullname;
+#if 0
+ F5Fwrite_fraction (path, name,
+ dim,
+ is_multipatch ? NULL : &v2h(gsh)[0], &v2h(lsh)[0],
+ H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE,
+ data,
+ &v2h(lbnd)[0], &v2h(lghosts)[0], &v2h(ughosts)[0],
+ fragmentname.c_str(), H5P_DEFAULT);
+#endif
+ F5Fwrite_fraction (path, name,
+ dim,
+ is_multipatch ? NULL : &v2h(gsh)[0], &v2h(ilen)[0],
+ H5T_NATIVE_DOUBLE, H5T_NATIVE_DOUBLE,
+ data,
+ &v2h(ioff)[0], &v2h(izero)[0], &v2h(izero)[0],
+ fragmentname.c_str(), H5P_DEFAULT);
+ free (groupname);
+ free (fullname);
+ break;
+ }
+
+ case tt_vector: {
+ // Vector field
+ CCTK_REAL const* rdata[cctk_dim];
+ vector<CCTK_REAL> idata[cctk_dim];
+ void const* data[cctk_dim];
+ for (int d=0; d<cctk_dim; ++d) {
+ rdata[d] =
+ (CCTK_REAL const*)CCTK_VarDataPtrI (cctkGH, timelevel, v0+d);
+ assert (rdata[d]);
+
+ int const vartype = CCTK_VarTypeI(var);
+ assert (vartype == CCTK_VARIABLE_REAL);
+ idata[d].resize (prod(ilen));
+ for (int k=0; k<ilen[2]; ++k) {
+ for (int j=0; j<ilen[1]; ++j) {
+ for (int i=0; i<ilen[0]; ++i) {
+ int const isrc =
+ CCTK_GFINDEX3D(cctkGH, imin[0]+i,imin[1]+j,imin[2]+k);
+ int const idst = i + ilen[0] * (j + ilen[1] * k);
+ idata[d][idst] = rdata[d][isrc];
+ }
+ }
+ }
+ data[d] = &idata[d].front();
+
+ }
+ char *const groupname = CCTK_GroupName(group);
+ char const *const name =
+ write_positions ? FIBER_HDF5_POSITIONS_STRING : groupname;
+ hid_t const type =
+ write_positions ? F5T_COORD3_DOUBLE : F5T_VEC3_DOUBLE;
+ int const will_cover_complete_domain = 0;
+#if 0
+ F5FSwrite_fraction (path, name,
+ dim,
+ is_multipatch ? NULL : &v2h(gsh)[0], &v2h(lsh)[0],
+ type, type,
+ data,
+ &v2h(lbnd)[0], &v2h(lghosts)[0], &v2h(ughosts)[0],
+ fragmentname.c_str(), H5P_DEFAULT,
+ will_cover_complete_domain);
+#endif
+ F5FSwrite_fraction (path, name,
+ dim,
+ is_multipatch ? NULL : &v2h(gsh)[0], &v2h(ilen)[0],
+ type, type,
+ data,
+ &v2h(ioff)[0], &v2h(izero)[0], &v2h(izero)[0],
+ fragmentname.c_str(), H5P_DEFAULT,
+ will_cover_complete_domain);
+ free (groupname);
+ break;
+ }
+
+ default:
+ assert (0);
+ }
+ }
+
+ }; // class output_iterator_t
+
+
+
+ void write_metadata (cGH *const cctkGH, hid_t const file)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (cctkGH);
+ assert (file >= 0);
+
+ herr_t herr;
+
+
+ CCTK_INFO ("Writing simulation metadata...");
+
+ // NOTE: We could write the metadata into only one of the process
+ // files (to save space), or write it into a separate metadata
+ // file
+
+ // Create a group to hold all metadata
+ hid_t const group =
+ H5Gcreate (file, metadata_group, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ assert (group >= 0);
+
+ // General information
+ WriteAttribute (group, "Cactus version", CCTK_FullVersion());
+
+ // Unique identifiers
+ if (CCTK_IsFunctionAliased ("UniqueConfigID")) {
+ WriteAttribute
+ (group, "config id", (char const*) UniqueConfigID(cctkGH));
+ }
+ if (CCTK_IsFunctionAliased ("UniqueBuildID")) {
+ WriteAttribute
+ (group, "build id", (char const*) UniqueBuildID(cctkGH));
+ }
+ if (CCTK_IsFunctionAliased ("UniqueSimulationID")) {
+ WriteAttribute
+ (group, "simulation id", (char const*) UniqueSimulationID(cctkGH));
+ }
+ if (CCTK_IsFunctionAliased ("UniqueRunID")) {
+ WriteAttribute
+ (group, "run id", (char const*) UniqueRunID(cctkGH));
+ }
+
+ // Number of I/O processes (i.e. the number of output files)
+ int const nprocs = CCTK_nProcs(cctkGH);
+ int const nioprocs = nprocs;
+ WriteAttribute (group, "nioprocs", nioprocs);
+
+ // Write parameters into a separate dataset (they may be too large
+ // for an attribute)
+ int const get_all = 1;
+ char *const parameters = IOUtil_GetAllParameters (cctkGH, get_all);
+ assert (parameters);
+ WriteLargeAttribute (group, all_parameters, parameters);
+ free (parameters);
+
+ // Grid structure
+ string const gs = serialise_grid_structure (cctkGH);
+ WriteLargeAttribute (group, grid_structure, gs.c_str());
+
+ herr = H5Gclose (group);
+ assert (not herr);
+ }
+
+
+
+ extern "C"
+ void F5_Output (CCTK_ARGUMENTS)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ herr_t herr;
+
+
+
+ assert (is_global_mode());
+ CCTK_VInfo (CCTK_THORNSTRING, "F5_Output: iteration=%d", cctk_iteration);
+
+
+
+ // We don't know how to open multiple files yet
+ assert (strcmp (file_content, "everything") == 0);
+
+ // Open file
+ static bool first_time = true;
+
+ string const basename =
+ generate_basename (cctkGH, CCTK_VarIndex("grid::r"));
+ int const myproc = CCTK_MyProc(cctkGH);
+ int const proc = myproc;
+ string const name =
+ create_filename (cctkGH, basename, proc, first_time);
+
+ indent_t indent;
+ cout << indent << "process=" << proc << "\n";
+
+ bool const truncate_file = first_time and IO_TruncateOutputFiles(cctkGH);
+ hid_t const file =
+ truncate_file ?
+ H5Fcreate (name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT) :
+ H5Fopen (name.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
+ assert (file >= 0);
+ first_time = false;
+
+ // write_metadata (cctkGH, file);
+
+ output_iterator_t iterator(cctkGH);
+ iterator.iterate (file);
+
+ // Close file
+ herr = H5Fclose (file);
+ assert (not herr);
+ }
+
+} // end namespace CarpetIOF5