#include #include #include #include #include #include #include #include #include #include #include #include "cctk.h" #include "cctk_Parameters.h" #include "CactusBase/IOUtil/src/ioutil_CheckpointRecovery.h" #include "Carpet/CarpetLib/src/data.hh" #include "Carpet/CarpetLib/src/gdata.hh" #include "Carpet/CarpetLib/src/gf.hh" #include "Carpet/CarpetLib/src/ggf.hh" #include "Carpet/CarpetLib/src/vect.hh" #include "carpet.hh" #include "ioser.hh" #include "bbhutil.h" extern "C" { int vsxynt(const char *name, double t, double *x, double *y, int n); } static const char* rcsid = "$Header:$"; // That's a hack namespace Carpet { void UnsupportedVarType (const int vindex); } using namespace std; using namespace Carpet; static bool CheckForVariable (const cGH* const cgh, const char* const varlist, const int vindex); static void SetFlag (int index, const char* optstring, void* arg); //void assign_ser_output_element (double& range, const ivect& index); //void assign_ser_output_element (double& range, const vect index); template static void write_ser ( const char *gfname, const generic_data* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int tl, const int rl, const int c, const int ml, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper, const int strip_left, const int strip_right); int CarpetIOSerStartup() { CarpetIOSer<1>::Startup(); CarpetIOSer<2>::Startup(); CarpetIOSer<3>::Startup(); return 0; } // Definition of static members template int CarpetIOSer::GHExtension; template int CarpetIOSer::IOMethod; template vector CarpetIOSer::do_truncate; template vector > CarpetIOSer::last_output; template int CarpetIOSer::Startup() { char msg[1000]; sprintf (msg, "AMR %dD Ser I/O provided by CarpetIOSer", outdim); CCTK_RegisterBanner (msg); char extension_name[1000]; sprintf (extension_name, "CarpetIOSer_%dD", outdim); GHExtension = CCTK_RegisterGHExtension(extension_name); CCTK_RegisterGHExtensionSetupGH (GHExtension, SetupGH); char method_name[1000]; sprintf (method_name, "IOSer_%dD", outdim); IOMethod = CCTK_RegisterIOMethod (method_name); CCTK_RegisterIOMethodOutputGH (IOMethod, OutputGH); CCTK_RegisterIOMethodOutputVarAs (IOMethod, OutputVarAs); CCTK_RegisterIOMethodTimeToOutput (IOMethod, TimeToOutput); CCTK_RegisterIOMethodTriggerOutput (IOMethod, TriggerOutput); return 0; } template void* CarpetIOSer ::SetupGH (tFleshConfig* const fc, const int convLevel, cGH* const cgh) { DECLARE_CCTK_PARAMETERS; // 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; rl int CarpetIOSer ::OutputGH (const cGH* const cgh) { for (int vindex=0; vindex int CarpetIOSer ::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 && var dirs; for (int d=0; d=0 && dirs[d]<3); const char* const coords = "xyz"; sprintf (filename, "%s%c", filename, coords[dirs[d]]); } const char* const suffixes = "lpv"; sprintf (filename, "%s%c", filename, suffixes[outdim-1]); ofstream file; if (CCTK_MyProc(cgh)==0) { // If this is the first time, then write a nice header on // the root processor if (do_truncate[n]) { struct stat fileinfo; if (! IOUtil_RestartFromRecovery(cgh) || stat(filename, &fileinfo)!=0) { file.open (filename, ios::out | ios::trunc); assert (file.good()); file << "# " << varname; for (int d=0; d offset(0); switch (outdim) { case 1: switch (dirs[0]) { case 0: offset[1] = GetGridOffset (cgh, 2, "out%dD_xline_yi", "out_xline_yi", "out%dD_xline_y", "out_xline_y", out_xline_y); offset[2] = GetGridOffset (cgh, 3, "out%dD_xline_zi", "out_xline_zi", "out%dD_xline_z", "out_xline_z", out_xline_z); break; case 1: offset[0] = GetGridOffset (cgh, 1, "out%dD_yline_xi", "out_yline_xi", "out%dD_yline_x", "out_yline_x", out_yline_x); offset[2] = GetGridOffset (cgh, 3, "out%dD_yline_zi", "out_yline_zi", "out%dD_yline_z", "out_yline_z", out_yline_z); break; case 2: offset[0] = GetGridOffset (cgh, 1, "out%dD_zline_xi", "out_zline_xi", "out%dD_zline_x", "out_zline_x", out_zline_x); offset[1] = GetGridOffset (cgh, 2, "out%dD_zline_yi", "out_zline_yi", "out%dD_zline_y", "out_zline_y", out_zline_y); break; default: abort(); } break; default: abort(); } // Traverse all components on this refinement and multigrid // level BEGIN_COMPONENT_LOOP(cgh) { const generic_gf* ff = 0; assert (var < (int)arrdata[group].data.size()); ff = (generic_gf*)arrdata[group].data[var]; const generic_data* const data = (*ff) (tl, reflevel, component, mglevel); const bbox ext = data->extent(); const vect offset1 = offset * ext.stride(); // coordinates const double coord_time = cgh->cctk_time; vect global_lower, global_upper; for (int d=0; d global_extent (hh->baseextent.upper() - hh->baseextent.lower() + hh->baseextent.stride() * (dd->lghosts + dd->ughosts)); vect coord_delta; for (int d=0; dextent().lower()" // (you'll pick up the integer operator* then) const vect coord_lower = global_lower + coord_delta * vect(data->extent().lower()); const vect coord_upper = global_lower + coord_delta * vect(data->extent().upper()); char *gfname = new char[strlen(alias)+strlen(out1D_tag)+1]; sprintf(gfname,"%s%s",alias,out1D_tag); write_ser (gfname, data, ext, n, cgh->cctk_iteration, offset1, dirs, tl, reflevel, component, mglevel, coord_time, coord_lower, coord_upper, strip_left, strip_right); delete [] gfname; // Append EOL after every component if (CCTK_MyProc(cgh)==0) { if (separate_components) { assert (file.good()); file << endl; } } assert (file.good()); } END_COMPONENT_LOOP(cgh); // 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()); } // if (desired) } // if (ascending) // Next direction combination done = true; for (int d=0; d int CarpetIOSer ::TimeToOutput (const cGH* const cgh, const int vindex) { DECLARE_CCTK_PARAMETERS; assert (vindex>=0 && vindexcctk_iteration % myoutevery != 0) { // Nothing should be output during this iteration return 0; } if (! CheckForVariable(cgh, GetStringParameter("out%dD_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; } template int CarpetIOSer ::TriggerOutput (const cGH* const cgh, const int vindex) { assert (vindex>=0 && vindexcctk_iteration; return retval; } template int CarpetIOSer ::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]; sprintf (cparam, ctempl, outdim); if (CCTK_ParameterQueryTimesSet (cparam, CCTK_THORNSTRING) > 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]; sprintf (iparam, itempl, outdim); if (CCTK_ParameterQueryTimesSet (iparam, CCTK_THORNSTRING) > 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 if (CCTK_ParameterQueryTimesSet (cglobal, "IO") > 0) { int ptype; const CCTK_REAL* const pcoord = (const CCTK_REAL*)CCTK_ParameterGet (cglobal, "IO", &ptype); assert (pcoord); const CCTK_REAL coord = *pcoord; assert (ptype == PARAMETER_REAL); return CoordToOffset (cgh, dir, coord, 0); } // Fourth choice: explicit global index if (CCTK_ParameterQueryTimesSet (iglobal, "IO") > 0) { int ptype; const int* const pindex = (const int*)CCTK_ParameterGet (iglobal, "IO", &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 CarpetIOSer ::CoordToOffset (const cGH* cgh, const int dir, const CCTK_REAL coord, const int ifallback) { assert (dir>=1 && dir<=dim); CCTK_REAL lower, upper; CCTK_CoordRange (cgh, &lower, &upper, dir, 0, "cart3d"); const int npoints = cgh->cctk_gsh[dir-1]; const CCTK_REAL rindex = (coord - lower) / (upper - lower) * (npoints-1); const int levfac = cgh->cctk_levfac[dir-1]; int cindex = (int)floor(rindex / levfac + 0.5 + 1e-6) * levfac; if (cindex<0 || cindex>=npoints) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "The specified coordinate value %g is not within the grid range [%g,%g]", coord, lower, upper); cindex = ifallback; } assert (cindex>=0 && cindex const char* CarpetIOSer ::GetStringParameter (const char* const parametertemplate, const char* const fallback) { char parametername[1000]; sprintf (parametername, parametertemplate, outdim); 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; } template int CarpetIOSer ::GetIntParameter (const char* const parametertemplate, const int fallback) { char parametername[1000]; sprintf (parametername, parametertemplate, outdim); 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 void data::assign_ser_output_element (double& range, const vect index) { range = (*this)[index]; } */ // Output template void write_ser ( const char *gfname, const generic_data* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int tl, const int rl, const int c, const int ml, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper, const int strip_left, const int strip_right) { assert (DD<=D); if (gfdata->proc()==0) { // output on processor 0 int rank; MPI_Comm_rank (dist::comm, &rank); if (rank == 0) { assert (D>=1 && D<=3); assert (DD==1); const char* const coords = "xyz"; const vect 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 vect org1(org); for (int d=0; d::iterator it=ext.begin(); it!=ext.end(); ++it) { vect index(org); for (int d=0; d*)gfdata)[index]; // elem++; // cout << "CarpetIOSer, before switch" << endl << flush; switch (CCTK_VarTypeI(vi)) { #define TYPECASE(N,T) \ case N: \ range[elem] = (*(data*)gfdata)[index]; \ elem++;\ break; #include "Carpet/Carpet/src/typecase" #undef TYPECASE default: UnsupportedVarType(vi); } // cout << "CarpetIOSer, after switch" << endl << flush; } assert(elem == nelems); char *window_name = new char[strlen(gfname)+100]; sprintf(window_name,"%s_l%d.%c",gfname,rl,"xyz"[dirs[0]]); vsxynt(window_name, coord_time, domain+strip_left, range+strip_left, nelems-strip_left-strip_right); delete [] window_name; delete [] domain; delete [] range; } // if extent().contains(org1) } } else { // copy to processor 0 and output there /* generic_data* const tmp = make_typed(); tmp->allocate(extent(), 0); tmp->copy_from (this, extent()); tmp->write_ser (gfname, time, org, dirs, tl, rl, c, ml, coord_time, coord_lower, coord_upper); delete tmp; */ generic_data* const tmp = gfdata->make_typed(); tmp->allocate(gfdata->extent(), 0); tmp->copy_from (gfdata, gfdata->extent()); write_ser (gfname, tmp, gfext, vi, time, org, dirs, tl, rl, c, ml, coord_time, coord_lower, coord_upper, strip_left, strip_right); delete tmp; } } // Explicit instantiation for all output dimensions template class CarpetIOSer<1>; template class CarpetIOSer<2>; template class CarpetIOSer<3>; template void write_ser ( const char *gfname, const generic_data<3>* const gfdata, const bbox& gfext, const int vi, const int time, const vect& org, const vect& dirs, const int tl, const int rl, const int c, const int ml, const CCTK_REAL coord_time, const vect& coord_lower, const vect& coord_upper, const int strip_left, const int strip_right);