diff options
author | Thomas Radke <tradke@aei.mpg.de> | 2005-06-24 12:39:00 +0000 |
---|---|---|
committer | Thomas Radke <tradke@aei.mpg.de> | 2005-06-24 12:39:00 +0000 |
commit | 67f5bca54cccb46ff35e037f460847dab5d62d42 (patch) | |
tree | 623a6a9472ad76388cfa030e5217beed216ebdf7 /Carpet/CarpetIOHDF5/src/Output.cc | |
parent | f1bbec2b98eec1d20762012595b8a865c2fd1b7f (diff) |
CarpetIOHDF5: implement parallel I/O
Like CactusPUGHIO/IOHDF5, CarpetIOHDF5 now also provides parallel I/O for
data and checkpointing/recovery.
The I/O mode is set via IOUtils' parameters IO::out_mode and IO::out_unchunked,
with parallel output to chunked files (one per processor) being the default.
The recovery and filereader interface can read any type of CarpetIOHDF5 data
files transparently - regardless of how it was created (serial/parallel,
or on a different number of processors).
See the updated thorn documentation for details.
darcs-hash:20050624123924-776a0-5639aee9677f0362fc94c80c534b47fd1b07ae74.gz
Diffstat (limited to 'Carpet/CarpetIOHDF5/src/Output.cc')
-rw-r--r-- | Carpet/CarpetIOHDF5/src/Output.cc | 1202 |
1 files changed, 332 insertions, 870 deletions
diff --git a/Carpet/CarpetIOHDF5/src/Output.cc b/Carpet/CarpetIOHDF5/src/Output.cc index 5e6b43b8a..5851a74cc 100644 --- a/Carpet/CarpetIOHDF5/src/Output.cc +++ b/Carpet/CarpetIOHDF5/src/Output.cc @@ -1,37 +1,15 @@ #include <assert.h> -#include <limits.h> -#include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <unistd.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_Functions.h" +#include "cctk_Arguments.h" #include "cctk_Parameters.h" -#include "util_String.h" #include "util_Table.h" -#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 "CarpetIOHDF5.hh" +#include "CactusBase/IOUtil/src/ioGH.h" namespace CarpetIOHDF5 @@ -41,375 +19,25 @@ using namespace std; using namespace Carpet; -// Variable definitions -vector<bool> do_truncate; // [var] -vector<vector<vector<int> > > last_output; // [ml][rl][var] - - -// registered GH extension setup routine -static void* SetupGH (tFleshConfig* const fleshconfig, - const int convLevel, cGH* const cctkGH); - -// callbacks for CarpetIOHDF5's I/O method -static int OutputGH (const cGH* const cctkGH); -static int OutputVarAs (const cGH* const cctkGH, const char* const varname, - const char* const alias); -static int TimeToOutput (const cGH* const cctkGH, const int vindex); -static int TriggerOutput (const cGH* const cctkGH, const int vindex); - // add attributes to an HDF5 dataset static void AddAttributes (const cGH *const cctkGH, const char *fullname, int vdim, int refinementlevel, - const ioRequest* request, + const ioRequest* const request, const ibbox& bbox, hid_t dataset); -// callback for I/O parameter parsing routine -static void GetVarIndex (int vindex, const char* optstring, void* arg); - -static void CheckSteerableParameters (const cGH *const cctkGH, - CarpetIOHDF5GH *myGH); -static int WarnAboutDeprecatedParameters (void); - -////////////////////////////////////////////////////////////////////////////// -// public routines -////////////////////////////////////////////////////////////////////////////// - -int CarpetIOHDF5_Startup (void) -{ - CCTK_RegisterBanner ("AMR HDF5 I/O provided by CarpetIOHDF5"); - - const int GHExtension = CCTK_RegisterGHExtension ("CarpetIOHDF5"); - CCTK_RegisterGHExtensionSetupGH (GHExtension, SetupGH); - - return (0); -} - - -static void* SetupGH (tFleshConfig* const fleshconfig, - const int convLevel, cGH* const cctkGH) -{ - DECLARE_CCTK_ARGUMENTS; - DECLARE_CCTK_PARAMETERS; - - CarpetIOHDF5GH* myGH; - - const void *dummy; - dummy = &fleshconfig; - dummy = &convLevel; - dummy = &cctkGH; - dummy = &dummy; - - // register CarpetIOHDF5's routines as a new I/O method - const int IOMethod = CCTK_RegisterIOMethod ("IOHDF5"); - CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH); - CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs); - CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput); - CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput); - - if (! CCTK_Equals (verbose, "none")) - { - CCTK_INFO ("I/O Method 'IOHDF5' registered: AMR output of grid variables " - "to HDF5 files"); - } - - // register CarpetIOHDF5's recovery routine with IOUtil - if (IOUtil_RegisterRecover ("CarpetIOHDF5 recovery", Recover) < 0) - { - CCTK_WARN (1, "Failed to register " CCTK_THORNSTRING " recovery routine"); - } - - const int numvars = CCTK_NumVars (); - - // allocate a new GH extension structure - myGH = (CarpetIOHDF5GH*) malloc (sizeof (CarpetIOHDF5GH)); - myGH->out_last = (int *) malloc (numvars * sizeof (int)); - myGH->requests = (ioRequest **) calloc (numvars, sizeof (ioRequest *)); - myGH->cp_filename_index = 0; - myGH->checkpoint_keep = abs (checkpoint_keep); - myGH->cp_filename_list = (char **) calloc (myGH->checkpoint_keep, sizeof (char *)); - myGH->out_vars = strdup (""); - myGH->out_every_default = out_every - 1; - - // initial I/O parameter check - myGH->stop_on_parse_errors = strict_io_parameter_check; - CheckSteerableParameters (cctkGH, myGH); - myGH->stop_on_parse_errors = 0; - - for (int i = 0; i < numvars; i++) - { - myGH->out_last[i] = -1; - } - - // create the output directory (if it doesn't match ".") - const char *my_out_dir = *out_dir ? out_dir : io_out_dir; - myGH->out_dir = (char *) calloc (1, strlen (my_out_dir) + 2); - if (strcmp (myGH->out_dir, ".")) - { - sprintf (myGH->out_dir, "%s/", my_out_dir); - if (CCTK_MyProc (cctkGH) == 0) - { - int result = CCTK_CreateDirectory (0755, myGH->out_dir); - if (result < 0) - { - CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "Problem creating CarpetIOHDF5 output directory '%s'", - myGH->out_dir); - } - else if (result > 0 && CCTK_Equals (verbose, "full")) - { - CCTK_VInfo (CCTK_THORNSTRING, - "CarpetIOHDF5 output directory '%s' already exists", - myGH->out_dir); - } - } - } - - // Now set hdf5 complex datatypes - 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 - - // Truncate all files if this is not a restart - do_truncate.resize(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(numvars, INT_MIN); - } - } - - return (myGH); -} - - -int CarpetIOHDF5_Init (const cGH* const cctkGH) -{ - DECLARE_CCTK_ARGUMENTS; - - *this_iteration = -1; - *next_output_iteration = 0; - *next_output_time = cctk_time; - - return (0); -} - - -int WriteVarChunked (const cGH* const cctkGH, - const hid_t writer, - const ioRequest* request, - const int called_from_checkpoint) -{ - DECLARE_CCTK_PARAMETERS; - - char *fullname = CCTK_FullName(request->vindex); - const int gindex = CCTK_GroupIndexFromVarI (request->vindex); - assert (gindex >= 0 && gindex < (int) Carpet::arrdata.size ()); - const int var = request->vindex - CCTK_FirstVarIndexI (gindex); - assert (var >= 0 && var < CCTK_NumVars ()); - cGroup group; - CCTK_GroupData (gindex, &group); - - - // Scalars and arrays have only one refinement level 0, - // regardless of what the current refinement level is. - // Output for them must be called in global mode. - int refinementlevel = reflevel; - if (group.grouptype == CCTK_SCALAR || group.grouptype == CCTK_ARRAY) - { - assert (do_global_mode); - refinementlevel = 0; - } - - // HDF5 doesn't like 0-dimensional arrays - if (group.grouptype == CCTK_SCALAR) - { - group.dim = 1; - } - - // If the user requested so, select single precision data output - hid_t memdatatype, filedatatype; - HDF5_ERROR (memdatatype = h5DataType (cctkGH, group.vartype, 0)); - HDF5_ERROR (filedatatype = - h5DataType (cctkGH, group.vartype, - out_single_precision && ! called_from_checkpoint)); - - const int myproc = CCTK_MyProc (cctkGH); - - // Traverse all maps - BEGIN_MAP_LOOP (cctkGH, group.grouptype) - { - BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) - { - // Using "exterior" includes ghost zones and refinement boundaries. - ibbox& bbox = arrdata.at(gindex).at(Carpet::map).dd-> - boxes.at(mglevel).at(refinementlevel).at(component).exterior; - - // Get the shape of the HDF5 dataset (in Fortran index order) - hsize_t shape[dim]; - hsize_t num_elems = 1; - for (int d = 0; d < group.dim; ++d) - { - shape[group.dim-1-d] = (bbox.shape() / bbox.stride())[d]; - num_elems *= shape[group.dim-1-d]; - } - - // Don't create zero-sized components - if (num_elems == 0) - { - continue; - } - - // Copy the overlap to the local processor - const ggf* ff = arrdata.at(gindex).at(Carpet::map).data.at(var); - const gdata* const data = (*ff) (request->timelevel, refinementlevel, - component, mglevel); - gdata* const processor_component = data->make_typed (request->vindex); - - processor_component->allocate (bbox, 0); - for (comm_state state(group.vartype); !state.done(); state.step()) - { - processor_component->copy_from (state, data, bbox); - } - - // Write data on I/O processor 0 - if (myproc == 0) - { - const void *data = (const void *) processor_component->storage(); - - // As per Cactus convention, DISTRIB=CONSTANT arrays - // (including grid scalars) are assumed to be the same on - // all processors and are therefore stored only by processor 0. - // - // Warn the user if this convention is violated. - if (component > 0 && group.disttype == CCTK_DISTRIB_CONSTANT) - { - const void *proc0 = CCTK_VarDataPtrI (cctkGH, request->timelevel, - request->vindex); - - if (memcmp (proc0, data, num_elems*CCTK_VarTypeSize(group.vartype))) - { - CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "values for DISTRIB=CONSTANT grid variable '%s' " - "(timelevel %d) differ between processors 0 and %d; " - "only the array from processor 0 will be stored", - fullname, request->timelevel, component); - } - } - else - { - // Construct a file-wide unique HDF5 dataset name - // (only add parts with varying metadata) - ostringstream datasetname; - datasetname << fullname - << " it=" << cctkGH->cctk_iteration - << " tl=" << request->timelevel; - if (mglevels > 1) - { - datasetname << " ml=" << mglevel; - } - if (group.grouptype == CCTK_GF) - { - if (Carpet::maps > 1) - { - datasetname << " m=" << Carpet::map; - } - datasetname << " rl=" << refinementlevel; - } - if (arrdata.at(gindex).at(Carpet::map).dd-> - boxes.at(mglevel).at(refinementlevel).size () > 1 && - group.disttype != CCTK_DISTRIB_CONSTANT) - { - datasetname << " c=" << component; - } - - // remove an already existing dataset of the same name - if (request->check_exist) - { - H5E_BEGIN_TRY - { - H5Gunlink (writer, datasetname.str().c_str()); - } H5E_END_TRY; - } - - hsize_t shape[dim]; - hssize_t origin[dim]; - for (int d = 0; d < group.dim; ++d) - { - origin[group.dim-1-d] = (bbox.lower() / bbox.stride())[d]; - shape[group.dim-1-d] = (bbox.shape() / bbox.stride())[d]; - } - - // Write the component as an individual dataset - hid_t dataspace, dataset; - HDF5_ERROR (dataspace = H5Screate_simple (group.dim, shape, NULL)); - HDF5_ERROR (dataset = H5Dcreate (writer, datasetname.str().c_str(), - filedatatype, dataspace, H5P_DEFAULT)); - HDF5_ERROR (H5Sclose (dataspace)); - HDF5_ERROR (H5Dwrite (dataset, memdatatype, H5S_ALL, H5S_ALL, - H5P_DEFAULT, data)); - AddAttributes (cctkGH, fullname, group.dim, refinementlevel, - request, bbox, dataset); - HDF5_ERROR (H5Dclose (dataset)); - } - - } // if myproc == 0 - - // Delete temporary copy of this component - delete processor_component; - - } END_COMPONENT_LOOP; - } END_MAP_LOOP; - - free (fullname); - - return 0; -} - int WriteVarUnchunked (const cGH* const cctkGH, - const hid_t writer, - const ioRequest* request, - const int called_from_checkpoint) + hid_t outfile, + const ioRequest* const request, + bool called_from_checkpoint) { DECLARE_CCTK_PARAMETERS; char *fullname = CCTK_FullName(request->vindex); const int gindex = CCTK_GroupIndexFromVarI (request->vindex); - assert (gindex >= 0 && gindex < (int) Carpet::arrdata.size ()); + assert (gindex >= 0 and gindex < (int) Carpet::arrdata.size ()); const int var = request->vindex - CCTK_FirstVarIndexI (gindex); - assert (var >= 0 && var < CCTK_NumVars ()); + assert (var >= 0 and var < CCTK_NumVars ()); cGroup group; CCTK_GroupData (gindex, &group); @@ -418,26 +46,19 @@ int WriteVarUnchunked (const cGH* const cctkGH, // regardless of what the current refinement level is. // Output for them must be called in global mode. int refinementlevel = reflevel; - if (group.grouptype == CCTK_SCALAR || group.grouptype == CCTK_ARRAY) - { + if (group.grouptype == CCTK_SCALAR or group.grouptype == CCTK_ARRAY) { assert (do_global_mode); refinementlevel = 0; } // HDF5 doesn't like 0-dimensional arrays - if (group.grouptype == CCTK_SCALAR) - { - group.dim = 1; - } + if (group.grouptype == CCTK_SCALAR) group.dim = 1; // If the user requested so, select single precision data output hid_t memdatatype, filedatatype; - HDF5_ERROR (memdatatype = h5DataType (cctkGH, group.vartype, 0)); - HDF5_ERROR (filedatatype = - h5DataType (cctkGH, group.vartype, - out_single_precision && ! called_from_checkpoint)); - - const int myproc = CCTK_MyProc (cctkGH); + HDF5_ERROR (memdatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, 0)); + HDF5_ERROR (filedatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, + out_single_precision and not called_from_checkpoint)); // create a file access property list to use the CORE virtual file driver hid_t plist; @@ -445,12 +66,10 @@ int WriteVarUnchunked (const cGH* const cctkGH, HDF5_ERROR (H5Pset_fapl_core (plist, 0, 0)); // Traverse all maps - BEGIN_MAP_LOOP (cctkGH, group.grouptype) - { + BEGIN_MAP_LOOP (cctkGH, group.grouptype) { // Collect the set of all components' bboxes ibset bboxes; - BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) - { + BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) { // Using "interior" removes ghost zones and refinement boundaries. bboxes += arrdata.at(gindex).at(Carpet::map).dd-> boxes.at(mglevel).at(refinementlevel).at(component).interior; @@ -461,59 +80,42 @@ int WriteVarUnchunked (const cGH* const cctkGH, // According to Cactus conventions, DISTRIB=CONSTANT arrays // (including grid scalars) are assumed to be the same on all // processors and are therefore stored only by processor 0. - if (group.disttype != CCTK_DISTRIB_CONSTANT) - { - bboxes.normalize(); - } + if (group.disttype != CCTK_DISTRIB_CONSTANT) bboxes.normalize(); // Loop over all components in the bbox set int bbox_id = 0; for (ibset::const_iterator bbox = bboxes.begin(); bbox != bboxes.end(); - bbox++, bbox_id++) - { + bbox++, bbox_id++) { // Get the shape of the HDF5 dataset (in Fortran index order) hsize_t shape[dim]; hsize_t num_elems = 1; - for (int d = 0; d < group.dim; ++d) - { + for (int d = 0; d < group.dim; ++d) { shape[group.dim-1-d] = (bbox->shape() / bbox->stride())[d]; num_elems *= shape[group.dim-1-d]; } // Don't create zero-sized components - if (num_elems == 0) - { - continue; - } + if (num_elems == 0) continue; // create the dataset on the I/O processor // skip DISTRIB=CONSTANT components from processors other than 0 hid_t memfile = -1, memdataset = -1; hid_t dataspace = -1, dataset = -1; - if (myproc == 0 && - (bbox_id == 0 || group.disttype != CCTK_DISTRIB_CONSTANT)) - { + if (dist::rank() == 0 and + (bbox_id == 0 or group.disttype != CCTK_DISTRIB_CONSTANT)) { // Construct a file-wide unique HDF5 dataset name // (only add parts with varying metadata) ostringstream datasetname; datasetname << fullname << " it=" << cctkGH->cctk_iteration << " tl=" << request->timelevel; - if (mglevels > 1) - { - datasetname << " ml=" << mglevel; - } - if (group.grouptype == CCTK_GF) - { - if (Carpet::maps > 1) - { - datasetname << " m=" << Carpet::map; - } + if (mglevels > 1) datasetname << " ml=" << mglevel; + if (group.grouptype == CCTK_GF) { + if (Carpet::maps > 1) datasetname << " m=" << Carpet::map; datasetname << " rl=" << refinementlevel; } - if (bboxes.setsize () > 1 && group.disttype != CCTK_DISTRIB_CONSTANT) - { + if (bboxes.setsize () > 1 and group.disttype != CCTK_DISTRIB_CONSTANT) { datasetname << " c=" << bbox_id; } @@ -529,21 +131,18 @@ int WriteVarUnchunked (const cGH* const cctkGH, filedatatype, dataspace, H5P_DEFAULT)); // remove an already existing dataset of the same name - if (request->check_exist) - { - H5E_BEGIN_TRY - { - H5Gunlink (writer, datasetname.str().c_str()); + if (request->check_exist) { + H5E_BEGIN_TRY { + H5Gunlink (outfile, datasetname.str().c_str()); } H5E_END_TRY; } - HDF5_ERROR (dataset = H5Dcreate (writer, datasetname.str().c_str(), + HDF5_ERROR (dataset = H5Dcreate (outfile, datasetname.str().c_str(), filedatatype, dataspace, H5P_DEFAULT)); } // Loop over all components bool first_time = true; - BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) - { + BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) { // Get the intersection of the current component with this combination // (use either the interior or exterior here, as we did above) ibbox const overlap = *bbox & @@ -551,10 +150,7 @@ int WriteVarUnchunked (const cGH* const cctkGH, boxes.at(mglevel).at(refinementlevel).at(component).interior; // Continue if this component is not part of this combination - if (overlap.empty()) - { - continue; - } + if (overlap.empty()) continue; // Copy the overlap to the local processor const ggf* ff = arrdata.at(gindex).at(Carpet::map).data.at(var); @@ -564,14 +160,12 @@ int WriteVarUnchunked (const cGH* const cctkGH, gdata* const processor_component = data->make_typed (request->vindex); processor_component->allocate (overlap, 0); - for (comm_state state(group.vartype); !state.done(); state.step()) - { + for (comm_state state(group.vartype); not state.done(); state.step()) { processor_component->copy_from (state, data, overlap); } // Write data - if (myproc == 0) - { + if (dist::rank() == 0) { const void *data = (const void *) processor_component->storage(); // As per Cactus convention, DISTRIB=CONSTANT arrays @@ -580,30 +174,26 @@ int WriteVarUnchunked (const cGH* const cctkGH, // 0. // // Warn the user if this convention is violated. - if (bbox_id > 0 && group.disttype == CCTK_DISTRIB_CONSTANT) - { + if (bbox_id > 0 and group.disttype == CCTK_DISTRIB_CONSTANT) { const void *proc0 = CCTK_VarDataPtrI (cctkGH, request->timelevel, request->vindex); - if (memcmp (proc0, data, num_elems*CCTK_VarTypeSize(group.vartype))) - { + if (memcmp (proc0, data, + num_elems * CCTK_VarTypeSize(group.vartype))) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "values for DISTRIB=CONSTANT grid variable '%s' " "(timelevel %d) differ between processors 0 and %d; " "only the array from processor 0 will be stored", fullname, request->timelevel, bbox_id); } - } - else - { + } else { hsize_t overlapshape[dim]; -#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 6 && H5_VERS_RELEASE == 4) +#if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 6 && H5_VERS_RELEASE >= 4) hsize_t overlaporigin[dim]; #else hssize_t overlaporigin[dim]; #endif - for (int d = 0; d < group.dim; ++d) - { + for (int d = 0; d < group.dim; ++d) { overlaporigin[group.dim-1-d] = ((overlap.lower() - bbox->lower()) / overlap.stride())[d]; overlapshape[group.dim-1-d] = @@ -625,8 +215,7 @@ int WriteVarUnchunked (const cGH* const cctkGH, // Add metadata information on the first time through // (have to do it inside of the COMPONENT_LOOP so that we have // access to the cGH elements) - if (first_time) - { + if (first_time) { AddAttributes (cctkGH, fullname, group.dim, refinementlevel, request, *bbox, dataset); first_time = false; @@ -641,9 +230,8 @@ int WriteVarUnchunked (const cGH* const cctkGH, // Finally create the recombined dataset in the real HDF5 file on disk // (skip DISTRIB=CONSTANT components from processors other than 0) - if (myproc == 0 && - (bbox_id == 0 || group.disttype != CCTK_DISTRIB_CONSTANT)) - { + if (dist::rank() == 0 and + (bbox_id == 0 or group.disttype != CCTK_DISTRIB_CONSTANT)) { void *data = malloc (H5Dget_storage_size (memdataset)); HDF5_ERROR (H5Dread (memdataset, filedatatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data)); @@ -667,349 +255,281 @@ int WriteVarUnchunked (const cGH* const cctkGH, } -////////////////////////////////////////////////////////////////////////////// -// private routines -////////////////////////////////////////////////////////////////////////////// -static void CheckSteerableParameters (const cGH *const cctkGH, - CarpetIOHDF5GH *myGH) +int WriteVarChunkedSequential (const cGH* const cctkGH, + hid_t outfile, + const ioRequest* const request, + bool called_from_checkpoint) { DECLARE_CCTK_PARAMETERS; - // re-parse the 'IOHDF5::out_vars' parameter if it has changed - if (strcmp (out_vars, myGH->out_vars)) - { - IOUtil_ParseVarsForOutput (cctkGH, CCTK_THORNSTRING, "IOHDF5::out_vars", - myGH->stop_on_parse_errors, out_vars, - -1, myGH->requests); - - // notify the user about the new setting - if (! CCTK_Equals (verbose, "none")) - { - char *msg = NULL; - for (int i = CCTK_NumVars () - 1; i >= 0; i--) - { - if (myGH->requests[i]) - { - char *fullname = CCTK_FullName (i); - if (! msg) - { - Util_asprintf (&msg, "Periodic HDF5 output requested for '%s'", - fullname); - } - else - { - Util_asprintf (&msg, "%s, '%s'", msg, fullname); - } - free (fullname); - } - } - if (msg) - { - CCTK_INFO (msg); - free (msg); - } - } - - // save the last setting of 'IOHDF5::out_vars' parameter - free (myGH->out_vars); - myGH->out_vars = strdup (out_vars); - } -} - - -static int OutputGH (const cGH* const cctkGH) -{ - DECLARE_CCTK_PARAMETERS; - static bool first_time = true; + char *fullname = CCTK_FullName(request->vindex); + const int gindex = CCTK_GroupIndexFromVarI (request->vindex); + assert (gindex >= 0 and gindex < (int) Carpet::arrdata.size ()); + const int var = request->vindex - CCTK_FirstVarIndexI (gindex); + assert (var >= 0 and var < CCTK_NumVars ()); + cGroup group; + CCTK_GroupData (gindex, &group); - // check if any deprecated parameters have been set in the parameter file - // (don't check after recovery though) - if (first_time) - { - if (CCTK_Equals (recover, "no") || ! *recover_file) - { - if (WarnAboutDeprecatedParameters ()) - { -#if 0 - // annoy the user if (s)he still used deprecated parameters - CCTK_WARN (1, "Now waiting 5 seconds to let your notice the " - "warning message(s) above..."); - sleep (5); -#endif - } - } - first_time = false; - } - - for (int vindex = CCTK_NumVars () - 1; vindex >= 0; vindex--) - { - if (TimeToOutput (cctkGH, vindex)) - { - TriggerOutput (cctkGH, vindex); - } + // Scalars and arrays have only one refinement level 0, + // regardless of what the current refinement level is. + // Output for them must be called in global mode. + int refinementlevel = reflevel; + if (group.grouptype == CCTK_SCALAR or group.grouptype == CCTK_ARRAY) { + assert (do_global_mode); + refinementlevel = 0; } - return (0); -} + // HDF5 doesn't like 0-dimensional arrays + if (group.grouptype == CCTK_SCALAR) group.dim = 1; + // If the user requested so, select single precision data output + hid_t memdatatype, filedatatype; + HDF5_ERROR (memdatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, 0)); + HDF5_ERROR (filedatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, + out_single_precision and not called_from_checkpoint)); -static int TimeToOutput (const cGH* const cctkGH, const int vindex) -{ - DECLARE_CCTK_ARGUMENTS; - DECLARE_CCTK_PARAMETERS; + // Traverse all maps + BEGIN_MAP_LOOP (cctkGH, group.grouptype) { + BEGIN_COMPONENT_LOOP (cctkGH, group.grouptype) { + // Using "exterior" includes ghost zones and refinement boundaries. + ibbox& bbox = arrdata.at(gindex).at(Carpet::map).dd-> + boxes.at(mglevel).at(refinementlevel).at(component).exterior; - const int numvars = CCTK_NumVars(); - assert (vindex>=0 && vindex<numvars); + // Get the shape of the HDF5 dataset (in Fortran index order) + hsize_t shape[dim]; + hsize_t num_elems = 1; + for (int d = 0; d < group.dim; ++d) { + shape[group.dim-1-d] = (bbox.shape() / bbox.stride())[d]; + num_elems *= shape[group.dim-1-d]; + } - if (CCTK_GroupTypeFromVarI (vindex) != CCTK_GF && ! do_global_mode) - { - return 0; - } + // Don't create zero-sized components + if (num_elems == 0) continue; - CarpetIOHDF5GH *myGH = - (CarpetIOHDF5GH *) CCTK_GHExtension (cctkGH, CCTK_THORNSTRING); - CheckSteerableParameters (cctkGH, myGH); + // Copy the overlap to the local processor + const ggf* ff = arrdata.at(gindex).at(Carpet::map).data.at(var); + const gdata* const data = (*ff) (request->timelevel, refinementlevel, + component, mglevel); + gdata* const processor_component = data->make_typed (request->vindex); - // check if output for this variable was requested - if (! myGH->requests[vindex]) - { - return (0); - } + processor_component->allocate (bbox, 0); + for (comm_state state(group.vartype); not state.done(); state.step()) { + processor_component->copy_from (state, data, bbox); + } - // check whether this refinement level should be output - if (! (myGH->requests[vindex]->refinement_levels & (1 << reflevel))) - { - return (0); - } + // Write data on I/O processor 0 + if (dist::rank() == 0) { + const void *data = (const void *) processor_component->storage(); - // check if output for this variable was requested individually - // by a "<varname>{ out_every = <number> }" option string - // this will overwrite the output criterion setting - const char *myoutcriterion = CCTK_EQUALS (out_criterion, "default") ? - io_out_criterion : out_criterion; - if (myGH->requests[vindex]->out_every >= 0) - { - myoutcriterion = "divisor"; - } + // As per Cactus convention, DISTRIB=CONSTANT arrays + // (including grid scalars) are assumed to be the same on + // all processors and are therefore stored only by processor 0. + // + // Warn the user if this convention is violated. + if (component > 0 and group.disttype == CCTK_DISTRIB_CONSTANT) { + const void *proc0 = CCTK_VarDataPtrI (cctkGH, request->timelevel, + request->vindex); - if (CCTK_EQUALS (myoutcriterion, "never")) - { - return (0); - } + if (memcmp (proc0, data, num_elems*CCTK_VarTypeSize(group.vartype))) { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "values for DISTRIB=CONSTANT grid variable '%s' " + "(timelevel %d) differ between processors 0 and %d; " + "only the array from processor 0 will be stored", + fullname, request->timelevel, component); + } + } else { + // Construct a file-wide unique HDF5 dataset name + // (only add parts with varying metadata) + ostringstream datasetname; + datasetname << fullname + << " it=" << cctkGH->cctk_iteration + << " tl=" << request->timelevel; + if (mglevels > 1) datasetname << " ml=" << mglevel; + if (group.grouptype == CCTK_GF) { + if (Carpet::maps > 1) datasetname << " m=" << Carpet::map; + datasetname << " rl=" << refinementlevel; + } + if (arrdata.at(gindex).at(Carpet::map).dd-> + boxes.at(mglevel).at(refinementlevel).size () > 1 and + group.disttype != CCTK_DISTRIB_CONSTANT) { + datasetname << " c=" << component; + } - // check whether to output at this iteration - bool output_this_iteration = false; - - if (CCTK_EQUALS (myoutcriterion, "iteration")) - { - int myoutevery = out_every == -2 ? io_out_every : out_every; - if (myoutevery > 0) - { - if (*this_iteration == cctk_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; - *this_iteration = cctk_iteration; - *next_output_iteration = cctk_iteration + myoutevery; - } - } - } - else if (CCTK_EQUALS (myoutcriterion, "divisor")) - { - int myoutevery = out_every == -2 ? io_out_every : out_every; - if (myGH->requests[vindex]->out_every >= 0) - { - myoutevery = myGH->requests[vindex]->out_every; - } - if (myoutevery > 0 && (cctk_iteration % myoutevery) == 0) - { - // we already decided to output this iteration - output_this_iteration = true; - } - } - else if (CCTK_EQUALS (myoutcriterion, "time")) - { - CCTK_REAL myoutdt = out_dt == -2 ? io_out_dt : out_dt; - if (myoutdt == 0 || *this_iteration == cctk_iteration) - { - output_this_iteration = true; - } - else if (myoutdt > 0 && (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; - *this_iteration = cctk_iteration; - *next_output_time = cctk_time + myoutdt; - } - } + // remove an already existing dataset of the same name + if (request->check_exist) { + H5E_BEGIN_TRY { + H5Gunlink (outfile, datasetname.str().c_str()); + } H5E_END_TRY; + } - if (! output_this_iteration) - { - return 0; - } + hsize_t shape[dim]; + hssize_t origin[dim]; + for (int d = 0; d < group.dim; ++d) { + origin[group.dim-1-d] = (bbox.lower() / bbox.stride())[d]; + shape[group.dim-1-d] = (bbox.shape() / bbox.stride())[d]; + } - 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; - } + // Write the component as an individual dataset + hid_t dataspace, dataset; + HDF5_ERROR (dataspace = H5Screate_simple (group.dim, shape, NULL)); + HDF5_ERROR (dataset = H5Dcreate (outfile, datasetname.str().c_str(), + filedatatype, dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Sclose (dataspace)); + HDF5_ERROR (H5Dwrite (dataset, memdatatype, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data)); + AddAttributes (cctkGH, fullname, group.dim, refinementlevel, + request, bbox, dataset); + HDF5_ERROR (H5Dclose (dataset)); + } - assert (last_output.at(mglevel).at(reflevel).at(vindex) < cctk_iteration); + } // if dist::rank() == 0 - // Should be output during this iteration - return 1; -} + // Delete temporary copy of this component + delete processor_component; + } END_COMPONENT_LOOP; + } END_MAP_LOOP; -static int TriggerOutput (const cGH* const cctkGH, const int vindex) -{ - char *fullname = CCTK_FullName (vindex); - const char *varname = CCTK_VarName (vindex); - const int retval = OutputVarAs (cctkGH, fullname, varname); free (fullname); - last_output.at(mglevel).at(reflevel).at(vindex) = cctkGH->cctk_iteration; - - return (retval); + return 0; } -static void GetVarIndex (int vindex, const char* optstring, void* arg) +int WriteVarChunkedParallel (const cGH* const cctkGH, + hid_t outfile, + const ioRequest* const request, + bool called_from_checkpoint) { - if (optstring) - { - char *fullname = CCTK_FullName (vindex); - CCTK_VWarn (2, __LINE__, __FILE__, CCTK_THORNSTRING, - "Option string '%s' will be ignored for HDF5 output of " - "variable '%s'", optstring, fullname); - free (fullname); - } + DECLARE_CCTK_PARAMETERS; - *((int *) arg) = vindex; -} + char *fullname = CCTK_FullName(request->vindex); + const int gindex = CCTK_GroupIndexFromVarI (request->vindex); + assert (gindex >= 0 and gindex < (int) Carpet::arrdata.size ()); + const int var = request->vindex - CCTK_FirstVarIndexI (gindex); + assert (var >= 0 and var < CCTK_NumVars ()); + cGroup group; + CCTK_GroupData (gindex, &group); -static int OutputVarAs (const cGH* const cctkGH, const char* const fullname, - const char* const alias) -{ - DECLARE_CCTK_ARGUMENTS; - DECLARE_CCTK_PARAMETERS; + // Scalars and arrays have only one refinement level 0, + // regardless of what the current refinement level is. + // Output for them must be called in global mode. + int refinementlevel = reflevel; + if (group.grouptype == CCTK_SCALAR or group.grouptype == CCTK_ARRAY) { + assert (do_global_mode); + refinementlevel = 0; + } - int vindex = -1; + // HDF5 doesn't like 0-dimensional arrays + if (group.grouptype == CCTK_SCALAR) group.dim = 1; - if (CCTK_TraverseString (fullname, GetVarIndex, &vindex, CCTK_VAR) < 0) - { - CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "error while parsing variable name '%s' (alias name '%s')", - fullname, alias); - return (-1); - } + // If the user requested so, select single precision data output + hid_t memdatatype, filedatatype; + HDF5_ERROR (memdatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, 0)); + HDF5_ERROR (filedatatype = CCTKtoHDF5_Datatype (cctkGH, group.vartype, + out_single_precision and not called_from_checkpoint)); - if (vindex < 0) - { - return (-1); - } + // Traverse all maps + BEGIN_MAP_LOOP (cctkGH, group.grouptype) { + BEGIN_LOCAL_COMPONENT_LOOP (cctkGH, group.grouptype) { - const int group = CCTK_GroupIndexFromVarI (vindex); - assert (group>=0 && group<(int)Carpet::arrdata.size()); + const ggf* ff = arrdata.at(gindex).at(Carpet::map).data.at(var); + const ibbox& bbox = (*ff) (request->timelevel, refinementlevel, + group.disttype == CCTK_DISTRIB_CONSTANT ? + 0 : component, mglevel)->extent(); - // Check for storage - if (! CCTK_QueryGroupStorageI(cctkGH, group)) - { - CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "Cannot output variable '%s' because it has no storage", - fullname); - return (0); - } + // Don't create zero-sized components + if (bbox.empty()) continue; + + // As per Cactus convention, DISTRIB=CONSTANT arrays + // (including grid scalars) are assumed to be the same on + // all processors and are therefore stored only by processor 0. + void* data = cctkGH->data[request->vindex][request->timelevel]; + const void* mydata = data; + if (group.disttype == CCTK_DISTRIB_CONSTANT) { + + MPI_Datatype datatype; + switch (group.vartype) { +#define TYPECASE(N,T) \ + case N: { T dummy; datatype = dist::datatype(dummy); } break; +#include "carpet_typecase.hh" +#undef TYPECASE + default: assert (0 and "invalid datatype"); + } - const int grouptype = CCTK_GroupTypeI(group); - if (grouptype == CCTK_SCALAR || grouptype == CCTK_ARRAY) - { - assert (do_global_mode); - } + const size_t size = bbox.size() * CCTK_VarTypeSize (group.vartype); + if (dist::rank() > 0) { + data = malloc (size); + } + MPI_Bcast (data, bbox.size(), datatype, 0, MPI_COMM_WORLD); + + if (memcmp (mydata, data, size)) { + CCTK_VWarn (2, __LINE__, __FILE__, CCTK_THORNSTRING, + "values for DISTRIB=CONSTANT grid variable '%s' " + "(timelevel %d) differ between processors 0 and %d; " + "only the array from processor 0 will be stored", + fullname, request->timelevel, component); + } + } - const int myproc = CCTK_MyProc (cctkGH); - - /* 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); - - // Invent a file name - const CarpetIOHDF5GH *myGH = - (CarpetIOHDF5GH *) CCTK_GHExtension (cctkGH, CCTK_THORNSTRING); - ostringstream filenamebuf; - filenamebuf << myGH->out_dir << alias << out_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 (myproc == 0) - { - // If this is the first time, then create and truncate the file - if (do_truncate.at(vindex)) - { - struct stat fileinfo; - if (IO_TruncateOutputFiles (cctkGH) || 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; + // Construct a file-wide unique HDF5 dataset name + // (only add parts with varying metadata) + ostringstream datasetname; + datasetname << fullname + << " it=" << cctkGH->cctk_iteration + << " tl=" << request->timelevel; + if (mglevels > 1) datasetname << " ml=" << mglevel; + if (group.grouptype == CCTK_GF) { + if (Carpet::maps > 1) datasetname << " m=" << Carpet::map; + datasetname << " rl=" << refinementlevel; + } + if (arrdata.at(gindex).at(Carpet::map).dd-> + boxes.at(mglevel).at(refinementlevel).size () > 1 and + group.disttype != CCTK_DISTRIB_CONSTANT) { + datasetname << " c=" << component; } - } - // Open the file - HDF5_ERROR (writer = H5Fopen (filename, H5F_ACC_RDWR, H5P_DEFAULT)); - } + // remove an already existing dataset of the same name + if (request->check_exist) { + H5E_BEGIN_TRY { + H5Gunlink (outfile, datasetname.str().c_str()); + } H5E_END_TRY; + } - if (CCTK_Equals (verbose, "full")) - { - CCTK_VInfo (CCTK_THORNSTRING, - "Writing variable '%s' on mglevel %d reflevel %d", - fullname, mglevel, reflevel); - } - if (out_unchunked) - { - WriteVarUnchunked (cctkGH, writer, request, 0); - } - else - { - WriteVarChunked (cctkGH, writer, request, 0); - } + // Get the shape of the HDF5 dataset (in Fortran index order) + hsize_t shape[dim]; + hssize_t origin[dim]; + for (int d = 0; d < group.dim; ++d) { + origin[group.dim-1-d] = (bbox.lower() / bbox.stride())[d]; + shape[group.dim-1-d] = (bbox.shape() / bbox.stride())[d]; + } - // Close the file - if (writer >= 0) - { - HDF5_ERROR (H5Fclose (writer)); - } + // Write the component as an individual dataset + hid_t dataspace, dataset; + HDF5_ERROR (dataspace = H5Screate_simple (group.dim, shape, NULL)); + HDF5_ERROR (dataset = H5Dcreate (outfile, datasetname.str().c_str(), + filedatatype, dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Sclose (dataspace)); + HDF5_ERROR (H5Dwrite (dataset, memdatatype, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data)); + AddAttributes (cctkGH, fullname, group.dim, refinementlevel, + request, bbox, dataset); + HDF5_ERROR (H5Dclose (dataset)); + + if (data != mydata) free (data); + + } END_LOCAL_COMPONENT_LOOP; + } END_MAP_LOOP; - // Don't truncate again - do_truncate.at(vindex) = false; + free (fullname); - return (0); + return 0; } +// add attributes to an HDF5 dataset static void AddAttributes (const cGH *const cctkGH, const char *fullname, int vdim, int refinementlevel, const ioRequest* request, @@ -1018,150 +538,92 @@ static void AddAttributes (const cGH *const cctkGH, const char *fullname, DECLARE_CCTK_ARGUMENTS; + // Legacy arguments + hid_t attr, dataspace, datatype; + HDF5_ERROR (dataspace = H5Screate (H5S_SCALAR)); + HDF5_ERROR (attr = H5Acreate (dataset, "level", H5T_NATIVE_INT, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, H5T_NATIVE_INT, &refinementlevel)); + HDF5_ERROR (H5Aclose (attr)); + + HDF5_ERROR (attr = H5Acreate (dataset, "carpet_mglevel", H5T_NATIVE_INT, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, H5T_NATIVE_INT, &mglevel)); + HDF5_ERROR (H5Aclose (attr)); + + HDF5_ERROR (attr = H5Acreate (dataset, "timestep", H5T_NATIVE_INT, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, H5T_NATIVE_INT, &cctk_iteration)); + HDF5_ERROR (H5Aclose (attr)); + + HDF5_ERROR (attr = H5Acreate (dataset, "group_timelevel", H5T_NATIVE_INT, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, H5T_NATIVE_INT, &request->timelevel)); + HDF5_ERROR (H5Aclose (attr)); + + HDF5_ERROR (attr = H5Acreate (dataset, "time", HDF5_REAL, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, HDF5_REAL, &cctk_time)); + HDF5_ERROR (H5Aclose (attr)); + + HDF5_ERROR (datatype = H5Tcopy (H5T_C_S1)); + HDF5_ERROR (H5Tset_size (datatype, strlen (fullname))); + HDF5_ERROR (attr = H5Acreate (dataset, "name", datatype, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, datatype, fullname)); + HDF5_ERROR (H5Aclose (attr)); + +#if 0 + // FIXME TR: output bbox and nghostzones again for chunked output + // Cactus arguments + WriteAttribute (dataset, "cctk_bbox", cctk_bbox, 2*vdim); + WriteAttribute (dataset, "cctk_nghostzones", cctk_nghostzones, vdim); +#endif + // write bbox attributes if we have coordinate system info CCTK_REAL origin[dim], delta[dim]; char *groupname = CCTK_GroupNameFromVarI (request->vindex); int coord_system_handle = Coord_GroupSystem (cctkGH, groupname); free (groupname); + HDF5_ERROR (H5Sclose (dataspace)); + hsize_t size = vdim; + HDF5_ERROR (dataspace = H5Screate_simple (1, &size, NULL)); + CCTK_INT coord_handles[dim]; - if (coord_system_handle >= 0 && + if (coord_system_handle >= 0 and Util_TableGetIntArray (coord_system_handle, vdim, - coord_handles, "COORDINATES") >= 0) - { + coord_handles, "COORDINATES") >= 0) { const ibbox& baseext = vdd.at(Carpet::map)->bases.at(mglevel).at(reflevel).exterior; const ivect pos = (bbox.lower() - baseext.lower()) / bbox.stride(); - for (int d = 0; d < vdim; d++) - { + for (int d = 0; d < vdim; d++) { Util_TableGetReal (coord_handles[d], &origin[d], "COMPMIN"); Util_TableGetReal (coord_handles[d], &delta[d], "DELTA"); delta[d] /= cctk_levfac[d]; origin[d] += delta[d] * (cctk_levoff[d] / cctk_levoffdenom[d] + pos[d]); } - WriteAttribute (dataset, "origin", origin, vdim); - WriteAttribute (dataset, "delta", delta, vdim); + HDF5_ERROR (attr = H5Acreate (dataset, "origin", HDF5_REAL, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, HDF5_REAL, origin)); + HDF5_ERROR (H5Aclose (attr)); + HDF5_ERROR (attr = H5Acreate (dataset, "delta", HDF5_REAL, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, HDF5_REAL, delta)); + HDF5_ERROR (H5Aclose (attr)); } - // Write FlexIO attributes - WriteAttribute (dataset, "level", refinementlevel); - vect<int, dim> iorigin = bbox.lower() / bbox.stride(); - WriteAttribute (dataset, "iorigin", &iorigin[0], vdim); - - WriteAttribute (dataset, "time", cctk_time); - WriteAttribute (dataset, "timestep", cctk_iteration); - - // Legacy arguments - WriteAttribute (dataset, "name", fullname); - WriteAttribute (dataset, "group_timelevel", request->timelevel); - -#if 0 - // FIXME TR: output bbox and nghostzones again for chunked output - // Cactus arguments - WriteAttribute (dataset, "cctk_bbox", cctk_bbox, 2*vdim); - WriteAttribute (dataset, "cctk_nghostzones", cctk_nghostzones, vdim); -#endif - - // Carpet arguments - WriteAttribute (dataset, "carpet_version", CARPET_VERSION); - WriteAttribute (dataset, "carpet_mglevel", mglevel); - WriteAttribute (dataset, "carpet_reflevel", refinementlevel); - - // Simulation arguments - if (CCTK_IsFunctionAliased ("UniqueSimulationID")) { - char const * const job_id - = static_cast<char const *> (UniqueSimulationID (cctkGH)); - WriteAttribute (dataset, "simulation id", job_id); - } -} - - -static int WarnAboutDeprecatedParameters (void) -{ - DECLARE_CCTK_PARAMETERS; - int warnings = 0; - char buffer[20]; - - if (CCTK_ParameterQueryTimesSet ("out3D_dir", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_dir", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_dir' is deprecated, please use " - "'IOHDF5::out_dir' instead"); - CCTK_ParameterSet ("out_dir", CCTK_THORNSTRING, out3D_dir); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("out3D_vars", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_vars", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_vars' is deprecated, please use " - "'IOHDF5::out_vars' instead"); - CCTK_ParameterSet ("out_vars", CCTK_THORNSTRING, out3D_vars); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("out3D_extension", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_extension", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_extension' is deprecated, please use " - "'IOHDF5::out_extension' instead"); - CCTK_ParameterSet ("out_extension", CCTK_THORNSTRING, out3D_extension); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("out3D_criterion", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_criterion", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_criterion' is deprecated, please use " - "'IOHDF5::out_criterion' instead"); - CCTK_ParameterSet ("out_criterion", CCTK_THORNSTRING, out3D_criterion); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("out3D_every", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_every", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_every' is deprecated, please use " - "'IOHDF5::out_every' instead"); - snprintf (buffer, sizeof (buffer), "%d", out3D_every); - CCTK_ParameterSet ("out_every", CCTK_THORNSTRING, buffer); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("out3D_dt", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("out_dt", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::out3D_dt' is deprecated, please use " - "'IOHDF5::out_dt' instead"); - snprintf (buffer, sizeof (buffer), "%f", (double)out3D_dt); - CCTK_ParameterSet ("out_dt", CCTK_THORNSTRING, buffer); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("in3D_dir", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("in_dir", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::in3D_dir' is deprecated, please use " - "'IOHDF5::in_dir' instead"); - CCTK_ParameterSet ("in_dir", CCTK_THORNSTRING, in3D_dir); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("in3D_vars", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("in_vars", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::in3D_vars' is deprecated, please use " - "'IOHDF5::in_vars' instead"); - CCTK_ParameterSet ("in_vars", CCTK_THORNSTRING, in3D_vars); - warnings++; - } - if (CCTK_ParameterQueryTimesSet ("in3D_extension", CCTK_THORNSTRING) > - CCTK_ParameterQueryTimesSet ("in_extension", CCTK_THORNSTRING)) - { - CCTK_WARN (2, "Parameter 'IOHDF5::in3D_extension' is deprecated, please use " - "'IOHDF5::in_extension' instead"); - CCTK_ParameterSet ("in_extension", CCTK_THORNSTRING, in3D_extension); - warnings++; - } + HDF5_ERROR (attr = H5Acreate (dataset, "iorigin", H5T_NATIVE_INT, + dataspace, H5P_DEFAULT)); + HDF5_ERROR (H5Awrite (attr, H5T_NATIVE_INT, &iorigin[0])); + HDF5_ERROR (H5Aclose (attr)); - return (warnings); + HDF5_ERROR (H5Tclose (datatype)); + HDF5_ERROR (H5Sclose (dataspace)); } |