aboutsummaryrefslogtreecommitdiff
path: root/CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc
diff options
context:
space:
mode:
Diffstat (limited to 'CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc')
-rw-r--r--CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc586
1 files changed, 586 insertions, 0 deletions
diff --git a/CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc b/CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc
new file mode 100644
index 000000000..47dbe7344
--- /dev/null
+++ b/CarpetDev/CarpetIONirvana/src/CarpetIONirvana.cc
@@ -0,0 +1,586 @@
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "util_Table.h"
+#include "cctk.h"
+#include "cctk_Arguments.h"
+#include "cctk_Parameters.h"
+#include "cctk_Version.h"
+
+#include "CactusBase/IOUtil/src/ioGH.h"
+#include "CactusBase/IOUtil/src/ioutil_CheckpointRecovery.h"
+
+#include "CarpetTimers.hh"
+
+#include "CarpetIONirvana.hh"
+
+#include "defs.hh"
+#include "gh.hh"
+
+
+
+namespace CarpetIONirvana
+{
+
+using namespace std;
+using namespace Carpet;
+using namespace Nirvana;
+
+
+// Variable definitions
+
+// when was the last checkpoint written ?
+static int last_checkpoint_iteration = -1;
+static CCTK_REAL last_checkpoint_walltime;
+
+
+// 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);
+
+// general checkpoint routine
+static void Checkpoint (const cGH* const cctkGH, int called_from);
+
+// callback for I/O parameter parsing routine
+static void GetVarIndex (int vindex, const char* optstring, void* arg);
+
+static void CheckSteerableParameters (const cGH *const cctkGH,
+ CarpetIONirvanaGH *myGH);
+
+
+//////////////////////////////////////////////////////////////////////////////
+// public routines
+//////////////////////////////////////////////////////////////////////////////
+
+int CarpetIONirvana_Startup (void)
+{
+ CCTK_RegisterBanner ("Carpet Data Nirvana I/O");
+
+ const int GHExtension = CCTK_RegisterGHExtension (CCTK_THORNSTRING);
+ CCTK_RegisterGHExtensionSetupGH (GHExtension, SetupGH);
+
+ /*IONirvana<0>::Startup();
+ IONirvana<1>::Startup();
+ IONirvana<2>::Startup();*/
+
+ return (0);
+}
+
+
+// Called at basegrid during regular startup
+void CarpetIONirvana_Init (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+
+ *this_iteration = -1;
+ *next_output_iteration = 0;
+ *next_output_time = cctk_time;
+
+ for (int d=0; d<3; ++d) {
+ this_iteration_slice[d] = 0;
+ last_output_iteration_slice[d] = 0;
+ last_output_time_slice[d] = cctk_time;
+ }
+}
+
+
+
+
+hid_t CCTKtoHDF5_Datatype (const cGH* const cctkGH,
+ int cctk_type, bool single_precision)
+{
+ hid_t retval;
+
+ const CarpetIONirvanaGH *myGH =
+ (CarpetIONirvanaGH *) CCTK_GHExtension (cctkGH, CCTK_THORNSTRING);
+
+ /*switch (cctk_type) {
+
+ case CCTK_VARIABLE_CHAR: retval = HDF5_CHAR; break;
+
+ case CCTK_VARIABLE_INT: retval = HDF5_INT; break;
+#ifdef CCTK_INT1
+ case CCTK_VARIABLE_INT1: retval = H5T_NATIVE_CHAR; break;
+#endif
+#ifdef CCTK_INT2
+ case CCTK_VARIABLE_INT2: retval = H5T_NATIVE_SHORT; break;
+#endif
+#ifdef CCTK_INT4
+ case CCTK_VARIABLE_INT4: retval = H5T_NATIVE_INT; break;
+#endif
+#ifdef CCTK_INT8
+ case CCTK_VARIABLE_INT8: retval = H5T_NATIVE_LLONG; break;
+#endif
+
+ case CCTK_VARIABLE_REAL: retval = HDF5_REAL;
+#ifdef CCTK_REAL4
+ if (single_precision) {
+ retval = H5T_NATIVE_FLOAT;
+ }
+#endif
+ break;
+
+ case CCTK_VARIABLE_COMPLEX: retval = myGH->HDF5_COMPLEX;
+#ifdef CCTK_REAL4
+ if (single_precision) {
+ retval = myGH->HDF5_COMPLEX8;
+ }
+#endif
+ break;
+
+#ifdef CCTK_REAL4
+ case CCTK_VARIABLE_REAL4: retval = H5T_NATIVE_FLOAT; break;
+ case CCTK_VARIABLE_COMPLEX8: retval = myGH->HDF5_COMPLEX8; break;
+#endif
+#ifdef CCTK_REAL8
+ case CCTK_VARIABLE_REAL8: retval = H5T_NATIVE_DOUBLE; break;
+ case CCTK_VARIABLE_COMPLEX16: retval = myGH->HDF5_COMPLEX16; break;
+#endif
+#ifdef CCTK_REAL16
+ case CCTK_VARIABLE_REAL16: retval = H5T_NATIVE_LDOUBLE; break;
+ case CCTK_VARIABLE_COMPLEX32: retval = myGH->HDF5_COMPLEX32; break;
+#endif
+
+ default: CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Unsupported CCTK variable datatype %d", cctk_type);
+ retval = -1;
+ }*/
+
+ return (retval);
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// private routines
+//////////////////////////////////////////////////////////////////////////////
+static void* SetupGH (tFleshConfig* const fleshconfig,
+ const int convLevel, cGH* const cctkGH)
+{
+ DECLARE_CCTK_PARAMETERS;
+
+ int error_count = 0;
+
+ // register CarpetIONirvana's routines as a new I/O method
+ const int IOMethod = CCTK_RegisterIOMethod ("IONirvana");
+ CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH);
+ CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs);
+ CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput);
+ CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput);
+
+ if (not CCTK_Equals (verbose, "none")) {
+ CCTK_INFO ("I/O Method 'Nirvana': Sending data to Nirvana ");
+ }
+
+ const int numvars = CCTK_NumVars ();
+
+ // allocate a new GH extension structure
+ CarpetIONirvanaGH* myGH = new CarpetIONirvanaGH;
+
+ myGH->requests.resize(numvars);
+ myGH->out_vars = strdup ("");
+ myGH->out_every_default = out_every - 1;
+
+ // initial I/O parameter check
+ myGH->out_dir = 0;
+ myGH->stop_on_parse_errors = strict_io_parameter_check;
+ CheckSteerableParameters (cctkGH, myGH);
+ myGH->stop_on_parse_errors = 0;
+
+
+ return (myGH);
+}
+
+
+static void CheckSteerableParameters (const cGH *const cctkGH,
+ CarpetIONirvanaGH *myGH)
+{
+ DECLARE_CCTK_PARAMETERS;
+
+ // re-parse the 'IOHDF5::out_dir' parameter if it has changed
+ const char *my_out_dir = *out_dir ? out_dir : io_out_dir;
+ char *the_out_dir;
+ if (strcmp (my_out_dir, ".")) {
+ int i = strlen (my_out_dir);
+ if (not strstr (my_out_dir, "%u")) {
+ the_out_dir = (char*) malloc (i + 2);
+ strcpy (the_out_dir, my_out_dir);
+ the_out_dir[i] = '/';
+ the_out_dir[i+1] = 0;
+ } else {
+ // TODO: ensure that there is exactly one "%u" and no other "%"
+ // substrings, except possibly "%%".
+ the_out_dir = (char*) malloc (i + 20);
+ snprintf (the_out_dir, i+19, my_out_dir, dist::rank());
+ strcat (the_out_dir, "/");
+ }
+ } else {
+ the_out_dir = strdup ("");
+ }
+
+ if (not myGH->out_dir or strcmp (the_out_dir, myGH->out_dir)) {
+ free (myGH->out_dir);
+ myGH->out_dir = the_out_dir;
+
+ // create the output directory
+ int result = IOUtil_CreateDirectory (cctkGH, myGH->out_dir,
+ true,
+ dist::rank());
+ if (result < 0) {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Problem creating HDF5 output directory '%s'", myGH->out_dir);
+ } else if (result > 0 and CCTK_Equals (verbose, "full")) {
+ CCTK_VInfo (CCTK_THORNSTRING,
+ "HDF5 output directory '%s' already exists", myGH->out_dir);
+ }
+ } else {
+ free (the_out_dir);
+ }
+
+ // re-parse the 'IONirvana::out_vars' parameter if it has changed
+ if (strcmp (out_vars, myGH->out_vars)) {
+#ifdef IOUTIL_PARSER_HAS_OUT_DT
+ IOUtil_ParseVarsForOutput (cctkGH, CCTK_THORNSTRING, "IONirvana::out_vars",
+ myGH->stop_on_parse_errors, out_vars,
+ -1, -1.0, &myGH->requests[0]);
+#else
+ IOUtil_ParseVarsForOutput (cctkGH, CCTK_THORNSTRING, "IONirvana::out_vars",
+ myGH->stop_on_parse_errors, out_vars,
+ -1, &myGH->requests[0]);
+#endif
+
+ // notify the user about the new setting
+ if (not CCTK_Equals (verbose, "none")) {
+ int count = 0;
+ ostringstream msg;
+ msg << "Periodic scalar output requested for:";
+ for (int vi=0; vi<CCTK_NumVars(); ++vi) {
+ if (myGH->requests[vi]) {
+ ++count;
+ char* const fullname = CCTK_FullName(vi);
+ msg << eol << " " << fullname;
+ free (fullname);
+ }
+ }
+ if (count > 0) {
+ CCTK_INFO (msg.str().c_str());
+ }
+ }
+
+ // 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)
+{
+ static Carpet::Timer timer ("CarpetIONirvana::OutputGH");
+ timer.start();
+ for (int vindex = CCTK_NumVars () - 1; vindex >= 0; vindex--) {
+ if (TimeToOutput (cctkGH, vindex)) {
+ TriggerOutput (cctkGH, vindex);
+ }
+ }
+ timer.stop();
+
+ return (0);
+}
+
+
+static int TimeToOutput (const cGH* const cctkGH, const int vindex)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ const int numvars = CCTK_NumVars();
+ assert (vindex>=0 and vindex<numvars);
+
+ if (CCTK_GroupTypeFromVarI (vindex) != CCTK_GF and not do_global_mode) {
+ return 0;
+ }
+
+ CarpetIONirvanaGH *myGH =
+ (CarpetIONirvanaGH *) CCTK_GHExtension (cctkGH, CCTK_THORNSTRING);
+ CheckSteerableParameters (cctkGH, myGH);
+
+ // check if output for this variable was requested
+ if (not myGH->requests[vindex]) {
+ return (0);
+ }
+
+ // check whether this refinement level should be output
+ if (not (myGH->requests[vindex]->refinement_levels & (1 << reflevel))) {
+ return (0);
+ }
+
+ // 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";
+ }
+
+ if (CCTK_EQUALS (myoutcriterion, "never")) {
+ return (0);
+ }
+
+ // 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 and (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 or *this_iteration == cctk_iteration) {
+ output_this_iteration = true;
+ } else if (myoutdt > 0) {
+ int do_output =
+ (cctk_time / cctk_delta_time >=
+ *next_output_time / cctk_delta_time - 1.0e-12);
+ MPI_Bcast (&do_output, 1, MPI_INT, 0, dist::comm());
+ if (do_output) {
+ // it is time for the next output
+ output_this_iteration = true;
+ *this_iteration = cctk_iteration;
+ *next_output_time = cctk_time + myoutdt;
+ }
+ }
+ }
+
+ return output_this_iteration ? 1 : 0;
+}
+
+
+static int TriggerOutput (const cGH* const cctkGH, const int vindex)
+{
+ DECLARE_CCTK_PARAMETERS;
+ int retval;
+
+ char* const fullname = CCTK_FullName(vindex);
+
+ const int gindex = CCTK_GroupIndexFromVarI(vindex);
+ char* const groupname = CCTK_GroupName(gindex);
+ for (char* p=groupname; *p; ++p) *p=tolower(*p);
+ retval = OutputVarAs (cctkGH, fullname, groupname);
+ free (groupname);
+
+ free (fullname);
+
+ return (retval);
+}
+
+
+static void GetVarIndex (int vindex, const char* optstring, void* arg)
+{
+ if (optstring) {
+ char *fullname = CCTK_FullName (vindex);
+ CCTK_VWarn (2, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Option string '%s' will be ignored for Nirvana output of "
+ "variable '%s'", optstring, fullname);
+ free (fullname);
+ }
+
+ *((int *) arg) = vindex;
+}
+
+
+static int OutputVarAs (const cGH* const cctkGH, const char* const fullname,
+ const char* const alias)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ int error_count = 0;
+ int vindex = -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 (vindex < 0) {
+ return (-1);
+ }
+
+ const int group = CCTK_GroupIndexFromVarI (vindex);
+ assert (group >= 0);
+ cGroup groupdata;
+ CCTK_GroupData (group, &groupdata);
+ if (groupdata.grouptype == CCTK_SCALAR or groupdata.grouptype == CCTK_ARRAY) {
+ assert (do_global_mode);
+ }
+
+ // get the default I/O request for this variable
+ const CarpetIONirvanaGH *myGH =
+ (CarpetIONirvanaGH *) CCTK_GHExtension (cctkGH, CCTK_THORNSTRING);
+ ioRequest* request = myGH->requests[vindex];
+ if (not request) {
+#ifdef IOUTIL_PARSER_HAS_OUT_DT
+ request = IOUtil_DefaultIORequest (cctkGH, vindex, 1, -1.0);
+#else
+ request = IOUtil_DefaultIORequest (cctkGH, vindex, 1);
+#endif
+ }
+
+ // Get grid hierarchy extentsion from IOUtil
+ const ioGH * const iogh = (const ioGH *) CCTK_GHExtension (cctkGH, "IO");
+ assert (iogh);
+
+
+ // Invent a base file name
+ int ioproc = 0, nfiles = 1;
+ string filename;
+ filename.append (myGH->out_dir);
+ //filename.append (alias);
+ filename.append("cactus-simulation-output");
+ if (not (groupdata.disttype == CCTK_DISTRIB_CONSTANT or
+ dist::size() == 1)) {
+ ioproc = dist::rank();
+ nfiles = dist::size();
+ }
+
+ // check if the file has been created already
+ typedef std::map<string, vector<vector<vector<int> > > > filelist;
+ static filelist created_files;
+ filelist::iterator thisfile = created_files.find (filename);
+ bool is_new_file = thisfile == created_files.end();
+ if (is_new_file) {
+ int const numvars = CCTK_NumVars ();
+ vector<vector<vector<int> > > last_outputs; // [ml][rl][var]
+ last_outputs.resize (mglevels);
+ for (int ml = 0; ml < mglevels; ++ml) {
+ last_outputs[ml].resize (maxreflevels);
+ for (int rl = 0; rl < maxreflevels; ++rl) {
+ last_outputs[ml][rl].resize (numvars, cctk_iteration - 1);
+ }
+ }
+ thisfile = created_files.insert (thisfile,
+ filelist::value_type (filename,
+ last_outputs));
+ assert (thisfile != created_files.end());
+ }
+
+ const int firstvar = CCTK_FirstVarIndexI(group);
+ const int numvars = CCTK_NumVarsInGroupI(group);
+
+ // check if this variable has been output already during this iteration
+ int& last_output = thisfile->second.at(mglevel).at(reflevel).at(vindex);
+ if (last_output == cctk_iteration) {
+ // Has already been output during this iteration
+ if (vindex == firstvar + numvars - 1) {
+ 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 < cctk_iteration);
+ last_output = cctk_iteration;
+
+ // Check for storage
+ if (not CCTK_QueryGroupStorageI (cctkGH, group)) {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Cannot output variable '%s' because it has no storage",
+ fullname);
+ return (0);
+ }
+
+ // Open the output file if this is a designated I/O processor
+ CCTK_REAL io_files = 0;
+ CCTK_REAL io_bytes = 0;
+ BeginTimingIO (cctkGH);
+
+ if (CCTK_Equals (verbose, "full")) {
+ CCTK_VInfo (CCTK_THORNSTRING,
+ "Writing variable '%s' on mglevel %d reflevel %d",
+ fullname, mglevel, reflevel);
+ }
+ for (int var = firstvar; var < firstvar + numvars; var++) {
+ ioRequest* r = myGH->requests[var];
+ if (not r) {
+#ifdef IOUTIL_PARSER_HAS_OUT_DT
+ r = IOUtil_DefaultIORequest (cctkGH, var, 1, -1.0);
+#else
+ r = IOUtil_DefaultIORequest (cctkGH, var, 1);
+#endif
+ }
+ if (groupdata.disttype == CCTK_DISTRIB_CONSTANT) {
+ error_count += WriteVar(cctkGH, filename, ioproc, io_bytes, r);
+ }
+ else
+ error_count += WriteVar(cctkGH, filename, ioproc, io_bytes, r);
+
+ if (r != myGH->requests[var]) IOUtil_FreeIORequest (&r);
+
+ // mark this variable to have been output at this iteration
+ thisfile->second.at(mglevel).at(reflevel).at(var) = cctk_iteration;
+ }
+
+ // free I/O request structure
+ if (request != myGH->requests[vindex]) {
+ IOUtil_FreeIORequest (&request);
+ }
+
+ // Close the file
+
+ EndTimingIO (cctkGH, io_files, io_bytes, true);
+
+ if (error_count > 0 and abort_on_io_errors) {
+ CCTK_WARN (0, "Aborting simulation due to previous I/O errors");
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+} // namespace CarpetIONirvana