#include #include #include #include #include #include #include #include #include #include #include #include "cctk.h" #include "cctk_Parameters.h" #include "AMRwriter.hh" #include "AmrGridReader.hh" #ifdef HDF4 # include "HDFIO.hh" #endif #ifdef HDF5 # include "H5IO.hh" #endif #include "IEEEIO.hh" #include "IO.hh" // Hack to stop FlexIO data type clash with LAM MPI #undef BYTE #undef CHAR #include "CactusBase/IOUtil/src/ioGH.h" #include "bbox.hh" #include "data.hh" #include "gdata.hh" #include "ggf.hh" #include "vect.hh" #include "carpet.hh" #include "ioflexio.hh" extern "C" { static const char* rcsid = "$Header:$"; CCTK_FILEVERSION(Carpet_CarpetIOFlexIO_ioflexio_cc); } namespace CarpetIOFlexIO { using namespace std; using namespace Carpet; using namespace CarpetIOFlexIOUtil; using namespace CarpetCheckpointRestart; // Variable definitions // int GHExtension; int IOMethod; vector do_truncate; vector > last_output; static const char* GetStringParameter (const char* const parametername, const char* const fallback); static int GetIntParameter (const char* const parametername, int fallback); static bool CheckForVariable (const cGH* const cgh, const char* const varlist, const int vindex); static void SetFlag (int index, const char* optstring, void* arg); int CarpetIOFlexIO_Startup () { CCTK_RegisterBanner ("AMR 3D FlexIO I/O provided by CarpetIOFlexIO"); // GHExtension = CCTK_RegisterGHExtension("CarpetIOFlexIO"); CCTK_RegisterGHExtensionSetupGH (CCTK_RegisterGHExtension("CarpetIOFlexIO"),SetupGH); IOMethod = CCTK_RegisterIOMethod ("CarpetIOFlexIO"); CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH); CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs); CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput); CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput); /* register the CarpetIOFlexIO recovery routine to thorn IOUtil */ if (IOUtil_RegisterRecover ("CarpetIOFlexIO recovery", CarpetIOFlexIO_Recover) < 0) { CCTK_WARN (1, "Failed to register IOFlexIO recovery routine"); } return 0; } void* SetupGH (tFleshConfig* const fc, const int convLevel, cGH* const cgh) { DECLARE_CCTK_PARAMETERS; CarpetIOFlexIOGH* myGH; CCTK_INT i; // Truncate all files if this is not a restart do_truncate.resize(CCTK_NumVars(), true); // No iterations have yet been output last_output.resize(maxreflevels); for (int rl=0; rlout_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 (i = 0; i < numvars; i++) { myGH->out_last [i] = -1; } myGH->open_output_files = NULL; return (myGH); return 0; } int OutputGH (const cGH* const cgh) { for (int vindex=0; vindexvindex; const int group = CCTK_GroupIndexFromVarI (varindex); const int n0 = CCTK_FirstVarIndexI(group); assert (n0>=0 && n0=0 && vartimelevel==0) tl = 0; else tl = - request->timelevel; assert (! ( (grouptype != CCTK_GF) && reflevel>0)); if (CCTK_MyProc(cgh)==0) { amrwriter->setType (FlexIODataType(CCTK_VarTypeI(varindex))); int gpdim = CCTK_GroupDimI(group); // need gpdim=1 if scalar (flexio wants this) if(gpdim == 0) if(grouptype == CCTK_SCALAR) gpdim = 1; else CCTK_WARN(0,"Non-scalar variable with dimension 0!!!"); // Set coordinate information CCTK_REAL lower[dim], upper[dim]; double origin[dim], delta[dim], timestep; for (int d=0; dcctk_delta_space[d]; } timestep = cgh->cctk_delta_time; amrwriter->setTopLevelParameters (gpdim, origin, delta, timestep, maxreflevels); // Set refinement information int interlevel_timerefinement; int interlevel_spacerefinement[dim]; int initial_gridplacementrefinement[dim]; interlevel_timerefinement = hh->reffact; for (int d=0; dreffact; initial_gridplacementrefinement[d] = 1; } amrwriter->setRefinement (interlevel_timerefinement, interlevel_spacerefinement, initial_gridplacementrefinement); // Set level amrwriter->setLevel (reflevel); // Set current time amrwriter->setTime (cgh->cctk_iteration); } // Traverse all components on this refinement and multigrid level BEGIN_COMPONENT_LOOP(cgh, grouptype) { const ggf* ff = 0; assert (var < (int)arrdata[group].data.size()); ff = (ggf*)arrdata[group].data[var]; const gdata* const data = (*ff) (tl, reflevel, component, mglevel); // get some more group information cGroupDynamicData gdyndata; int ierr = CCTK_GroupDynamicData(cgh,group,&gdyndata); assert(ierr==0); cGroup cgdata; ierr = CCTK_GroupData(group,&cgdata); assert(ierr==0); /* handle CCTK_DISTRIB_CONSTANT scalar and arrays */ #if 0 if (cgdata.disttype == CCTK_DISTRIB_CONSTANT) { assert(grouptype == CCTK_ARRAY || grouptype == CCTK_SCALAR); if (hh->processors[reflevel][component] == 0) { if (grouptype == CCTK_SCALAR) { CCTK_VInfo (CCTK_THORNSTRING, "dumping SCALAR distrib const"); int rank=1; int dim[1]={1}; writer -> write(FlexIODataType(CCTK_VarTypeI(varindex)),rank,dim,CCTK_VarDataPtrI(cgh,tl,varindex)); DumpCommonAttributes(cgh,writer,request); continue; } else { writer -> write(FlexIODataType(CCTK_VarTypeI(varindex)),cgdata.dim,gdyndata.lsh,CCTK_VarDataPtrI(cgh,tl,varindex)); DumpCommonAttributes(cgh,writer,request); continue; } } else { continue; } } #endif // Make temporary copy on processor 0 bbox ext = data->extent(); vect lo = ext.lower(); vect hi = ext.upper(); vect str = ext.stride(); // Ignore ghost zones if desired const int out3D_output_outer_boundary_var = (called_from_checkpoint) ? -1 : out3D_output_outer_boundary; const int out3D_max_num_lower_ghosts_var = (called_from_checkpoint) ? -1 : out3D_max_num_lower_ghosts; const int out3D_max_num_upper_ghosts_var = (called_from_checkpoint) ? -1 : out3D_max_num_upper_ghosts; for (int d=0; d(lo,hi,str); gdata* const tmp = data->make_typed (varindex); tmp->allocate (ext, 0); //fprintf(stderr,"\n writing1 %d\n",CCTK_MyProc(cgh)); if ( !((cgdata.disttype == CCTK_DISTRIB_CONSTANT) && (hh->processors[reflevel][component]!=0))) { if (cgdata.disttype == CCTK_DISTRIB_CONSTANT) { assert(grouptype == CCTK_ARRAY || grouptype == CCTK_SCALAR); //fprintf(stderr,"\n scalar %d %d comp: %d\n",CCTK_MyProc(cgh),varindex,component); int origin[dim], dims[dim]; for (int d=0; dwrite (origin, dims, (void*)data->storage()); DumpCommonAttributes(cgh,writer,request); } delete tmp; continue; } else { for (comm_state state; !state.done(); state.step()) { tmp->copy_from (state, data, ext); } //fprintf(stderr,"\n writing2 %d component: %d varindex: %d distrib_const: %d\n",CCTK_MyProc(cgh),component,varindex,(cgdata.disttype == CCTK_DISTRIB_CONSTANT)); // Write data if (CCTK_MyProc(cgh)==0) { int origin[dim], dims[dim]; for (int d=0; dwrite (origin, dims, (void*)tmp->storage()); // dump attributes DumpCommonAttributes(cgh,writer,request); } // Delete temporary copy delete tmp; } } } END_COMPONENT_LOOP; return 0; } int OutputVarAs (const cGH* const cgh, const char* const varname, const char* const alias) { DECLARE_CCTK_PARAMETERS; const int n = CCTK_VarIndex(varname); assert (n>=0 && n=0 && group<(int)Carpet::arrdata.size()); const int n0 = CCTK_FirstVarIndexI(group); assert (n0>=0 && n0=0 && var0) return 0; int first_vindex = CCTK_FirstVarIndexI (group); /* get the default I/O request for this group */ ioRequest* request = IOUtil_DefaultIORequest (cgh, first_vindex, 1); // Get grid hierarchy extentsion from IOUtil const ioGH * const iogh = (const ioGH *)CCTK_GHExtension (cgh, "IO"); assert (iogh); // Create the output directory const char* myoutdir = GetStringParameter("out3D_dir", out_dir); if (CCTK_MyProc(cgh)==0) { CCTK_CreateDirectory (0755, myoutdir); } // Invent a file name const char* extension = 0; if (CCTK_Equals(out3D_format, "IEEE")) { extension = ".raw"; #ifdef HDF4 } else if (CCTK_Equals(out3D_format, "HDF4")) { extension = ".hdf"; #endif #ifdef HDF5 } else if (CCTK_Equals(out3D_format, "HDF5")) { extension = ".h5"; #endif } else { assert (0); } extension = GetStringParameter ("out3D_extension", extension); ostringstream filenamebuf; filenamebuf << myoutdir << "/" << alias << extension; string filenamestr = filenamebuf.str(); const char * const filename = filenamestr.c_str(); IObase* writer = 0; AMRwriter* amrwriter = 0; // Write the file only on the root processor if (CCTK_MyProc(cgh)==0) { // If this is the first time, then create and truncate the file if (do_truncate[n]) { struct stat fileinfo; if (! iogh->recovered || stat(filename, &fileinfo)!=0) { writer = 0; if (CCTK_Equals(out3D_format, "IEEE")) { writer = new IEEEIO(filename, IObase::Create); #ifdef HDF4 } else if (CCTK_Equals(out3D_format, "HDF4")) { writer = new HDFIO(filename, IObase::Create); #endif #ifdef HDF5 } else if (CCTK_Equals(out3D_format, "HDF5")) { writer = new H5IO(filename, IObase::Create); #endif } else { assert (0); } delete writer; writer = 0; } } // Open the file if (CCTK_Equals(out3D_format, "IEEE")) { writer = new IEEEIO(filename, IObase::Append); #ifdef HDF4 } else if (CCTK_Equals(out3D_format, "HDF4")) { writer = new HDFIO(filename, IObase::Append); #endif #ifdef HDF5 } else if (CCTK_Equals(out3D_format, "HDF5")) { writer = new H5IO(filename, IObase::Append); #endif } else { assert (0); } assert (writer->isValid()); amrwriter = new AMRwriter(*writer); } WriteGF(cgh,writer,amrwriter,request,0); // Close the file if (CCTK_MyProc(cgh)==0) { delete amrwriter; amrwriter = 0; delete writer; writer = 0; } // Don't truncate again do_truncate[n] = false; return 0; } int TimeToOutput (const cGH* const cgh, const int vindex) { DECLARE_CCTK_PARAMETERS; assert (vindex>=0 && vindex<(int)last_output[reflevel].size()); const int myoutevery = GetIntParameter("out3D_every", out_every); if (myoutevery < 0) { // Nothing should be output at all return 0; } if (cgh->cctk_iteration % myoutevery != 0) { // Nothing should be output during this iteration return 0; } if (! CheckForVariable(cgh, GetStringParameter("out3D_vars",""), vindex)) { // This variable should not be output return 0; } if (last_output[reflevel][vindex] == cgh->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[reflevel][vindex] < cgh->cctk_iteration); // Should be output during this iteration return 1; } int TriggerOutput (const cGH* const cgh, const int vindex) { assert (vindex>=0 && vindexcctk_iteration; return retval; } int ReadGF (const cGH* const cgh, IObase* reader, AmrGridReader* amrreader,int currdataset) { /* this functions reads in a variable on the current reflevel from an already open file. At some point it should be called from InputVarAs */ DECLARE_CCTK_PARAMETERS; int tl = -1; int mglevel = -1; int rl = -1; int comp = -1; int myproc = CCTK_MyProc (cgh); int rank; int dims[dim]; int nbytes; char* varname; char warnstring[256]; int asize,i; IObase::DataType datatype; int group,varindex; CCTK_REAL cctk_time; if(myproc==0) { // read the name of the variable i = reader->readAttributeInfo ("name", datatype, asize); if (i >= 0 && datatype == FLEXIO_CHAR && asize > 0) { varname = (char*) malloc(sizeof(char)*asize+1); reader->readAttribute (i, varname); } else { CCTK_WARN (0, "Something is wrong! Can't read dataset names!!!"); } varindex = CCTK_VarIndex(varname); assert(varindex > -1); group = CCTK_GroupIndexFromVarI(varindex); assert(group > -1); // Check for storage if (! CCTK_QueryGroupStorageI(cgh, group)) { CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING, "Cannot recover variable \"%s\" because it has no storage", varname); return 0; } // read reflevel i = reader->readAttributeInfo ("reflevel", datatype, asize); if (i >= 0 && datatype == FLEXIO_INT && asize > 0) { reader->readAttribute (i, &rl); } else { CCTK_WARN (0, "Something is wrong! Can't read refinement level!!!"); } i = reader->readAttributeInfo ("component", datatype, asize); if (i >= 0 && datatype == FLEXIO_INT && asize > 0) { reader->readAttribute (i, &comp); } else { CCTK_WARN (0, "Something is wrong! Can't read component!!!"); } i = reader->readAttributeInfo ("timelevel", datatype, asize); if (i >= 0 && datatype == FLEXIO_INT && asize > 0) { reader->readAttribute (i, &tl); } else { CCTK_WARN (0, "Something is wrong! Can't read timelevel!!!"); } i = reader->readAttributeInfo ("mglevel", datatype, asize); if (i >= 0 && datatype == FLEXIO_INT && asize > 0) { reader->readAttribute (i, &mglevel); } else { CCTK_WARN (0, "Something is wrong! Can't read multi group level!!!"); } i = reader->readAttributeInfo ("cctk_time", datatype, asize); if (i >= 0 && datatype == FLEXIO_REAL && asize > 0) { reader->readAttribute (i, &cctk_time); } else { CCTK_WARN (0, "Something is wrong! Can't read coordinate time!!!"); } // Read information about dataset if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Reading dataset info"); reader->readInfo (datatype, rank, dims); nbytes = IObase::nBytes(datatype,rank,dims); if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "type=%d rank=%d dims=[%d,%d,%d] nbytes=%d", (int)datatype, rank, dims[0], dims[1], dims[2], nbytes); int gpdim = CCTK_GroupDimI(group); const int grouptype = CCTK_GroupTypeI(group); // need gpdim=1 if scalar (flexio wants this) if(gpdim == 0) if(grouptype == CCTK_SCALAR) gpdim = 1; else CCTK_WARN(0,"Non-scalar variable with dimension 0!!!"); CCTK_VInfo(CCTK_THORNSTRING,"Recovering varindex: %d grouptype: %d varname: %s tl: %d, rl: %d, c: %d",varindex,grouptype,varname,tl,rl,comp); free(varname); // Check rank assert (rank==gpdim); } // Broadcast varindex,group,rank, dimensions, and nbytes,rl,tl,mglevel MPI_Bcast (&varindex, 1, MPI_INT, 0, dist::comm); assert (varindex>=0); MPI_Bcast (&group, 1, MPI_INT, 0, dist::comm); assert (group>=0); MPI_Bcast (&rank, 1, MPI_INT, 0, dist::comm); assert (rank>=1); MPI_Bcast (&dims, rank, MPI_INT, 0, dist::comm); for (int d=0; d=0); MPI_Bcast (&nbytes, 1, MPI_INT, 0, dist::comm); assert (nbytes>=0); MPI_Bcast (&rl, 1, MPI_INT, 0, dist::comm); MPI_Bcast (&tl, 1, MPI_INT, 0, dist::comm); MPI_Bcast (&mglevel, 1, MPI_INT, 0, dist::comm); MPI_Bcast (&comp, 1, MPI_INT, 0, dist::comm); int gpdim = CCTK_GroupDimI(group); const int grouptype = CCTK_GroupTypeI(group); cGroup cgdata; int ierr = CCTK_GroupData(group,&cgdata); assert(ierr==0); // Read grid AmrGrid* amrgrid = 0; int amr_origin[dim]; int amr_dims[dim]; if (myproc==0) { // Read data if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Reading AMR data"); amrgrid = amrreader->getGrid(currdataset); assert (amrgrid!=0); assert (amrgrid->data!=0); IObase::DataType atype; int alength; // If iorigin attribute is absent, assume file has unigrid // data. Initialize iorigin to 0. if (reader->readAttributeInfo("iorigin", atype, alength) < 0) { for (int d=0; diorigin[d] = 0; } } for (int d=0; diorigin[d]; // fprintf(stderr,"\n amr_origin[%d]=%d",d,amr_origin[d]); amr_dims[d] = amrgrid->dims[d]; //fprintf(stderr,"\n amr_dims[%d]=%d",d,amr_dims[d]); } for (int d=gpdim; d=0 && n0=0 && varcomponents(rl) << endl; //cout << "myproc: " << CCTK_MyProc(cgh) << endl; // fprintf(stderr,"%d amr_dims: %d,%d,%d\n",CCTK_MyProc(cgh),amr_dims[0],amr_dims[1],amr_dims[2]); //fprintf(stderr,"%d amr_origin: %d,%d,%d\n",CCTK_MyProc(cgh),amr_origin[0],amr_origin[1],amr_origin[2]); for(int c=0;ccomponents(rl);c++) { ggf* ff = 0; assert (var < (int)arrdata[group].data.size()); ff = (ggf*)arrdata[group].data[var]; gdata* const data = (*ff) (tl, rl, c, mglevel); // Create temporary data storage on processor 0 const int reflevelfact_local=ipow(reffact,rl); vect str = vect(maxreflevelfact/reflevelfact_local); if(grouptype == CCTK_SCALAR || grouptype == CCTK_ARRAY) str = vect (1); vect lb = vect(amr_origin) * str; vect ub = lb + (vect(amr_dims) - 1) * str; gdata* const tmp = data->make_typed (varindex); // Copy into grid function if (cgdata.disttype == CCTK_DISTRIB_CONSTANT) { assert(grouptype == CCTK_ARRAY || grouptype == CCTK_SCALAR); if (grouptype == CCTK_SCALAR) { lb[0] = hh->processors.at(rl).at(c); ub[0] = hh->processors.at(rl).at(c); } else { lb[dim-1] = lb[dim-1] + (ub[dim-1]-lb[dim-1]+1)*hh->processors.at(rl).at(c); ub[dim-1] = ub[dim-1] + (ub[dim-1]-lb[dim-1]+1)*hh->processors.at(rl).at(c); } } const bbox ext(lb,ub,str); if (myproc==0) { tmp->allocate (ext, 0, amrgrid->data); } else { tmp->allocate (ext, 0, 0); } for (comm_state state; !state.done(); state.step()) { data->copy_from (state, tmp, ext & data->extent() ); } // Delete temporary copy delete tmp; } // manual component loop if (myproc==0) { free (amrgrid->data); free (amrgrid); amrgrid = 0; } return 0; } int InputGH (const cGH* const cgh) { int retval = 0; for (int vindex=0; vindex=0 && n=0 && group<(int)Carpet::arrdata.size()); const int n0 = CCTK_FirstVarIndexI(group); assert (n0>=0 && n0=0 && varisValid()) { CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING, "Could not open file \"%s\" for reading", filename); } assert (reader->isValid()); if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Reading AMR info"); amrreader = new AmrGridReader(*reader); // Read information about dataset if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Reading dataset info"); IObase::DataType numbertype; reader->readInfo (numbertype, rank, dims); nbytes = IObase::nBytes(numbertype,rank,dims); if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "type=%d rank=%d dims=[%d,%d,%d] nbytes=%d", (int)numbertype, rank, dims[0], dims[1], dims[2], nbytes); // Check rank assert (rank==gpdim); // Check datatype // TODO: Check datatype correctly assert (CCTK_VarTypeI(n) == CCTK_VARIABLE_REAL8 || (sizeof(CCTK_REAL) == sizeof(CCTK_REAL8) && CCTK_VarTypeI(n) == CCTK_VARIABLE_REAL)); // TODO: check grid spacing // Number of datasets if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Reading number of datasets"); ndatasets = reader->nDatasets(); if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "ndatasets=%d", ndatasets); assert (ndatasets>=0); } // Broadcast rank, dimensions, and nbytes MPI_Bcast (&rank, 1, MPI_INT, 0, dist::comm); assert (rank>=1); MPI_Bcast (&dims, rank, MPI_INT, 0, dist::comm); for (int d=0; d=0); MPI_Bcast (&nbytes, 1, MPI_INT, 0, dist::comm); assert (nbytes>=0); // Broadcast number of datasets MPI_Bcast (&ndatasets, 1, MPI_INT, 0, dist::comm); assert (ndatasets>=0); // Read all datasets // TODO: read only some datasets for (int dataset=0; datasetgetGrid(dataset); assert (amrgrid!=0); assert (amrgrid->data!=0); // If iorigin attribute is absent, assume file has unigrid // data. Initialize iorigin to 0. IObase::DataType atype; int alength; if (reader->readAttributeInfo("iorigin", atype, alength) < 0) { for (int d=0; diorigin[d] = 0; } } for (int d=0; diorigin[d]; amr_dims[d] = amrgrid->dims[d]; } for (int d=gpdim; d* ff = 0; assert (var < (int)arrdata[group].data.size()); ff = (ggf*)arrdata[group].data[var]; gdata* const data = (*ff) (tl, rl, component, mglevel); // Create temporary data storage on processor 0 const vect str = vect(reflevelfact); const vect lb = vect(amr_origin) * str; const vect ub = lb + (vect(amr_dims) - 1) * str; const bbox ext(lb,ub,str); gdata* const tmp = data->make_typed (n); if (CCTK_MyProc(cgh)==0) { tmp->allocate (ext, 0, amrgrid->data); } else { tmp->allocate (ext, 0, 0); } // Copy into grid function for (comm_state state; !state.done(); state.step()) { data->copy_from (state, tmp, ext); } // Delete temporary copy delete tmp; } END_COMPONENT_LOOP; if (CCTK_MyProc(cgh)==0) { free (amrgrid->data); free (amrgrid); amrgrid = 0; } } // loop over datasets // Close the file if (CCTK_MyProc(cgh)==0) { if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Deleting AMR info"); delete amrreader; amrreader = 0; if (verbose) CCTK_VInfo (CCTK_THORNSTRING, "Closing file"); delete reader; reader = 0; } return 0; } int CarpetIOFlexIO_ReadData (CCTK_ARGUMENTS) { DECLARE_CCTK_ARGUMENTS; return InputGH(cctkGH); } const char* GetStringParameter (const char* const parametername, const char* const fallback) { if (CCTK_ParameterQueryTimesSet (parametername, CCTK_THORNSTRING) > 0) { int ptype; const char* const* const ppval = (const char* const*)CCTK_ParameterGet (parametername, CCTK_THORNSTRING, &ptype); assert (ppval); const char* const pval = *ppval; assert (ptype == PARAMETER_STRING); return pval; } return fallback; } int GetIntParameter (const char* const parametername, int fallback) { if (CCTK_ParameterQueryTimesSet (parametername, CCTK_THORNSTRING) > 0) { int ptype; const int* const ppval = (const int*)CCTK_ParameterGet (parametername, CCTK_THORNSTRING, &ptype); assert (ppval); const int pval = *ppval; assert (ptype == PARAMETER_INT); return pval; } return fallback; } bool CheckForVariable (const cGH* const cgh, const char* const varlist, const int vindex) { const int numvars = CCTK_NumVars(); assert (vindex>=0 && vindex flags(numvars); CCTK_TraverseString (varlist, SetFlag, &flags, CCTK_GROUP_OR_VAR); return flags[vindex]; } void SetFlag (int index, const char* optstring, void* arg) { vector& flags = *(vector*)arg; flags[index] = true; } } // namespace CarpetIOFlexIO