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't
assert(group.vectorlength == 1);
GHExt::GlobalData::ScalarGroupData &scalargroupdata = globaldata.scalargroupdata.at(gi);
scalargroupdata.groupindex = gi;
scalargroupdata.firstvarindex = CCTK_FirstVarIndexI(gi);
scalargroupdata.numvars = group.numvars;
// Allocate data
scalargroupdata.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
// CommonGroupData
poison_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 levels
struct 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> issues
vector<vector<CCTK_REAL *> > data; // [time level][var index]
};
// TODO: right now this is sized for the total number of groups
vector<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 header
file << "#"
<< "\t"
<< "iteration"
<< "\t"
<< "time";
for (int vi = 0; vi < groupdata.numvars; ++vi) {
file << "\t" << CCTK_VarName(group.firstvarindex + vi);
file << "\n";
#endif
// Output data
const 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 nan
void 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 valid
assert(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 nan
void 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 valid
assert(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 levels
const 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 level
if (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));