#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cctk.h" #include "cctk_Parameters.h" #include "CactusBase/IOUtil/src/ioGH.h" #include "data.hh" #include "dist.hh" #include "gdata.hh" #include "gf.hh" #include "ggf.hh" #include "vect.hh" #include "carpet.hh" #include "ioascii.hh" extern "C" { static const char* rcsid = "$Header:$"; CCTK_FILEVERSION(Carpet_CarpetIOASCII_ioascii_cc); } // That's a hack namespace Carpet { void UnsupportedVarType (const int vindex); } namespace CarpetIOASCII { using namespace std; using namespace Carpet; void SetFlag (int index, const char* optstring, void* arg); // Special output routines for complex numbers #ifdef CCTK_REAL4 ostream& operator<< (ostream& os, const CCTK_COMPLEX8& val) { return os << CCTK_Cmplx8Real(val) << " " << CCTK_Cmplx8Imag(val); } #endif #ifdef CCTK_REAL8 ostream& operator<< (ostream& os, const CCTK_COMPLEX16& val) { return os << CCTK_Cmplx16Real(val) << " " << CCTK_Cmplx16Imag(val); } #endif #ifdef CCTK_REAL16 ostream& operator<< (ostream& os, const CCTK_COMPLEX32& val) { return os << CCTK_Cmplx32Real(val) << " " << CCTK_Cmplx32Imag(val); } #endif template void WriteASCII (ostream& os, const gdata* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper); int CarpetIOASCIIStartup() { IOASCII<0>::Startup(); IOASCII<1>::Startup(); IOASCII<2>::Startup(); IOASCII<3>::Startup(); return 0; } void CarpetIOASCIIInit (CCTK_ARGUMENTS) { DECLARE_CCTK_ARGUMENTS; for (int d=0; d<4; ++d) { this_iteration[d] = 0; last_output_iteration[d] = 0; last_output_time[d] = cctk_time; } } // Definition of static members template int IOASCII::GHExtension; template int IOASCII::IOMethod; template vector IOASCII::do_truncate; template vector > > IOASCII::last_output; template int IOASCII::Startup() { ostringstream msg; msg << "AMR " << outdim << "D ASCII I/O provided by CarpetIOASCII"; CCTK_RegisterBanner (msg.str().c_str()); ostringstream extension_name; extension_name << "CarpetIOASCII_" << outdim << "D"; GHExtension = CCTK_RegisterGHExtension(extension_name.str().c_str()); CCTK_RegisterGHExtensionSetupGH (GHExtension, SetupGH); ostringstream method_name; method_name << "IOASCII_" << outdim << "D"; IOMethod = CCTK_RegisterIOMethod (method_name.str().c_str()); CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH); CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs); CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput); CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput); return 0; } template void* IOASCII ::SetupGH (tFleshConfig* const fc, const int convLevel, cGH* const cgh) { DECLARE_CCTK_PARAMETERS; const void *dummy; dummy = &fc; dummy = &convLevel; dummy = &cgh; dummy = &dummy; // Truncate all files if this is not a restart do_truncate.resize(CCTK_NumVars(), true); // No iterations have yet been output last_output.resize(mglevels); for (int ml=0; ml int IOASCII ::OutputGH (const cGH* const cgh) { for (int vindex=0; vindex int IOASCII ::OutputVarAs (const cGH* const cgh, const char* const varname, const char* const alias) { DECLARE_CCTK_PARAMETERS; assert (is_level_mode()); const int n = CCTK_VarIndex(varname); if (n<0) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Variable \"%s\" does not exist", varname); return -1; } assert (n>=0 && n=0 && group<(int)Carpet::arrdata.size()); const int n0 = CCTK_FirstVarIndexI(group); assert (n0>=0 && n0=0 && var=1); // Check for storage if (! CCTK_QueryGroupStorageI(cgh, group)) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Cannot output variable \"%s\" because it has no storage", varname); return 0; } const int grouptype = CCTK_GroupTypeI(group); switch (grouptype) { case CCTK_SCALAR: case CCTK_ARRAY: assert (do_global_mode); break; case CCTK_GF: /* do nothing */ break; default: assert (0); } const int rl = grouptype == CCTK_GF ? reflevel : 0; const int groupdim = CCTK_GroupDimI(group); if (outdim > groupdim) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Cannot produce %dD ASCII output file \"%s\" for variable \"%s\" because it has only %d dimensions", outdim, alias, varname, groupdim); return -1; } assert (outdim <= groupdim); // 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("out%dD_dir"); if (CCTK_EQUALS(myoutdir, "")) { myoutdir = out_dir; } if (CCTK_MyProc(cgh)==0) { CCTK_CreateDirectory (0755, myoutdir); } // Loop over all direction combinations vect dirs (0); bool done; do { // Output each combination only once bool ascending = true; for (int d1=0; d1 1) { filenamebuf << Carpet::map << "."; } for (int d=0; d 1) { filenamebuf << Carpet::map << "."; } for (int d=0; d=0 && dirs[d]<3); const char* const coords = "xyz"; filenamebuf << coords[dirs[d]]; } const char* const suffixes = "plpv"; filenamebuf << suffixes[outdim]; } // we need a persistent temporary here string filenamestr = filenamebuf.str(); const char* const filename = filenamestr.c_str(); // If this is the first time, then write a nice header if (do_truncate.at(n)) { struct stat fileinfo; if (IO_TruncateOutputFiles (cgh) || stat(filename, &fileinfo)!=0) { file.open (filename, ios::out | ios::trunc); if (! file.good()) { CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING, "Could not open output file \"%s\" for variable \"%s\"", filename, varname); } assert (file.good()); file << "# " << varname; for (int d=0; d* ff = 0; assert (var < (int)arrdata.at(group).at(Carpet::map).data.size()); ff = (ggf*)arrdata.at(group).at(Carpet::map).data.at(var); const int mintl = output_all_timelevels ? 1-num_tl : 0; const int maxtl = 0; for (int tl=mintl; tl<=maxtl; ++tl) { const gdata* const data = (*ff) (tl, rl, component, mglevel); ibbox ext = data->extent(); ivect lo = ext.lower(); ivect hi = ext.upper(); ivect str = ext.stride(); // Ignore ghost zones if desired for (int d=0; dcctk_bbox[2*d] ? out3D_outer_ghosts : out3D_ghosts; bool output_upper_ghosts = cgh->cctk_bbox[2*d+1] ? out3D_outer_ghosts : out3D_ghosts; if (! output_lower_ghosts) { lo[d] += cgh->cctk_nghostzones[d] * str[d]; } if (! output_upper_ghosts) { hi[d] -= cgh->cctk_nghostzones[d] * str[d]; } } ext = ibbox(lo,hi,str); // coordinates const CCTK_REAL coord_time = cgh->cctk_time; rvect global_lower; rvect coord_delta; if (grouptype == CCTK_GF) { for (int d=0; dcctk_origin_space[d]; coord_delta[d] = cgh->cctk_delta_space[d] / maxreflevelfact; } } else { for (int d=0; dbases.at(0).at(mglevel).exterior; offset1 = baseext.lower() + offset * ext.stride(); } else { offset1 = offset * ext.stride(); } for (int d=0; dcctk_iteration, offset1, dirs, rl, mglevel, Carpet::map, component, tl, coord_time, coord_lower, coord_upper); // Append EOL after every component if (CCTK_MyProc(cgh)==0) { if (separate_components) { assert (file.good()); file << endl; } } assert (file.good()); } // for tl } END_COMPONENT_LOOP; // Append EOL after every complete set of components if (CCTK_MyProc(cgh)==0) { if (separate_grids) { assert (file.good()); file << endl; } file.close(); assert (file.good()); } assert (! file.is_open()); } END_MAP_LOOP; } // if (desired) } // if (ascending) // Next direction combination done = true; for (int d=0; d int IOASCII ::TimeToOutput (const cGH* const cctkGH, const int vindex) { DECLARE_CCTK_ARGUMENTS; DECLARE_CCTK_PARAMETERS; assert (vindex>=0 && vindex= last_output_iteration[outdim] + myoutevery) { // it is time for the next output output_this_iteration = true; last_output_iteration[outdim] = cctk_iteration; this_iteration[outdim] = cctk_iteration; } else { // we want no output at this iteration output_this_iteration = false; } } else if (CCTK_EQUALS (myoutcriterion, "divisor")) { int myoutevery = GetIntParameter("out%dD_every"); if (myoutevery == -2) { myoutevery = out_every; } if (myoutevery <= 0) { // output is disabled output_this_iteration = false; } else if (cctk_iteration % myoutevery == 0) { // we already decided to output this iteration output_this_iteration = true; } else { // we want no output at this iteration output_this_iteration = false; } } else if (CCTK_EQUALS (myoutcriterion, "time")) { CCTK_REAL myoutdt = GetRealParameter("out%dD_dt"); if (myoutdt == -2) { myoutdt = out_dt; } if (myoutdt < 0) { // output is disabled output_this_iteration = false; } else if (myoutdt == 0) { // output all iterations output_this_iteration = true; } else if (cctk_iteration == this_iteration[outdim]) { // we already decided to output this iteration output_this_iteration = true; } else if (cctk_time / cctk_delta_time >= (last_output_time[outdim] + myoutdt) / cctk_delta_time - 1.0e-12) { // it is time for the next output output_this_iteration = true; last_output_time[outdim] = cctk_time; this_iteration[outdim] = cctk_iteration; } else { // we want no output at this iteration output_this_iteration = false; } } else { assert (0); } // select output criterion if (! output_this_iteration) return 0; // check which variables to output static vector output_variables; static int output_variables_iteration = -1; if (cctk_iteration > output_variables_iteration) { output_variables.resize (CCTK_NumVars()); const char* const varlist = GetStringParameter("out%dD_vars"); if (CCTK_TraverseString (varlist, SetFlag, &output_variables, CCTK_GROUP_OR_VAR) < 0) { int abort_on_error = output_variables_iteration < 0 && strict_io_parameter_check; CCTK_VWarn (abort_on_error ? 0 : 1, __LINE__, __FILE__,CCTK_THORNSTRING, "error while parsing parameter 'IOASCII::out%dD_vars'", outdim); } output_variables_iteration = cctk_iteration; } if (! output_variables.at(vindex)) return 0; if (last_output.at(mglevel).at(reflevel).at(vindex) == cctk_iteration) { // Has already been output during this iteration char* varname = CCTK_FullName(vindex); CCTK_VWarn (5, __LINE__, __FILE__, CCTK_THORNSTRING, "Skipping output for variable \"%s\", because this variable " "has already been output during the current iteration -- " "probably via a trigger during the analysis stage", varname); free (varname); return 0; } assert (last_output.at(mglevel).at(reflevel).at(vindex) < cctk_iteration); // Should be output during this iteration return 1; } template int IOASCII ::TriggerOutput (const cGH* const cgh, const int vindex) { assert (vindex>=0 && vindexcctk_iteration; return retval; } template int IOASCII ::GetGridOffset (const cGH* const cgh, const int dir, const char* const itempl, const char* const iglobal, const char* const ctempl, const char* const cglobal, const CCTK_REAL cfallback) { // First choice: explicit coordinate char cparam[1000]; snprintf (cparam, sizeof cparam, ctempl, outdim); const int ncparam = CCTK_ParameterQueryTimesSet (cparam, CCTK_THORNSTRING); assert (ncparam >= 0); if (ncparam > 0) { int ptype; const CCTK_REAL* const pcoord = ((const CCTK_REAL*)CCTK_ParameterGet (cparam, CCTK_THORNSTRING, &ptype)); assert (pcoord); const CCTK_REAL coord = *pcoord; assert (ptype == PARAMETER_REAL); return CoordToOffset (cgh, dir, coord, 0); } // Second choice: explicit index char iparam[1000]; snprintf (iparam, sizeof iparam, itempl, outdim); const int niparam = CCTK_ParameterQueryTimesSet (iparam, CCTK_THORNSTRING); assert (niparam >= 0); if (niparam > 0) { int ptype; const int* const pindex = (const int*)CCTK_ParameterGet (iparam, CCTK_THORNSTRING, &ptype); assert (pindex); const int index = *pindex; assert (ptype == PARAMETER_INT); return index; } // Third choice: explicit global coordinate const char* iothorn = CCTK_ImplementationThorn ("IO"); assert (iothorn); if (cglobal) { const int ncglobal = CCTK_ParameterQueryTimesSet (cglobal, iothorn); assert (ncglobal >= 0); if (ncglobal > 0) { int ptype; const CCTK_REAL* const pcoord = (const CCTK_REAL*)CCTK_ParameterGet (cglobal, iothorn, &ptype); assert (pcoord); const CCTK_REAL coord = *pcoord; assert (ptype == PARAMETER_REAL); return CoordToOffset (cgh, dir, coord, 0); } } // Fourth choice: explicit global index if (iglobal) { const int niglobal = CCTK_ParameterQueryTimesSet (iglobal, iothorn); assert (niglobal >= 0); if (niglobal > 0) { int ptype; const int* const pindex = (const int*)CCTK_ParameterGet (iglobal, iothorn, &ptype); assert (pindex); const int index = *pindex; assert (ptype == PARAMETER_INT); return index; } } // Fifth choice: default coordinate return CoordToOffset (cgh, dir, cfallback, 0); } template int IOASCII ::CoordToOffset (const cGH* cgh, const int dir, const CCTK_REAL coord, const int ifallback) { assert (dir>=1 && dir<=dim); assert (mglevel!=-1 && reflevel!=-1 && Carpet::map!=-1); const CCTK_REAL delta = cgh->cctk_delta_space[dir-1] / cgh->cctk_levfac[dir-1]; const CCTK_REAL lower = cgh->cctk_origin_space[dir-1]; #if 0 const int npoints = cgh->cctk_gsh[dir-1]; const CCTK_REAL upper = lower + (npoints-1) * delta; #endif const CCTK_REAL rindex = (coord - lower) / delta; int cindex = (int)floor(rindex + 0.75); #if 0 if (cindex<0 || cindex>=npoints) { cindex = ifallback; assert (dir>=1 && dir<=3); CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "The specified coordinate value %g for the %c-direction is not within the grid range [%g,%g] on convergence level %d, refinement level %d, map %d; using %g instead", coord, "xyz"[dir-1], lower, upper, mglevel, reflevel, Carpet::map, lower + delta * cindex); } assert (cindex>=0 && cindex const char* IOASCII ::GetStringParameter (const char* const parametertemplate) { char parametername[1000]; snprintf (parametername, sizeof parametername, parametertemplate, outdim); 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 || ptype == PARAMETER_KEYWORD); return pval; } template CCTK_INT IOASCII ::GetIntParameter (const char* const parametertemplate) { char parametername[1000]; snprintf (parametername, sizeof parametername, parametertemplate, outdim); int ptype; const CCTK_INT* const ppval = (const CCTK_INT*)CCTK_ParameterGet (parametername, CCTK_THORNSTRING, &ptype); assert (ppval); assert (ptype == PARAMETER_INT || ptype == PARAMETER_BOOLEAN); const CCTK_INT pval = *ppval; return pval; } template CCTK_REAL IOASCII ::GetRealParameter (const char* const parametertemplate) { char parametername[1000]; snprintf (parametername, sizeof parametername, parametertemplate, outdim); int ptype; const CCTK_REAL* const ppval = (const CCTK_REAL*)CCTK_ParameterGet (parametername, CCTK_THORNSTRING, &ptype); assert (ppval); assert (ptype == PARAMETER_REAL); const CCTK_REAL pval = *ppval; return pval; } void SetFlag (int index, const char* optstring, void* arg) { optstring = optstring; vector& flags = *(vector*)arg; flags.at(index) = true; } static CCTK_REAL nicelooking (CCTK_REAL const val, CCTK_REAL const base) { return floor(val / base + 0.5) * base; } // Output template void WriteASCII (ostream& os, const gdata* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper) { assert (DD<=D); assert (gfdata->has_storage()); if (gfdata->proc()==0) { // output on processor 0 int rank; MPI_Comm_rank (dist::comm, &rank); if (rank == 0) { assert (os.good()); os << "# iteration " << time << endl << "# refinement level " << rl << " multigrid level " << ml << " map " << m << " component " << c << " time level " << tl << endl << "# column format: it\ttl rl c ml\t"; assert (D>=1 && D<=3); const char* const coords = "xyz"; for (int d=0; d lo = gfext.lower()[dirs]; const vect up = gfext.upper()[dirs]; const vect str = gfext.stride()[dirs]; const bbox ext(lo,up,str); // Check whether the output origin is contained in the extent // of the data that should be output ivect org1(org); for (int d=0; d::iterator it=ext.begin(); do { ivect index(org); for (int d=0; d= 0); if (gfext.upper()[d] - gfext.lower()[d] == 0) { os << coord_lower[d]; } else { CCTK_REAL const dx = ((coord_upper[d] - coord_lower[d]) / (gfext.upper()[d] - gfext.lower()[d])); os << (nicelooking (coord_lower[d] + (index[d] - gfext.lower()[d]) * dx, dx * 1.0e-8)); } if (d != D-1) os << " "; } os << "\t"; switch (CCTK_VarTypeI(vi)) { #define TYPECASE(N,T) \ case N: \ os << (*(const data*)gfdata)[index]; \ break; #include "carpet_typecase.hh" #undef TYPECASE default: UnsupportedVarType(vi); } os << endl; ++it; for (int d=0; d* const tmp = gfdata->make_typed(vi); tmp->allocate(gfdata->extent(), 0); for (comm_state state; !state.done(); state.step()) { tmp->copy_from (state, gfdata, gfdata->extent()); } WriteASCII (os, tmp, gfext, vi, time, org, dirs, rl, ml, m, c, tl, coord_time, coord_lower, coord_upper); delete tmp; } } // Explicit instantiation for all output dimensions template class IOASCII<0>; template class IOASCII<1>; template class IOASCII<2>; template class IOASCII<3>; template void WriteASCII (ostream& os, const gdata<3>* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper); template void WriteASCII (ostream& os, const gdata<3>* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper); template void WriteASCII (ostream& os, const gdata<3>* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper); template void WriteASCII (ostream& os, const gdata<3>* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int rl, const int ml, const int m, const int c, const int tl, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper); } // namespace CarpetIOASCII