aboutsummaryrefslogtreecommitdiff
path: root/Carpet/CarpetIOHDF5/src/iohdf5.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Carpet/CarpetIOHDF5/src/iohdf5.cc')
-rw-r--r--Carpet/CarpetIOHDF5/src/iohdf5.cc1181
1 files changed, 1181 insertions, 0 deletions
diff --git a/Carpet/CarpetIOHDF5/src/iohdf5.cc b/Carpet/CarpetIOHDF5/src/iohdf5.cc
new file mode 100644
index 000000000..6a7ba3b46
--- /dev/null
+++ b/Carpet/CarpetIOHDF5/src/iohdf5.cc
@@ -0,0 +1,1181 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+#include <hdf5.h>
+
+#include "cctk.h"
+#include "cctk_Parameters.h"
+
+extern "C" {
+ static const char* rcsid = "$Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetIOHDF5/src/iohdf5.cc,v 1.41 2004/07/09 15:38:18 tradke Exp $";
+ CCTK_FILEVERSION(Carpet_CarpetIOHDF5_iohdf5_cc);
+}
+
+#include "CactusBase/IOUtil/src/ioGH.h"
+#include "CactusBase/IOUtil/src/ioutil_CheckpointRecovery.h"
+
+#include "bbox.hh"
+#include "data.hh"
+#include "gdata.hh"
+#include "ggf.hh"
+#include "vect.hh"
+
+#include "carpet.hh"
+
+#include "iohdf5.hh"
+#include "iohdf5GH.h"
+
+
+namespace CarpetIOHDF5 {
+
+using namespace std;
+using namespace Carpet;
+
+
+// Variable definitions
+vector<bool> do_truncate; // [var]
+vector<vector<vector<int> > > last_output; // [ml][rl][var]
+
+
+void CarpetIOHDF5Startup (void)
+{
+ DECLARE_CCTK_PARAMETERS
+
+
+ CCTK_RegisterBanner ("AMR 3D HDF5 I/O provided by CarpetIOHDF5");
+
+ int GHExtension = CCTK_RegisterGHExtension ("CarpetIOHDF5");
+ CCTK_RegisterGHExtensionSetupGH (GHExtension, SetupGH);
+
+ int IOMethod = CCTK_RegisterIOMethod ("IOHDF5");
+ CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH);
+ CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs);
+ CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput);
+ CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput);
+
+ /* initial I/O parameter check */
+ int numvars = CCTK_NumVars ();
+ vector<bool> flags(numvars);
+
+ if (CCTK_TraverseString (out3D_vars, SetFlag, &flags,CCTK_GROUP_OR_VAR) < 0)
+ {
+ CCTK_VWarn (strict_io_parameter_check ? 0 : 1,
+ __LINE__, __FILE__, CCTK_THORNSTRING,
+ "error while parsing parameter 'IOHDF5::out3D_vars'");
+ }
+
+#if 0
+ // Christian's Recovery routine
+ if ( !(CCTK_Equals(recover,"no")) ) {
+ ierr = IOUtil_RegisterRecover ("CarpetIOHDF5 recovery", Recover);
+ assert (! ierr);
+ } else {
+ // Erik's Recovery routine
+ ierr = IOUtil_RegisterRecover ("CarpetIOHDF5", Recover);
+ assert (! ierr);
+ }
+#else
+ if (IOUtil_RegisterRecover ("CarpetIOHDF5 recovery", Recover) < 0)
+ {
+ CCTK_WARN (1, "Failed to register IOFlexIO recovery routine");
+ }
+#endif
+}
+
+
+
+int CarpetIOHDF5Init (const cGH* const cctkGH)
+{
+ DECLARE_CCTK_ARGUMENTS;
+
+ *this_iteration = -1;
+ *next_output_iteration = 0;
+ *next_output_time = cctk_time;
+
+ return (0);
+}
+
+
+
+void* SetupGH (tFleshConfig* const fc,
+ const int convLevel, cGH* const cctkGH)
+{
+ DECLARE_CCTK_PARAMETERS;
+
+ CarpetIOHDF5GH* myGH;
+
+ const void *dummy;
+ dummy = &fc;
+ dummy = &convLevel;
+ dummy = &cctkGH;
+ dummy = &dummy;
+
+ // Truncate all files if this is not a restart
+ do_truncate.resize(CCTK_NumVars(), true);
+
+ // No iterations have yet been output
+ last_output.resize(mglevels);
+ for (int ml=0; ml<mglevels; ++ml) {
+ last_output.at(ml).resize(maxreflevels);
+ for (int rl=0; rl<maxreflevels; ++rl) {
+ last_output.at(ml).at(rl).resize(CCTK_NumVars(), INT_MIN);
+ }
+ }
+
+ // We register only once, ergo we get only one handle. We store
+ // that statically, so there is no need to pass anything to
+ // Cactus.
+
+ /* allocate a new GH extension structure */
+
+ CCTK_INT numvars = CCTK_NumVars ();
+
+ myGH = (CarpetIOHDF5GH*) malloc (sizeof (CarpetIOHDF5GH));
+ myGH->out_last = (int *) malloc (numvars * sizeof (int));
+ myGH->requests = (ioRequest **) calloc (numvars, sizeof (ioRequest *));
+ myGH->cp_filename_list = (char **) calloc (abs (checkpoint_keep), sizeof (char *));
+ myGH->cp_filename_index = 0;
+ myGH->out_vars = strdup ("");
+ myGH->out_every_default = out_every - 1;
+
+ for (int i = 0; i < numvars; i++)
+ {
+ myGH->out_last [i] = -1;
+ }
+
+ myGH->open_output_files = NULL;
+
+ // Now set hdf5 complex datatypes
+ // Stolen from Thomas Radke
+ HDF5_ERROR (myGH->HDF5_COMPLEX =
+ H5Tcreate (H5T_COMPOUND, sizeof (CCTK_COMPLEX)));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX, "real",
+ offsetof (CCTK_COMPLEX, Re), HDF5_REAL));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX, "imag",
+ offsetof (CCTK_COMPLEX, Im), HDF5_REAL));
+#ifdef CCTK_REAL4
+ HDF5_ERROR (myGH->HDF5_COMPLEX8 =
+ H5Tcreate (H5T_COMPOUND, sizeof (CCTK_COMPLEX8)));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX8, "real",
+ offsetof (CCTK_COMPLEX8, Re), HDF5_REAL4));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX8, "imag",
+ offsetof (CCTK_COMPLEX8, Im), HDF5_REAL4));
+#endif
+#ifdef CCTK_REAL8
+ HDF5_ERROR (myGH->HDF5_COMPLEX16 =
+ H5Tcreate (H5T_COMPOUND, sizeof (CCTK_COMPLEX16)));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX16, "real",
+ offsetof (CCTK_COMPLEX16, Re), HDF5_REAL8));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX16, "imag",
+ offsetof (CCTK_COMPLEX16, Im), HDF5_REAL8));
+#endif
+#ifdef CCTK_REAL16
+ HDF5_ERROR (myGH->HDF5_COMPLEX32 =
+ H5Tcreate (H5T_COMPOUND, sizeof (CCTK_COMPLEX32)));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX32, "real",
+ offsetof (CCTK_COMPLEX32, Re), HDF5_REAL16));
+ HDF5_ERROR (H5Tinsert (myGH->HDF5_COMPLEX32, "imag",
+ offsetof (CCTK_COMPLEX32, Im), HDF5_REAL16));
+#endif
+ return (myGH);
+}
+
+int OutputGH (const cGH* const cctkGH) {
+ for (int vindex=0; vindex<CCTK_NumVars(); ++vindex) {
+ if (TimeToOutput(cctkGH, vindex)) {
+ TriggerOutput(cctkGH, vindex);
+ }
+ }
+ return 0;
+}
+
+
+
+int OutputVarAs (const cGH* const cctkGH, const char* const varname,
+ const char* const alias)
+{
+ DECLARE_CCTK_ARGUMENTS
+ DECLARE_CCTK_PARAMETERS
+
+ int numvars = CCTK_NumVars ();
+ vector<bool> flags (numvars);
+
+ if (CCTK_TraverseString (varname, SetFlag, &flags, CCTK_VAR) < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "error while parsing variable name '%s' (alias name '%s')",
+ varname, alias);
+ return (-1);
+ }
+
+ int vindex = 0;
+ while (! flags.at (vindex) && vindex < numvars) vindex++;
+ if (vindex >= numvars)
+ {
+ return (-1);
+ }
+
+ const int group = CCTK_GroupIndexFromVarI (vindex);
+ assert (group>=0 && group<(int)Carpet::arrdata.size());
+
+ // Check for storage
+ if (! CCTK_QueryGroupStorageI(cctkGH, group))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Cannot output variable '%s' because it has no storage",
+ varname);
+ return (0);
+ }
+
+ const int grouptype = CCTK_GroupTypeI(group);
+ if (grouptype == CCTK_SCALAR || grouptype == CCTK_ARRAY)
+ {
+ assert (do_global_mode);
+ }
+
+ /* get the default I/O request for this variable */
+ ioRequest* request = IOUtil_DefaultIORequest (cctkGH, vindex, 1);
+
+ // Get grid hierarchy extentsion from IOUtil
+ const ioGH * const iogh = (const ioGH *)CCTK_GHExtension (cctkGH, "IO");
+ assert (iogh);
+
+ // Create the output directory
+ const char* myoutdir = out3D_dir;
+ if (CCTK_EQUALS(myoutdir, "")) {
+ myoutdir = out_dir;
+ }
+ if (CCTK_MyProc(cctkGH)==0) {
+ CCTK_CreateDirectory (0755, myoutdir);
+ }
+
+ // Invent a file name
+ ostringstream filenamebuf;
+ filenamebuf << myoutdir << "/" << alias << out3D_extension;
+ string filenamestr = filenamebuf.str();
+ const char * const filename = filenamestr.c_str();
+
+ hid_t writer = -1;
+
+ // Write the file only on the root processor
+ if (CCTK_MyProc (cctkGH) == 0)
+ {
+
+ // If this is the first time, then create and truncate the file
+ if (do_truncate.at(vindex))
+ {
+ struct stat fileinfo;
+ if (! iogh->recovered || stat(filename, &fileinfo)!=0)
+ {
+ HDF5_ERROR (writer = H5Fcreate (filename, H5F_ACC_TRUNC, H5P_DEFAULT,
+ H5P_DEFAULT));
+ assert (writer>=0);
+ HDF5_ERROR (H5Fclose (writer));
+ writer = -1;
+ }
+ }
+
+ // Open the file
+ HDF5_ERROR (writer = H5Fopen (filename, H5F_ACC_RDWR, H5P_DEFAULT));
+ }
+
+ if (verbose)
+ {
+ CCTK_VInfo (CCTK_THORNSTRING,
+ "Writing variable '%s' on mglevel %d reflevel %d",
+ varname, mglevel, reflevel);
+ }
+ WriteVar (cctkGH, writer, request, 0);
+
+ // Close the file
+ if (writer >= 0)
+ {
+ HDF5_ERROR (H5Fclose (writer));
+ }
+
+ // Don't truncate again
+ do_truncate.at(vindex) = false;
+
+ return (0);
+}
+
+int WriteVar (const cGH* const cctkGH, const hid_t writer, const ioRequest* request,
+ const int called_from_checkpoint) {
+
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ void * h5data=NULL;
+
+ const int n = request->vindex;
+ assert (n>=0 && n<CCTK_NumVars());
+ const char * varname = CCTK_FullName(n);
+ const int group = CCTK_GroupIndexFromVarI (n);
+ assert (group>=0 && group<(int)Carpet::arrdata.size());
+ const int n0 = CCTK_FirstVarIndexI(group);
+ assert (n0>=0 && n0<CCTK_NumVars());
+ const int var = n - n0;
+ assert (var>=0 && var<CCTK_NumVars());
+ int tl = 0;
+
+ const int gpdim = CCTK_GroupDimI(group);
+
+ // Check for storage
+ if (! CCTK_QueryGroupStorageI(cctkGH, group)) {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Cannot output variable \"%s\" because it has no storage",
+ varname);
+ return 0;
+ }
+
+ const int grouptype = CCTK_GroupTypeI(group);
+ switch (grouptype) {
+ case CCTK_SCALAR:
+ case CCTK_ARRAY:
+ assert (do_global_mode);
+ break;
+ case CCTK_GF:
+ /* do nothing */
+ break;
+ default:
+ assert (0);
+ }
+ const int rl = grouptype==CCTK_GF ? reflevel : 0;
+
+ cGroup cgdata;
+ int ierr = CCTK_GroupData(group,&cgdata);
+ assert(ierr==0);
+
+ // Select memory (source) and file (destination) datatypes
+ int cctkDataType = CCTK_VarTypeI(n);
+ const hid_t memdatatype = h5DataType(cctkGH, cctkDataType);
+ assert(memdatatype >= 0);
+ if (out_single_precision && ! called_from_checkpoint)
+ {
+ if (cctkDataType == CCTK_VARIABLE_REAL)
+ {
+ cctkDataType = CCTK_VARIABLE_REAL4;
+ }
+ else if (cctkDataType == CCTK_VARIABLE_COMPLEX)
+ {
+ cctkDataType = CCTK_VARIABLE_COMPLEX8;
+ }
+#ifdef CCTK_INT2
+ else if (cctkDataType == CCTK_VARIABLE_INT)
+ {
+ cctkDataType = CCTK_VARIABLE_INT2;
+ }
+#endif
+ }
+ const hid_t filedatatype = h5DataType(cctkGH, cctkDataType);
+ assert(filedatatype >= 0);
+
+ // let's get the correct Carpet time level (which is the (-1) * Cactus timelevel):
+ tl = - request->timelevel;
+
+ // Traverse all components
+ BEGIN_MAP_LOOP(cctkGH, grouptype) {
+ BEGIN_COMPONENT_LOOP(cctkGH, grouptype) {
+
+ const ggf<dim>* ff = 0;
+
+ ff = (ggf<dim>*)arrdata.at(group).at(Carpet::map).data.at(var);
+
+ const gdata<dim>* const data = (*ff) (tl, rl, component, mglevel);
+
+ // Make temporary copy on processor 0
+ const ibbox ext = data->extent();
+// vect<int,dim> lo = ext.lower();
+// vect<int,dim> hi = ext.upper();
+// vect<int,dim> str = ext.stride();
+
+ gdata<dim>* const tmp = data->make_typed (n);
+ tmp->allocate (ext, 0);
+
+ if ( !((cgdata.disttype == CCTK_DISTRIB_CONSTANT) &&
+ (arrdata.at(group).at(Carpet::map).hh->processors.at(reflevel).at(component)!=0))) {
+
+ if (cgdata.disttype == CCTK_DISTRIB_CONSTANT) {
+ assert(grouptype == CCTK_ARRAY || grouptype == CCTK_SCALAR);
+ if(component!=0) goto skip;
+ h5data = CCTK_VarDataPtrI(cctkGH,tl,n);
+ } else {
+ for (comm_state<dim> state; !state.done(); state.step()) {
+ tmp->copy_from (state, data, ext);
+ }
+ }
+ // Write data
+ if (CCTK_MyProc(cctkGH)==0) {
+
+ int ldim=0;
+ if ( grouptype==CCTK_SCALAR ) {
+ ldim = 1;
+ } else {
+ ldim = gpdim;
+ }
+
+ // hsize_t shape[ldim];
+
+ vector<hsize_t> shape(ldim);
+
+ for (int d=0; d<ldim; ++d) {
+ shape[ldim-1-d] = (ext.shape() / ext.stride())[d];
+ }
+ hid_t dataspace;
+ HDF5_ERROR (dataspace = H5Screate_simple (ldim, &shape[0], NULL));
+ assert (dataspace>=0);
+
+
+ ostringstream datasetnamebuf;
+ datasetnamebuf << varname
+ << " it=" << cctk_iteration
+ << " tl=" << tl
+ << " ml=" << mglevel
+ << " rl=" << rl
+ << " m=" << Carpet::map
+ << " c=" << component;
+ string datasetnamestr = datasetnamebuf.str();
+ assert (datasetnamestr.size() <= 256); // limit dataset name size
+ const char * const datasetname = datasetnamestr.c_str();
+ hid_t dataset;
+ HDF5_ERROR (dataset = H5Dcreate (writer, datasetname, filedatatype, dataspace, H5P_DEFAULT));
+
+ if (dataset>=0) {
+
+ if (cgdata.disttype != CCTK_DISTRIB_CONSTANT) {
+ h5data = (void*)tmp->storage();
+ }
+
+ HDF5_ERROR (H5Dwrite (dataset, memdatatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, h5data));
+
+ // Write FlexIO attributes
+ WriteAttribute (dataset, "level", rl);
+ {
+ CCTK_REAL origin[dim], delta[dim];
+ CCTK_REAL min_ext[dim], max_ext[dim];
+ for (int d=0; d<dim; ++d) {
+ origin[d] = CCTK_ORIGIN_SPACE(d);
+ delta[d] = CCTK_DELTA_SPACE(d);
+ min_ext[d] = origin[d] + cctk_lbnd[d] * delta[d];
+ max_ext[d] = origin[d] + cctk_ubnd[d] * delta[d];
+ }
+ WriteAttribute (dataset, "origin", min_ext, dim);
+ WriteAttribute (dataset, "delta", delta, dim);
+ WriteAttribute (dataset, "min_ext", min_ext, dim);
+ WriteAttribute (dataset, "max_ext", max_ext, dim);
+ }
+ WriteAttribute (dataset, "time", cctk_time);
+ WriteAttribute (dataset, "timestep", cctk_iteration);
+ WriteAttribute (dataset, "level_timestep", cctk_iteration / reflevelfact);
+ WriteAttribute (dataset, "persistence", maxreflevelfact / reflevelfact);
+ {
+ int time_refinement=0;
+ int spatial_refinement[dim];
+ int grid_placement_refinement[dim];
+ time_refinement = reflevelfact;
+ for (int d=0; d<dim; ++d) {
+ spatial_refinement[d] = reflevelfact;
+ grid_placement_refinement[d] = reflevelfact;
+ }
+ WriteAttribute (dataset, "time_refinement", time_refinement);
+ WriteAttribute (dataset, "spatial_refinement", spatial_refinement, dim);
+ WriteAttribute (dataset, "grid_placement_refinement", grid_placement_refinement, dim);
+ }
+ {
+ int iorigin[dim];
+ for (int d=0; d<dim; ++d) {
+ iorigin[d] = (ext.lower() / ext.stride())[d];
+ }
+ WriteAttribute (dataset, "iorigin", iorigin, dim);
+ }
+
+ // Write some additional attributes
+
+ // Legacy arguments
+ {
+ char * fullname = CCTK_FullName(n);
+ assert (fullname);
+ WriteAttribute (dataset, "name", fullname);
+ free (fullname);
+ }
+
+ // Group arguments
+ WriteAttribute (dataset, "group_version", 1);
+ {
+ char * fullname = CCTK_FullName(n);
+ assert (fullname);
+ WriteAttribute (dataset, "group_fullname", fullname);
+ free (fullname);
+ }
+ WriteAttribute (dataset, "group_varname", CCTK_VarName(n));
+ {
+ char * groupname = CCTK_GroupName(group);
+ assert (groupname);
+ WriteAttribute (dataset, "group_groupname", groupname);
+ free (groupname);
+ }
+ switch (grouptype) {
+ case CCTK_GF:
+ WriteAttribute (dataset, "group_grouptype", "CCTK_GF");
+ break;
+ case CCTK_ARRAY:
+ WriteAttribute (dataset, "group_grouptype", "CCTK_ARRAY");
+ break;
+ case CCTK_SCALAR:
+ WriteAttribute (dataset, "group_grouptype", "CCTK_SCALAR");
+ break;
+ default:
+ assert (0);
+ }
+ WriteAttribute (dataset, "group_dim", CCTK_GroupDimI(group));
+ WriteAttribute (dataset, "group_timelevel", tl);
+ WriteAttribute (dataset, "group_numtimelevels", CCTK_NumTimeLevelsI(group));
+
+ // Cactus arguments
+ WriteAttribute (dataset, "cctk_version", 1);
+ WriteAttribute (dataset, "cctk_dim", cctk_dim);
+ WriteAttribute (dataset, "cctk_iteration", cctk_iteration);
+ WriteAttribute (dataset, "cctk_gsh", cctk_gsh, dim);
+ WriteAttribute (dataset, "cctk_lsh", cctk_lsh, dim);
+ WriteAttribute (dataset, "cctk_lbnd", cctk_lbnd, dim);
+ WriteAttribute (dataset, "cctk_delta_time", cctk_delta_time);
+ WriteAttribute (dataset, "cctk_delta_space", cctk_delta_space, dim);
+ WriteAttribute (dataset, "cctk_origin_space", cctk_origin_space, dim);
+ WriteAttribute (dataset, "cctk_bbox", cctk_bbox, 2*dim);
+ WriteAttribute (dataset, "cctk_levfac", cctk_levfac, dim);
+ WriteAttribute (dataset, "cctk_levoff", cctk_levoff, dim);
+ WriteAttribute (dataset, "cctk_levoffdenom", cctk_levoffdenom, dim);
+ WriteAttribute (dataset, "cctk_timefac", cctk_timefac);
+ WriteAttribute (dataset, "cctk_convlevel", cctk_convlevel);
+ WriteAttribute (dataset, "cctk_convfac", cctk_convfac);
+ WriteAttribute (dataset, "cctk_nghostzones", cctk_nghostzones, dim);
+ WriteAttribute (dataset, "cctk_time", cctk_time);
+
+ // Carpet arguments
+ WriteAttribute (dataset, "carpet_version", 1);
+ WriteAttribute (dataset, "carpet_dim", dim);
+ WriteAttribute (dataset, "carpet_basemglevel", basemglevel);
+ WriteAttribute (dataset, "carpet_mglevel", mglevel);
+ WriteAttribute (dataset, "carpet_mglevels", mglevels);
+ WriteAttribute (dataset, "carpet_mgface", mgfact);
+ WriteAttribute (dataset, "carpet_reflevel", reflevel);
+ WriteAttribute (dataset, "carpet_reflevels", reflevels);
+ WriteAttribute (dataset, "carpet_reffact", reffact);
+ WriteAttribute (dataset, "carpet_map", Carpet::map);
+ WriteAttribute (dataset, "carpet_maps", maps);
+ WriteAttribute (dataset, "carpet_component", component);
+ WriteAttribute (dataset, "carpet_components", vhh.at(Carpet::map)->components(reflevel));
+
+ HDF5_ERROR (H5Dclose (dataset));
+ }
+
+ HDF5_ERROR (H5Sclose (dataspace));
+
+ } // if on root processor
+ } // if ! CCTK_DISTRIB_BLAH
+
+ skip:
+ // Delete temporary copy
+ delete tmp;
+
+ } END_COMPONENT_LOOP;
+ } END_MAP_LOOP;
+
+ return 0;
+}
+
+
+
+int TimeToOutput (const cGH* const cctkGH, const int vindex)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (vindex>=0 && vindex<CCTK_NumVars());
+
+
+
+ const int grouptype = CCTK_GroupTypeFromVarI(vindex);
+ switch (grouptype) {
+ case CCTK_SCALAR:
+ case CCTK_ARRAY:
+ if (! do_global_mode) return 0;
+ break;
+ case CCTK_GF:
+ // do nothing
+ break;
+ default:
+ assert (0);
+ }
+
+
+
+ // check whether to output at this iteration
+ bool output_this_iteration;
+
+ const char* myoutcriterion = out3D_criterion;
+ if (CCTK_EQUALS(myoutcriterion, "default")) {
+ myoutcriterion = out_criterion;
+ }
+
+ if (CCTK_EQUALS (myoutcriterion, "never")) {
+
+ // Never output
+ output_this_iteration = false;
+
+ } else if (CCTK_EQUALS (myoutcriterion, "iteration")) {
+
+ int myoutevery = out3D_every;
+ if (myoutevery == -2) {
+ myoutevery = out_every;
+ }
+ if (myoutevery <= 0) {
+ // output is disabled
+ output_this_iteration = false;
+ } else if (cctk_iteration == *this_iteration) {
+ // we already decided to output this iteration
+ output_this_iteration = true;
+ } else if (cctk_iteration >= *next_output_iteration) {
+ // it is time for the next output
+ output_this_iteration = true;
+ *next_output_iteration = cctk_iteration + myoutevery;
+ *this_iteration = cctk_iteration;
+ } else {
+ // we want no output at this iteration
+ output_this_iteration = false;
+ }
+
+ } else if (CCTK_EQUALS (myoutcriterion, "divisor")) {
+
+ int myoutevery = out3D_every;
+ if (myoutevery == -2) {
+ myoutevery = out_every;
+ }
+ if (myoutevery <= 0) {
+ // output is disabled
+ output_this_iteration = false;
+ } else if ((cctk_iteration % myoutevery) == 0) {
+ // we already decided to output this iteration
+ output_this_iteration = true;
+ } else {
+ // we want no output at this iteration
+ output_this_iteration = false;
+ }
+
+ } else if (CCTK_EQUALS (myoutcriterion, "time")) {
+
+ CCTK_REAL myoutdt = out3D_dt;
+ if (myoutdt == -2) {
+ myoutdt = out_dt;
+ }
+ if (myoutdt < 0) {
+ // output is disabled
+ output_this_iteration = false;
+ } else if (myoutdt == 0) {
+ // output all iterations
+ output_this_iteration = true;
+ } else if (cctk_iteration == *this_iteration) {
+ // we already decided to output this iteration
+ output_this_iteration = true;
+ } else if (cctk_time / cctk_delta_time
+ >= *next_output_time / cctk_delta_time - 1.0e-12) {
+ // it is time for the next output
+ output_this_iteration = true;
+ *next_output_time = cctk_time + myoutdt;
+ *this_iteration = cctk_iteration;
+ } else {
+ // we want no output at this iteration
+ output_this_iteration = false;
+ }
+
+ } else {
+
+ assert (0);
+
+ } // select output criterion
+
+ if (! output_this_iteration) return 0;
+
+
+
+ if (! CheckForVariable(out3D_vars, vindex)) {
+ // This variable should not be output
+ return 0;
+ }
+
+
+
+ if (last_output.at(mglevel).at(reflevel).at(vindex) == cctk_iteration) {
+ // Has already been output during this iteration
+ char* varname = CCTK_FullName(vindex);
+ CCTK_VWarn (5, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Skipping output for variable \"%s\", because this variable "
+ "has already been output during the current iteration -- "
+ "probably via a trigger during the analysis stage",
+ varname);
+ free (varname);
+ return 0;
+ }
+
+ assert (last_output.at(mglevel).at(reflevel).at(vindex) < cctk_iteration);
+
+ // Should be output during this iteration
+ return 1;
+}
+
+
+
+int TriggerOutput (const cGH* const cctkGH, const int vindex) {
+ assert (vindex>=0 && vindex<CCTK_NumVars());
+
+ char* varname = CCTK_FullName(vindex);
+ const int retval = OutputVarAs (cctkGH, varname, CCTK_VarName(vindex));
+ free (varname);
+
+ last_output.at(mglevel).at(reflevel).at(vindex) = cctkGH->cctk_iteration;
+
+ return retval;
+}
+
+
+
+
+int ReadVar (const cGH* const cctkGH, const int vindex,
+ const hid_t dataset, vector<ibset> &regions_read,
+ const int called_from_recovery)
+{
+
+ DECLARE_CCTK_PARAMETERS;
+
+ const int group = CCTK_GroupIndexFromVarI (vindex);
+ assert (group>=0 && group<(int)Carpet::arrdata.size());
+ char *fullname = CCTK_FullName (vindex);
+ const int n0 = CCTK_FirstVarIndexI(group);
+ assert (n0>=0 && n0<CCTK_NumVars());
+ const int var = vindex - n0;
+ assert (var>=0 && var<CCTK_NumVars());
+ int tl = 0;
+
+ bool did_read_something = false;
+
+ // Stuff needed for Recovery
+
+ void *h5data = NULL;
+
+ if (verbose)
+ {
+ CCTK_VInfo (CCTK_THORNSTRING, " reading '%s'", fullname);
+ }
+
+ // Check for storage
+ if (! CCTK_QueryGroupStorageI(cctkGH, group))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Cannot input variable \"%s\" because it has no storage",
+ fullname);
+ free (fullname);
+ return 0;
+ }
+
+ const int grouptype = CCTK_GroupTypeI(group);
+ if ((grouptype == CCTK_SCALAR || grouptype == CCTK_ARRAY) && reflevel > 0)
+ {
+ free (fullname);
+ return 0;
+ }
+
+ const int gpdim = CCTK_GroupDimI(group);
+
+
+ int intbuffer[2 + 2*dim];
+ int &group_timelevel = intbuffer[0],
+ &amr_level = intbuffer[1];
+ int *amr_origin = &intbuffer[2],
+ *amr_dims = &intbuffer[2+dim];
+
+ if (CCTK_MyProc(cctkGH)==0)
+ {
+ // get dataset dimensions
+ hid_t dataspace;
+ HDF5_ERROR (dataspace = H5Dget_space (dataset));
+ int rank = (int) H5Sget_simple_extent_ndims (dataspace);
+ assert (0 < rank && rank <= dim);
+ assert ((grouptype == CCTK_SCALAR ? gpdim+1 : gpdim) == rank);
+ vector<hsize_t> shape(rank);
+ HDF5_ERROR (H5Sget_simple_extent_dims (dataspace, &shape[0], NULL));
+ HDF5_ERROR (H5Sclose (dataspace));
+
+ for (int i = 0; i < dim; i++)
+ {
+ amr_dims[i] = 1;
+ amr_origin[i] = 0;
+ }
+ int datalength = 1;
+ for (int i = 0; i < rank; i++)
+ {
+ datalength *= shape[i];
+ amr_dims[i] = shape[rank-i-1];
+ }
+
+ const int cctkDataType = CCTK_VarTypeI(vindex);
+ const hid_t datatype = h5DataType(cctkGH,cctkDataType);
+
+ //cout << "datalength: " << datalength << " rank: " << rank << "\n";
+ //cout << shape[0] << " " << shape[1] << " " << shape[2] << "\n";
+
+ // to do: read in an allocate with correct datatype
+
+ h5data = malloc (CCTK_VarTypeSize (cctkDataType) * datalength);
+ HDF5_ERROR (H5Dread (dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+ h5data));
+
+ ReadAttribute (dataset, "level", amr_level);
+ ReadAttribute (dataset, "iorigin", amr_origin, rank);
+
+ if(called_from_recovery)
+ {
+ ReadAttribute(dataset,"group_timelevel", group_timelevel);
+ }
+ } // MyProc == 0
+
+ MPI_Bcast (intbuffer, sizeof (intbuffer) / sizeof (*intbuffer), MPI_INT, 0, dist::comm);
+
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "amr_level: " << amr_level << " reflevel: " << reflevel << endl;
+#endif
+
+ if (amr_level == reflevel)
+ {
+ // Traverse all components on all levels
+ BEGIN_MAP_LOOP(cctkGH, grouptype)
+ {
+ BEGIN_COMPONENT_LOOP(cctkGH, grouptype)
+ {
+ did_read_something = true;
+
+ ggf<dim>* ff = 0;
+
+ assert (var < (int)arrdata.at(group).at(Carpet::map).data.size());
+ ff = (ggf<dim>*)arrdata.at(group).at(Carpet::map).data.at(var);
+
+ if(called_from_recovery) tl = group_timelevel;
+
+ gdata<dim>* const data = (*ff) (tl, reflevel, component, mglevel);
+
+ // Create temporary data storage on processor 0
+ vect<int,dim> str = vect<int,dim>(maxreflevelfact/reflevelfact);
+
+ if(grouptype == CCTK_SCALAR || grouptype == CCTK_ARRAY)
+ str = vect<int,dim> (1);
+
+ vect<int,dim> lb = vect<int,dim>::ref(amr_origin) * str;
+ vect<int,dim> ub
+ = lb + (vect<int,dim>::ref(amr_dims) - 1) * str;
+
+ gdata<dim>* const tmp = data->make_typed (vindex);
+
+
+ cGroup cgdata;
+ int ierr = CCTK_GroupData(group,&cgdata);
+ assert(ierr==0);
+ //cout << "lb_before: " << lb << endl;
+ //cout << "ub_before: " << ub << endl;
+ if (cgdata.disttype == CCTK_DISTRIB_CONSTANT) {
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "CCTK_DISTRIB_CONSTANT: " << fullname << endl;
+#endif
+ assert(grouptype == CCTK_ARRAY || grouptype == CCTK_SCALAR);
+ if (grouptype == CCTK_SCALAR) {
+ lb[0] = arrdata.at(group).at(Carpet::map).hh->processors.at(reflevel).at(component);
+ ub[0] = arrdata.at(group).at(Carpet::map).hh->processors.at(reflevel).at(component);
+ for(int i=1;i<dim;i++) {
+ lb[i]=0;
+ ub[i]=0;
+ }
+ } else {
+ const int newlb = lb[gpdim-1] +
+ (ub[gpdim-1]-lb[gpdim-1]+1)*
+ (arrdata.at(group).at(Carpet::map).hh->processors.at(reflevel).at(component));
+ const int newub = ub[gpdim-1] +
+ (ub[gpdim-1]-lb[gpdim-1]+1)*
+ (arrdata.at(group).at(Carpet::map).hh->processors.at(reflevel).at(component));
+ lb[gpdim-1] = newlb;
+ ub[gpdim-1] = newub;
+ }
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "lb: " << lb << endl;
+ cout << "ub: " << ub << endl;
+#endif
+ }
+ const bbox<int,dim> ext(lb,ub,str);
+
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "ext: " << ext << endl;
+#endif
+
+ if (CCTK_MyProc(cctkGH)==0) {
+ tmp->allocate (ext, 0, h5data);
+ } else {
+ tmp->allocate (ext, 0);
+ }
+
+ // Initialise with what is found in the file -- this does
+ // not guarantee that everything is initialised.
+ const bbox<int,dim> overlap = tmp->extent() & data->extent();
+ regions_read.at(Carpet::map) |= overlap;
+
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "working on component: " << component << endl;
+ cout << "tmp->extent " << tmp->extent() << endl;
+ cout << "data->extent " << data->extent() << endl;
+ cout << "overlap " << overlap << endl;
+ cout << "-----------------------------------------------------" << endl;
+#endif
+
+ // FIXME: is this barrier really necessary ??
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ // Copy into grid function
+ for (comm_state<dim> state; !state.done(); state.step()) {
+ data->copy_from (state, tmp, overlap);
+ }
+
+
+ // Delete temporary copy
+ delete tmp;
+
+
+ } END_COMPONENT_LOOP;
+
+ if (called_from_recovery) {
+ arrdata.at(group).at(Carpet::map).tt->set_time(reflevel,mglevel,
+ (CCTK_REAL) ((cctkGH->cctk_time - cctk_initial_time)
+ / (delta_time * mglevelfact)) );
+ }
+
+
+ } END_MAP_LOOP;
+
+ } // if amr_level == reflevel
+
+ free (h5data);
+ free (fullname);
+
+ return did_read_something;
+}
+
+
+
+static int InputVarAs (const cGH* const cctkGH, const int vindex,
+ const char* const alias)
+{
+ DECLARE_CCTK_PARAMETERS;
+
+ char *fullname = CCTK_FullName (vindex);
+ const int group = CCTK_GroupIndexFromVarI (vindex);
+ assert (group>=0 && group<(int)Carpet::arrdata.size());
+
+ int want_dataset = 0;
+ bool did_read_something = false;
+ int ndatasets = 0;
+ hid_t dataset = 0;
+
+ char datasetname[1024];
+
+ // Check for storage
+ if (! CCTK_QueryGroupStorageI(cctkGH, group)) {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Cannot input variable \"%s\" because it has no storage",
+ fullname);
+ free (fullname);
+ return 0;
+ }
+
+ const int grouptype = CCTK_GroupTypeI(group);
+ const int rl = grouptype==CCTK_GF ? reflevel : 0;
+ //cout << "want level " << rl << " reflevel " << reflevel << endl;
+
+ // Find the input directory
+ const char* const myindir = in3D_dir;
+
+ // Invent a file name
+ ostringstream filenamebuf;
+ filenamebuf << myindir << "/" << alias << in3D_extension;
+ string filenamestr = filenamebuf.str();
+ const char * const filename = filenamestr.c_str();
+
+ hid_t reader = -1;
+
+ // Read the file only on the root processor
+ if (CCTK_MyProc(cctkGH)==0) {
+
+ // Open the file
+ if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Opening file \"%s\"", filename);
+ reader = H5Fopen (filename, H5F_ACC_RDONLY, H5P_DEFAULT);
+ if (reader<0) {
+ CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Could not open file \"%s\" for reading", filename);
+ }
+ assert (reader>=0);
+ // get the number of datasets in the file
+ ndatasets=GetnDatasets(reader);
+ }
+
+ vector<ibset> regions_read(Carpet::maps);
+
+ // Broadcast number of datasets
+ MPI_Bcast (&ndatasets, 1, MPI_INT, 0, dist::comm);
+ assert (ndatasets>=0);
+
+
+ for (int datasetid=0; datasetid<ndatasets; ++datasetid) {
+ if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Handling dataset #%d", datasetid);
+
+
+ // Read data
+ if (CCTK_MyProc(cctkGH)==0) {
+ GetDatasetName(reader,datasetid,datasetname);
+ // cout << datasetname << "\n";
+
+ HDF5_ERROR (dataset = H5Dopen (reader, datasetname));
+ }
+
+
+#if 0
+ int amr_level;
+ int amr_origin[dim];
+ int amr_dims[dim];
+#endif
+
+ if (CCTK_MyProc(cctkGH)==0) {
+
+ // Read data
+ char * name;
+ ReadAttribute (dataset, "name", name);
+ // cout << "dataset name is " << name << endl;
+ if (verbose && name) {
+ CCTK_VInfo (CCTK_THORNSTRING, "Dataset name is \"%s\"", name);
+ }
+ want_dataset = name && CCTK_EQUALS(name, fullname);
+ free (name);
+ } // myproc == 0
+
+ MPI_Bcast (&want_dataset, 1, MPI_INT, 0, dist::comm);
+
+ if(want_dataset) {
+ did_read_something = ReadVar(cctkGH,vindex,dataset,regions_read,0);
+ } // want_dataset
+
+ } // loop over datasets
+
+ // Close the file
+ if (CCTK_MyProc(cctkGH)==0) {
+ if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Closing file");
+ HDF5_ERROR (H5Fclose(reader));
+ reader=-1;
+ }
+
+ // Was everything initialised?
+ if (did_read_something) {
+ for (int m=0; m<Carpet::maps; ++m) {
+ dh<dim>& thedd = *arrdata.at(group).at(m).dd;
+ ibset all_exterior;
+ for (size_t c=0; c<thedd.boxes.at(rl).size(); ++c) {
+ all_exterior |= thedd.boxes.at(rl).at(c).at(mglevel).exterior;
+ }
+ if (regions_read.at(m) != all_exterior) {
+#ifdef CARPETIOHDF5_DEBUG
+ cout << "read: " << regions_read.at(m) << endl
+ << "want: " << all_exterior << endl;
+#endif
+ CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Variable \"%s\" could not be initialised from file -- the file may be missing data",
+ fullname);
+ }
+ }
+ } // if did_read_something
+ // CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING,"stop!");
+
+ return did_read_something ? 0 : -1;
+
+}
+
+
+int CarpetIOHDF5ReadData (const cGH* const cctkGH)
+{
+ int retval = 0;
+ DECLARE_CCTK_PARAMETERS
+
+
+ int numvars = CCTK_NumVars ();
+ vector<bool> flags (numvars);
+
+ if (CCTK_TraverseString (in3D_vars, SetFlag, &flags, CCTK_GROUP_OR_VAR) < 0)
+ {
+ CCTK_VWarn (strict_io_parameter_check ? 0 : 1,
+ __LINE__, __FILE__, CCTK_THORNSTRING,
+ "error while parsing parameter 'IOHDF5::in3D_vars'");
+ }
+
+ for (int vindex = 0; vindex < numvars; vindex++)
+ {
+ if (flags.at (vindex))
+ {
+ retval = InputVarAs (cctkGH, vindex, CCTK_VarName (vindex));
+ if (retval)
+ {
+ break;
+ }
+ }
+ }
+
+ return (retval);
+}
+
+
+
+#if 0
+/** returns the number of recovered variables */
+int Recover (cGH* const cctkGH, const char *basefilename,
+ const int called_from)
+{
+ assert (cctkGH);
+ assert (basefilename);
+ assert (called_from == CP_INITIAL_DATA
+ || called_from == CP_EVOLUTION_DATA
+ || called_from == CP_RECOVER_PARAMETERS
+ || called_from == CP_RECOVER_DATA
+ || called_from == FILEREADER_DATA);
+
+ // the other modes are not supported yet
+ assert (called_from == FILEREADER_DATA);
+
+ const ioGH * const iogh = (const ioGH *) CCTK_GHExtension (cctkGH, "IO");
+ assert (iogh);
+
+ int num_vars_read = 0;
+ assert (iogh->do_inVars);
+ for (int n=0; n<CCTK_NumVars(); ++n) {
+ if (iogh->do_inVars[n]) {
+ const int ierr = InputVarAs (cctkGH, vindex, basefilename);
+ if (! ierr) {
+ ++ num_vars_read;
+ }
+ }
+ }
+
+ return num_vars_read;
+}
+#endif
+
+} // namespace CarpetIOHDF5