aboutsummaryrefslogtreecommitdiff
path: root/CarpetDev/CarpetIOF5_standalone/src/IOF5.cc
diff options
context:
space:
mode:
Diffstat (limited to 'CarpetDev/CarpetIOF5_standalone/src/IOF5.cc')
-rw-r--r--CarpetDev/CarpetIOF5_standalone/src/IOF5.cc694
1 files changed, 694 insertions, 0 deletions
diff --git a/CarpetDev/CarpetIOF5_standalone/src/IOF5.cc b/CarpetDev/CarpetIOF5_standalone/src/IOF5.cc
new file mode 100644
index 000000000..1173f5228
--- /dev/null
+++ b/CarpetDev/CarpetIOF5_standalone/src/IOF5.cc
@@ -0,0 +1,694 @@
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+// force HDF5 1.8.x installations to use the new API
+#define H5Dcreate_vers 2
+
+#include <hdf5.h>
+
+#include "cctk.h"
+#include "cctk_Arguments.h"
+#include "cctk_Parameters.h"
+
+#include "CactusBase/IOUtil/src/ioGH.h"
+#include "CactusBase/IOUtil/src/ioutil_CheckpointRecovery.h"
+
+#include "carpet.hh"
+
+#include "defs.hh"
+
+#include "extending.hh"
+#include "file.hh"
+#include "utils.hh"
+#include "writer.hh"
+
+
+
+namespace CarpetIOF5 {
+
+
+
+ int const Error_none = 0; // no error
+
+ int const Error_illegal_varname = -1;
+ int const Error_group_has_no_storage = -2;
+
+ int const Error_lonely_option_string = -3;
+ int const Error_unterminated_option_string = -4;
+ int const Error_garbage_after_option_string = -5;
+ int const Error_invalid_variable_name = -6;
+
+
+
+ extern "C" int
+ CarpetIOF5_Startup ();
+
+ static void *
+ Setup (tFleshConfig * const fleshconfig,
+ int const convlevel,
+ cGH * const cctkGH);
+
+ extern "C" void
+ CarpetIOF5_Init (CCTK_ARGUMENTS);
+
+
+
+ static int
+ OutputGH (cGH const * cctkGH);
+
+ static void
+ mark_variables (int variable,
+ char const * options,
+ void * ptr);
+
+
+
+ static int
+ TimeToOutput (cGH const * cctkGH,
+ int variable);
+
+
+
+ static int
+ TriggerOutput (cGH const * cctkGH,
+ int variable);
+
+
+
+ static int
+ OutputVarAs (cGH const * cctkGH,
+ char const * varname,
+ char const * alias);
+
+
+
+ static void
+ WriteParameters (F5::file_t & file);
+
+
+
+ static string
+ generate_filename (cGH const * cctkGH,
+ int variable);
+
+
+
+ int
+ CarpetIOF5_Startup ()
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ if (verbose) CCTK_INFO ("Startup");
+ return extending_t::create (Setup);
+ }
+
+
+
+ void *
+ Setup (tFleshConfig * const fleshconfig,
+ int const convlevel,
+ cGH * const cctkGH)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (fleshconfig != 0);
+ if (verbose) CCTK_INFO ("Setup");
+ return extending_t::setup
+ (cctkGH, OutputGH, TimeToOutput, TriggerOutput, OutputVarAs);
+ }
+
+
+
+ void
+ CarpetIOF5_Init (CCTK_ARGUMENTS)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ if (verbose) CCTK_INFO ("Init");
+
+ * next_output_iteration = 0;
+ * next_output_time = cctk_time;
+ * this_iteration = -1;
+ }
+
+
+
+ int
+ OutputGH (cGH const * const cctkGH)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (cctkGH != 0);
+
+ if (verbose) CCTK_INFO ("OutputGH");
+
+ int ierr;
+
+ vector<bool> want_variables (CCTK_NumVars());
+ ierr
+ = CCTK_TraverseString (out_vars,
+ mark_variables,
+ static_cast<void *> (& want_variables),
+ CCTK_GROUP_OR_VAR);
+ switch (ierr) {
+ case -2: return Error_lonely_option_string;
+ case -3: return Error_unterminated_option_string;
+ case -4: return Error_garbage_after_option_string;
+ case -5: return Error_invalid_variable_name;
+ }
+ assert (ierr >= 0);
+
+ ierr = Error_none;
+ for (int variable = 0; variable < CCTK_NumVars(); ++ variable)
+ {
+ if (want_variables.at(variable))
+ {
+ if (TimeToOutput (cctkGH, variable))
+ {
+ ierr = TriggerOutput (cctkGH, variable);
+ }
+ }
+ }
+
+ return ierr;
+ }
+
+
+
+ void
+ mark_variables (int const variable,
+ char const * const options,
+ void * const ptr)
+ {
+ vector<bool> & want_variables = * static_cast<vector<bool> *> (ptr);
+ want_variables.at (variable) = true;
+ }
+
+
+
+ int
+ TimeToOutput (cGH const * const cctkGH,
+ int const variable)
+ {
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (cctkGH != 0);
+ assert (variable >= 0 and variable < CCTK_NumVars());
+
+ assert (Carpet::is_level_mode());
+
+ if (verbose)
+ {
+ char * const fullname = CCTK_FullName(variable);
+ CCTK_VInfo (CCTK_THORNSTRING, "TimeToOutput \"%s\"", fullname);
+ free (fullname);
+ }
+
+ bool should_output;
+
+ char const * const my_out_criterion
+ = (CCTK_EQUALS (out_criterion, "default")
+ ? IO_out_criterion
+ : out_criterion);
+
+ if (CCTK_EQUALS (my_out_criterion, "always"))
+ {
+ should_output = true;
+ }
+ else if (CCTK_EQUALS (my_out_criterion, "never"))
+ {
+ should_output = false;
+ }
+ else if (CCTK_EQUALS (my_out_criterion, "iteration"))
+ {
+ int const my_out_every = out_every == -2 ? IO_out_every : out_every;
+ switch (my_out_every)
+ {
+ case 0:
+ should_output = true;
+ break;
+ case -1:
+ should_output = false;
+ break;
+ default:
+ if (* this_iteration == cctk_iteration)
+ {
+ // we already decided to output this iteration
+ should_output = true;
+ }
+ else if (cctk_iteration >= * next_output_iteration)
+ {
+ // it is time for the next output
+ should_output = true;
+ * this_iteration = cctk_iteration;
+ * next_output_iteration = cctk_iteration + my_out_every;
+ }
+ else
+ {
+ should_output = false;
+ }
+ break;
+ }
+ }
+ else if (CCTK_EQUALS (my_out_criterion, "time"))
+ {
+ CCTK_REAL const my_out_dt = out_dt == -2 ? IO_out_dt : out_dt;
+ if (out_dt == 0)
+ {
+ should_output = true;
+ }
+ else if (out_dt == -1)
+ {
+ should_output = false;
+ }
+ else
+ {
+ if (* this_iteration == cctk_iteration)
+ {
+ // we already decided to output this iteration
+ should_output = true;
+ }
+ else if (cctk_time / cctk_delta_time
+ >= * next_output_time / cctk_delta_time - dt_fudge)
+ {
+ // it is time for the next output
+ should_output = true;
+ * this_iteration = cctk_iteration;
+ * next_output_time = cctk_time + my_out_dt;
+ }
+ else
+ {
+ should_output = false;
+ }
+ }
+ }
+ else
+ {
+ CCTK_WARN (1, "internal error");
+ should_output = false;
+ }
+
+ if (should_output)
+ {
+ extending_t extending (cctkGH);
+ int const last_output_iteration
+ = (extending.get_last_output_iteration
+ (Carpet::mglevel, Carpet::reflevel, variable));
+ assert (last_output_iteration <= cctk_iteration);
+ if (last_output_iteration == cctk_iteration)
+ {
+ // Skipping output for variable, because this variable has
+ // already been output during the current iteration --
+ // probably via a trigger during the analysis stage
+ should_output = false;
+ }
+ else
+ {
+ extending.set_last_output_iteration
+ (Carpet::mglevel, Carpet::reflevel, variable, cctk_iteration);
+ }
+ }
+
+ return should_output;
+ }
+
+
+
+ int
+ TriggerOutput (cGH const * const cctkGH,
+ int const variable)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (cctkGH != 0);
+ assert (variable >= 0 and variable < CCTK_NumVars());
+
+ char * const fullname = CCTK_FullName (variable);
+ assert (fullname);
+
+ if (verbose)
+ {
+ CCTK_VInfo (CCTK_THORNSTRING, "TriggerOutput \"%s\"", fullname);
+ }
+
+ string const alias = generate_filename (cctkGH, variable);
+
+ int const ierr = OutputVarAs (cctkGH, fullname, alias.c_str());
+
+ free (fullname);
+
+ return ierr;
+ }
+
+
+
+ int
+ OutputVarAs (cGH const * const cctkGH,
+ char const * const varname,
+ char const * const alias)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (cctkGH != 0);
+ assert (varname != 0);
+ assert (alias != 0);
+
+ if (verbose)
+ {
+ CCTK_VInfo (CCTK_THORNSTRING, "OutputVarAs \"%s\" \"%s\"",
+ varname, alias);
+ }
+
+ int const variable = CCTK_VarIndex (varname);
+ if (variable < 0)
+ {
+ return Error_illegal_varname;
+ }
+ assert (variable >= 0 and variable < CCTK_NumVars());
+
+ int const group = CCTK_GroupIndexFromVarI (variable);
+ assert (group >= 0 and group < CCTK_NumGroups());
+
+ if (CCTK_ActiveTimeLevelsGI (cctkGH, group) == 0)
+ {
+ return Error_group_has_no_storage;
+ }
+
+ extending_t extending (cctkGH);
+
+ bool const use_IO_out_dir = strcmp (out_dir, "") == 0;
+ string const path = use_IO_out_dir ? IO_out_dir : out_dir;
+ string const basename = alias;
+
+ bool const did_truncate = extending.get_did_truncate (basename);
+ bool const do_truncate
+ = not did_truncate and IO_TruncateOutputFiles (cctkGH);
+ extending.set_did_truncate (basename);
+
+ int const proc = CCTK_MyProc (cctkGH);
+ bool have_metafile; // whether there is a metadata file
+ int metadata_processor; // the processor which outputs the metadata file
+ int output_processor; // the processor which outputs our data
+ if (CCTK_EQUALS (out_mode, "proc"))
+ {
+ have_metafile = true;
+ metadata_processor = 0;
+ output_processor = proc;
+ }
+ else if (CCTK_EQUALS (out_mode, "np"))
+ {
+ have_metafile = true;
+ metadata_processor = 0;
+ output_processor = proc / out_proc_every * out_proc_every;
+ }
+ else if (CCTK_EQUALS (out_mode, "onefile"))
+ {
+ have_metafile = false;
+ metadata_processor = 0;
+ output_processor = 0;
+ }
+ else
+ {
+ assert (0);
+ }
+
+ F5::file_t * metafile = NULL;
+ if (have_metafile and proc == metadata_processor)
+ {
+ metafile
+ = new F5::file_t (cctkGH, path, basename, string (out_extension),
+ do_truncate, true, false);
+ }
+
+ F5::file_t * file = NULL;
+ if (proc == output_processor)
+ {
+ file = new F5::file_t (cctkGH, path, basename, string (out_extension),
+ do_truncate, not have_metafile, true);
+ }
+
+ if (do_truncate)
+ {
+ // Output parameters once after the output file has been created
+ if (proc == metadata_processor)
+ {
+ if (CCTK_EQUALS (out_save_parameters, "all") or
+ CCTK_EQUALS (out_save_parameters, "only set"))
+ {
+ WriteParameters (have_metafile ? * metafile : * file);
+ }
+ else if (CCTK_EQUALS (out_save_parameters, "no"))
+ {
+ // do nothing
+ }
+ else
+ {
+ assert (0);
+ }
+ }
+ }
+
+ if (metafile)
+ {
+ writer_t writer (cctkGH, variable);
+ writer.write (* metafile);
+ delete metafile;
+ metafile = NULL;
+ }
+ {
+ writer_t writer (cctkGH, variable);
+#warning "TODO: handle the case where not all processors are writing to their own file"
+ assert (proc == output_processor);
+ assert (file);
+ writer.write (* file);
+ delete file;
+ file = NULL;
+ }
+
+ return Error_none;
+ }
+
+
+
+ void
+ WriteParameters (F5::file_t & file)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ cGH const * const cctkGH = file.get_cctkGH ();
+
+ hid_t const hdf5_file = file.get_hdf5_file();
+
+ hid_t const attribute_group
+ = F5::open_or_create_group (hdf5_file,
+ "Parameters and Global Attributes");
+ assert (attribute_group >= 0);
+
+ // unique configuration identifier
+ if (CCTK_IsFunctionAliased ("UniqueConfigID")) {
+ F5::write_or_check_attribute
+ (attribute_group, "config id",
+ static_cast<char const *> (UniqueConfigID (cctkGH)));
+ }
+
+ // unique build identifier
+ if (CCTK_IsFunctionAliased ("UniqueBuildID")) {
+ F5::write_or_check_attribute
+ (attribute_group, "build id",
+ static_cast<char const *> (UniqueBuildID (cctkGH)));
+ }
+
+ // unique simulation identifier
+ if (CCTK_IsFunctionAliased ("UniqueSimulationID")) {
+ F5::write_or_check_attribute
+ (attribute_group, "simulation id",
+ static_cast<char const *> (UniqueSimulationID (cctkGH)));
+ }
+
+ // unique run identifier
+ if (CCTK_IsFunctionAliased ("UniqueRunID")) {
+ F5::write_or_check_attribute
+ (attribute_group, "run id",
+ static_cast<char const *> (UniqueRunID (cctkGH)));
+ }
+
+ // Output Cactus parameters as single string
+ {
+ char * const parameters = IOUtil_GetAllParameters (cctkGH, true);
+ assert (parameters);
+ // Create a dataset, since the data may not fit into an attribute
+ hsize_t const size = strlen (parameters) + 1;
+ hid_t const dataspace = H5Screate_simple (1, & size, NULL);
+ assert (dataspace >= 0);
+ hid_t properties = H5Pcreate (H5P_DATASET_CREATE);
+ assert (properties >= 0);
+ check (not H5Pset_chunk (properties, 1, & size));
+ if (compression_level > 0)
+ {
+ check (not H5Pset_deflate (properties, compression_level));
+ }
+ if (write_checksum)
+ {
+ check (not H5Pset_fletcher32 (properties));
+ }
+ hid_t const dataset
+ = H5Dcreate (attribute_group, "All Parameters", H5T_NATIVE_CHAR,
+ dataspace, H5P_DEFAULT,
+ properties, H5P_DEFAULT);
+ assert (dataset >= 0);
+ check (not H5Dwrite (dataset, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, parameters));
+ check (not H5Dclose (dataset));
+ check (not H5Pclose (properties));
+ check (not H5Sclose (dataspace));
+ free (parameters);
+ }
+
+ check (not H5Gclose (attribute_group));
+
+ // This is far too slow to be useful
+#if 0
+ hid_t const parameter_group
+ = F5::open_or_create_group (hdf5_file, "Cactus parameters");
+ assert (parameter_group >= 0);
+
+ int first = 1;
+ for (;;)
+ {
+ cParamData const * parameter_data;
+ char * parameter_fullname;
+
+ int const ierr
+ = CCTK_ParameterWalk (first, 0,
+ & parameter_fullname, & parameter_data);
+ if (ierr > 0) break;
+ assert (ierr >= 0);
+
+ int type;
+ void const * const parameter_value
+ = CCTK_ParameterGet (parameter_data->name, parameter_data->thorn,
+ & type);
+ assert (type == parameter_data->type);
+ assert (parameter_value != 0);
+
+ switch (type)
+ {
+ case PARAMETER_BOOLEAN:
+ case PARAMETER_INT:
+ {
+ CCTK_INT const value
+ = * static_cast<CCTK_INT const *> (parameter_value);
+ F5::write_or_check_attribute
+ (parameter_group, parameter_fullname, value);
+ }
+ break;
+ case PARAMETER_REAL:
+ {
+ CCTK_REAL const value
+ = * static_cast<CCTK_REAL const *> (parameter_value);
+ F5::write_or_check_attribute
+ (parameter_group, parameter_fullname, value);
+ }
+ break;
+ case PARAMETER_KEYWORD:
+ case PARAMETER_STRING:
+ {
+ char const * const value
+ = * static_cast<char const * const *> (parameter_value);
+ F5::write_or_check_attribute
+ (parameter_group, parameter_fullname, value);
+ }
+ break;
+ default:
+ assert (0);
+ }
+
+ free (parameter_fullname);
+
+ first = 0;
+ }
+
+ check (not H5Gclose (parameter_group));
+#endif
+ }
+
+
+
+ string
+ generate_filename (cGH const * const cctkGH,
+ int const variable)
+ {
+ DECLARE_CCTK_PARAMETERS;
+
+ assert (variable >= 0);
+
+ ostringstream filename_buf;
+
+ if (CCTK_EQUALS (file_content, "variable"))
+ {
+ char * const varname = CCTK_FullName (variable);
+ assert (varname);
+ for (char * p = varname; * p; ++ p)
+ {
+ *p = tolower (* p);
+ }
+ filename_buf << varname;
+ free (varname);
+ }
+ else if (CCTK_EQUALS (file_content, "group"))
+ {
+ char * const groupname = CCTK_GroupNameFromVarI (variable);
+ assert (groupname);
+ for (char * p = groupname; * p; ++ p)
+ {
+ *p = tolower (* p);
+ }
+ filename_buf << groupname;
+ free (groupname);
+ }
+ else if (CCTK_EQUALS (file_content, "thorn"))
+ {
+ char const * const impname = CCTK_ImpFromVarI (variable);
+ char * const thornname = strdup (impname);
+ assert (thornname);
+ char * const colon = strchr (thornname, ':');
+ assert (colon);
+ * colon = '\0';
+ for (char * p = thornname; * p; ++ p)
+ {
+ *p = tolower (* p);
+ }
+ filename_buf << thornname;
+ free (thornname);
+ }
+ else if (CCTK_EQUALS (file_content, "everything"))
+ {
+ filename_buf << out_filename;
+ }
+ else
+ {
+ assert (0);
+ }
+
+ if (out_timesteps_per_file > 0)
+ {
+ int const iteration = (cctkGH->cctk_iteration
+ / out_timesteps_per_file * out_timesteps_per_file);
+ filename_buf << ".it"
+ << setw (iteration_digits) << setfill ('0') << iteration;
+ }
+
+ return filename_buf.str();
+ }
+
+} // namespace CarpetIOF5