M5R6KQLXLGYSVKHVAX5AJKD6NYE6IM5Z6WVTR3BTKPJDNNKF3ARAC GECUITHDXKCWB7HBCM7EA5Q56JDDWUVUWHMW2K6OM7UW36DFAZ3QC KXFBF2APM2MBHH47ZXJ2R47IEYHWTNP2GVG4KULO66YR2DUUKCJQC GQVQJCNQNO2KD7ZMC7RESCUAMUAP7OED6CTA6SYLZKQGXKXZ6T3QC IVHURSHY4636OGIF3PNDO5CWOVRLJ75M4LP65J6I2E6KAM4QKF4AC 722HZ7UFINNE3YKSYKP2NHZ5XEG5QQLQHSKC7PREJZR3EX6RDYUAC KG47IF4CPCUT3BHS34WDRHTH5HYMBTY4OSTB3X7APR2E5ZJ32IYQC TVBD244E7Q7WV44CRBTFST535NUP3JAZH6OLL4IKDR3OWEXSU7HAC YIQN7NJTGEVKW7JZHL6CTH6EPCIXCNBYNURIGXPYZAOUX3VAJQMAC 33IC3UHCEPZLGS5ACS2JXHGT6CRU5LXU6PM6RDHCERPOIELVRVXQC QN2UTSQP4IMCMVXZNR24J22N24ASGXF6EWXQ2P3VWVQERUPFAFDQC 2DD222JSYRPHTXKSRXLSOMSCQPZUORNFLLO2P3GMIDELAAMD5MEQC AEVGZIZEUIC52MCK3J4V547YEV2R4YQL3JUJW7FSP4R34PSZ43DAC WASO7G5FJXRXWNH2U2FLUNEKU6VE63OI3HUYP64BVD4LMD6KE7OQC KCIWCVZOHG44WBOLKI2XK33WPHPRI5FWCETF4AOGTPZISKCW3CLQC 5XGIB7XMEZNBLA5ZLQTXRTC3AZ5CTRGMXWBPVMWXG4DPHKWDF4ZAC UZAKARMGORRQG733ZUPJOEGL5FG243I32NCC2SRSFDCZKUQ5A52QC BPRNUTY7MHK7LK4EY5MY5OFFG3ABOL7LWXD574L35M74YSQPULFAC UUGQGVC4WEKN64WAP7F5QPS2UHGQB5ZLMFRIYNWKMIEBDO3QRX4AC RCLGQ2LZMFVPBPTU2G55DJ6HZPOGGTPZRZCY54VGP6YLHANJ2LAQC OJZWEAJRLOA5FZAC6FMGBQ6XFQFDNO55IRWLFWDAYWM54MUIU5LAC VAF66DTVLDWNG7N2PEQYEH4OH5SPSMFBXKPR2PU67IIM6CVPCJ7AC 2DKSL6DKZAIYQUJGDULORCKU5K4Z5Z3W4RIKQYDSLKMCNQNDZFBAC BVR7DVINVPQG7PA6Z7QYVYNQ43YZL7XCC6AOMSMWMGAAB2Q43STAC BSMJ4V7GV3EOGY4KCSTOJQUOFE2OOCIKQETE4WC2WRNLWBQIBW3QC RTNZAS3UPI6GG3KY4Z5WVXJ4R2YF5427BB6WAV3GHRS5W7XPOSUQC FEMASUBNU32NSG4DNXZX54CGCA57PVRGYO46L3A6F2EJ4BCSJ3SAC TFYA5EBLWIMWQ4ULT6MK4Y2XWAFJH5JPLS2MGM7IR4ZWLNJHTNXQC TOBGHRPKEPSXDN56WGSZNWOMCBVJ4KUSLWYWI56MC2RR3MM3KLZAC void SetupGlobals() {DECLARE_CCTK_PARAMETERS;if (verbose)CCTK_VINFO("SetupGlobals");GHExt::GlobalData &globaldata = ghext->globaldata;const int numgroups = CCTK_NumGroups();globaldata.scalargroupdata.resize(numgroups);for (int gi = 0; gi < numgroups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);/* only grid functions live on levels (and the grid) */if(group.grouptype != CCTK_SCALAR and group.grouptype != CCTK_ARRAY)continue;assert(group.grouptype == CCTK_SCALAR);assert(group.vartype == CCTK_VARIABLE_REAL);assert(group.disttype == CCTK_DISTRIB_DEFAULT);assert(group.dim == dim);// TODO: vectors must be contiguous in memory and mine aren'tassert(group.vectorlength == 1);GHExt::GlobalData::ScalarGroupData &scalargroupdata = globaldata.scalargroupdata.at(gi);scalargroupdata.groupindex = gi;scalargroupdata.firstvarindex = CCTK_FirstVarIndexI(gi);scalargroupdata.numvars = group.numvars;// Allocate datascalargroupdata.data.resize(group.numtimelevels);for (int tl = 0; tl < int(scalargroupdata.data.size()); ++tl) {scalargroupdata.data.at(tl).resize(scalargroupdata.numvars);for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {// TODO: find out something that avoid new ?scalargroupdata.data.at(tl).at(vi) = new CCTK_REAL;// TODO: decide that valid_bnd == false always and rely on// initialization magic?scalargroupdata.valid.at(tl).at(vi).valid_int = false;scalargroupdata.valid.at(tl).at(vi).valid_bnd = true;// TODO: make poison_invalid and check_invalid virtual members of// CommonGroupDatapoison_invalid(scalargroupdata, vi, tl);check_valid(scalargroupdata, vi, tl);}}}}
struct CommonGroupData {int groupindex;int firstvarindex;int numvars;vector<vector<valid_t> > valid; // [time level][var index]// TODO: add poison_invalid and check_valid functions};struct GlobalData {// all data that exists on all levelsstruct ScalarGroupData : public CommonGroupData {// TODO: find out how to do this without a pointer to a single double but// also working around const vector<CCTK_REAL> issuesvector<vector<CCTK_REAL *> > data; // [time level][var index]};// TODO: right now this is sized for the total number of groupsvector<ScalarGroupData> scalargroupdata; // [group index]};GlobalData globaldata;
}}}void OutputScalars(const cGH *restrict cctkGH) {DECLARE_CCTK_ARGUMENTS;DECLARE_CCTK_PARAMETERS;static Timer timer("OutputNorms");Interval interval(timer);const bool is_root = CCTK_MyProc(nullptr) == 0;if (!is_root)return;const int numgroups = CCTK_NumGroups();for (int gi = 0; gi < numgroups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR)continue;string groupname = unique_ptr<char>(CCTK_GroupName(gi)).get();groupname = regex_replace(groupname, regex("::"), "-");for (auto &c : groupname)c = tolower(c);ostringstream buf;buf << out_dir << "/" << groupname;const string filename = buf.str();ofstream file(filename.c_str(), std::ofstream::out | std::ofstream::app);// TODO: write proper header (once)#if 0// Output headerfile << "#"<< "\t"<< "iteration"<< "\t"<< "time";for (int vi = 0; vi < groupdata.numvars; ++vi) {file << "\t" << CCTK_VarName(group.firstvarindex + vi);file << "\n";#endif// Output dataconst GHExt::GlobalData &restrict globaldata = ghext->globaldata;const GHExt::GlobalData::ScalarGroupData &restrict scalargroupdata =globaldata.scalargroupdata.at(gi);const int tl = 0;file << cctkGH->cctk_iteration << "\t" << cctkGH->cctk_time;for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {file << "\t" << *scalargroupdata.data.at(tl).at(vi);
}}// Set grid scalars to nanvoid poison_invalid(const GHExt::GlobalData::ScalarGroupData &scalargroupdata, int vi,int tl) {DECLARE_CCTK_PARAMETERS;if (!poison_undefined_values)return;const valid_t &valid = scalargroupdata.valid.at(tl).at(vi);if (valid.valid_int && valid.valid_bnd)return;// scalar have no boundary so we expect it to alway be validassert(valid.valid_bnd);if (!valid.valid_int) {CCTK_REAL *restrict const ptr = scalargroupdata.data.at(tl).at(vi);*ptr = 0.0 / 0.0;
}// Ensure grid scalars are not nanvoid check_valid(const GHExt::GlobalData::ScalarGroupData &scalargroupdata, int vi,int tl) {DECLARE_CCTK_PARAMETERS;if (!poison_undefined_values)return;const valid_t &valid = scalargroupdata.valid.at(tl).at(vi);if (!valid.valid_int && !valid.valid_bnd)return;// scalar have no boundary so we expect it to alway be validassert(valid.valid_bnd);atomic<bool> found_nan{false};if (valid.valid_int) {CCTK_REAL *restrict const ptr = scalargroupdata.data.at(tl).at(vi);if (CCTK_BUILTIN_EXPECT(isnan(*ptr), false)) {found_nan = true;}}if (CCTK_BUILTIN_EXPECT(found_nan, false)) {const char *where = valid.valid_int && valid.valid_bnd? "interior and boundary": valid.valid_int ? "interior" : "boundary";CCTK_VERROR("Grid Scalar \"%s\" has nans on time level %d; expected valid %s",CCTK_FullVarName(scalargroupdata.firstvarindex + vi),tl, where);}
// Grid scalar pointers{auto &restrict globaldata = ghext->globaldata;const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR)continue;auto &restrict scalargroupdata = globaldata.scalargroupdata.at(gi);for (int tl = 0; tl < int(scalargroupdata.data.size()); ++tl) {const auto &restrict vars = scalargroupdata.data.at(tl);for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {cctkGH->data[scalargroupdata.firstvarindex + vi][tl] = vars.at(vi);}}}}
// Grid scalar pointers{auto &restrict globaldata = ghext->globaldata;const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR)continue;auto &restrict scalargroupdata = globaldata.scalargroupdata.at(gi);for (int tl = 0; tl < int(scalargroupdata.data.size()); ++tl) {for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {cctkGH->data[scalargroupdata.firstvarindex + vi][tl] = nullptr;}}}}
for (auto &restrict groupdata : leveldata.groupdata) {
const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_GF)continue;auto &restrict groupdata = leveldata.groupdata.at(gi);
for (auto &restrict groupdata : leveldata.groupdata) {
const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_GF)continue;auto &restrict groupdata = leveldata.groupdata.at(gi);
for (auto &restrict groupdata : leveldata.groupdata) {
const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_GF)continue;auto &restrict groupdata = leveldata.groupdata.at(gi);
// invalidate scalars{auto &restrict globaldata = ghext->globaldata;const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR)continue;auto &restrict scalargroupdata = globaldata.scalargroupdata.at(gi);const bool checkpoint = get_group_checkpoint_flag(scalargroupdata.groupindex);if (!checkpoint) {// Invalidate all time levelsconst int ntls = scalargroupdata.data.size();for (int tl = 0; tl < ntls; ++tl) {for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {scalargroupdata.valid.at(tl).at(vi) = valid_t();poison_invalid(scalargroupdata, vi, tl);}}}}}
for (auto &restrict groupdata : leveldata.groupdata) {
const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_GF)continue;auto &restrict groupdata = leveldata.groupdata.at(gi);
// cycle scalars{auto &restrict globaldata = ghext->globaldata;const int num_groups = CCTK_NumGroups();for (int gi = 0; gi < num_groups; ++gi) {cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR)continue;auto &restrict scalargroupdata = globaldata.scalargroupdata.at(gi);const int ntls = scalargroupdata.data.size();// Rotate time levels and invalidate current time levelif (ntls > 1) {auto tmp = move(scalargroupdata.data.at(ntls - 1));for (int tl = ntls - 1; tl > 0; --tl)scalargroupdata.data.at(tl) = scalargroupdata.data.at(tl - 1);scalargroupdata.data.at(0) = tmp;vector<valid_t> vtmp = move(scalargroupdata.valid.at(ntls - 1));for (int tl = ntls - 1; tl > 0; --tl)scalargroupdata.valid.at(tl) = move(scalargroupdata.valid.at(tl - 1));scalargroupdata.valid.at(0) = move(vtmp);for (int vi = 0; vi < scalargroupdata.numvars; ++vi)scalargroupdata.valid.at(0).at(vi) = valid_t();for (int vi = 0; vi < scalargroupdata.numvars; ++vi)poison_invalid(scalargroupdata, vi, 0);}}}
const auto &restrict groupdata = leveldata.groupdata.at(rd.gi);
cGroup group;int ierr = CCTK_GroupData(rd.gi, &group);assert(!ierr);// TODO: something about this cast (https://stackoverflow.com/questions/6179314/casting-pointers-and-the-ternary-operator-have-i-reinvented-the-wheel)const GHExt::CommonGroupData * groupdata = group.grouptype == CCTK_GF ?static_cast<const GHExt::CommonGroupData *>(&leveldata.groupdata.at(rd.gi)) :static_cast<const GHExt::CommonGroupData *>(&globaldata.scalargroupdata.at(rd.gi));
auto &restrict groupdata = leveldata.groupdata.at(wr.gi);valid_t &have = groupdata.valid.at(wr.tl).at(wr.vi);
cGroup group;int ierr = CCTK_GroupData(wr.gi, &group);assert(!ierr);GHExt::CommonGroupData * groupdata = group.grouptype == CCTK_GF ?static_cast<GHExt::CommonGroupData *>(&leveldata.groupdata.at(wr.gi)) :static_cast<GHExt::CommonGroupData *>(&globaldata.scalargroupdata.at(wr.gi));valid_t &have = groupdata->valid.at(wr.tl).at(wr.vi);
auto &restrict groupdata = leveldata.groupdata.at(wr.gi);
cGroup group;int ierr = CCTK_GroupData(wr.gi, &group);assert(!ierr);GHExt::CommonGroupData * groupdata = group.grouptype == CCTK_GF ?static_cast<GHExt::CommonGroupData *>(&leveldata.groupdata.at(wr.gi)) :static_cast<GHExt::CommonGroupData *>(&globaldata.scalargroupdata.at(wr.gi));