5B6D6UREX556XOAM75B3WOIGE6DT43HIS6JOVJYNXUT3FSZDUPBAC 3QWZBYJLGJFSLSL2ZG4JVCSUGF73TQJNPHV3MRMIIBUA7XNUU7NAC WNYN6LX3FYXXW3TKGRA7GRLFMIR4YXQMFAWJCB76QAXLY6JR4Q7AC ANVJBTFKJDVQBSYMHQ455IQVAOCD3YVYZLDH5K2BS67UTSF5JNBQC PY277W4CPZCB5NTENNXI4TNA7IFBOAQA2ZS7AGVTNCFSXJXKPPGAC IVHURSHY4636OGIF3PNDO5CWOVRLJ75M4LP65J6I2E6KAM4QKF4AC HVV73EHEMEFVCPS75XZAFUGWOY7LBYOJOIDNHJUK4MB5QTS3CTJQC 722HZ7UFINNE3YKSYKP2NHZ5XEG5QQLQHSKC7PREJZR3EX6RDYUAC U77PE56ICORZNQW33NXGSEMW7GDHCSSZ4EXB6OHBJSHEG6WHYSSQC TY6WZ2R2THWDIQCTDZIFSX3S2SNSC67GUFE7S4TFXLRQNP7SNUBAC PU3YB5FX7NK65435O3H3AHCTUDHFRW7IOARLJJ4NBFG3GTIYVLCQC WV2J4VRLSW42SGIRDLF326LLC7L2ABAMSZ3YKABS532K27U3X3CAC FS7Q6TUHBK5WSRDC3TM6KV2BPGWATRBLDHFGEJ72BR3FRDEOC3WAC JN2TPHENEBIY2OE5FRCQ2E6QCL6FPVHJHUCP4UODD6DITRVV2LIQC BVR7DVINVPQG7PA6Z7QYVYNQ43YZL7XCC6AOMSMWMGAAB2Q43STAC ZARZZPSISIOCXZOWNJQMMQSQPXFSZLDDIDAFY35X2GV37RBB7WUAC M5R6KQLXLGYSVKHVAX5AJKD6NYE6IM5Z6WVTR3BTKPJDNNKF3ARAC EHF2P5PKVTMAUL5R5QSZ3DS3VLE7Z6SHJTCZAGRBTQ66Y7HZKNYQC WZPFZTNOJMA2ANRX22OL6QUCU6KUWSZVQJSL46KKBEB37MWRVNNAC T3TZRPPAIA24I3YL3JFB4XEAYCWU3HJAJUCF7NNIFMP4I5X4SM5QC XU5HOJREK4XY4NBCJINLZPKQNKSYOLUDTWR47REFSNQKDOSNDXLQC IV3MLV677VWS7GLESBQZ4HRFNW5TBFBIGIBWXTCHAER3FQ7VG3GQC KCIWCVZOHG44WBOLKI2XK33WPHPRI5FWCETF4AOGTPZISKCW3CLQC VMCDMDXKME66ESRMB3PYSUZZH2XG2GIQMEOEKRH33WGCEBPXTWUQC UZAKARMGORRQG733ZUPJOEGL5FG243I32NCC2SRSFDCZKUQ5A52QC WASO7G5FJXRXWNH2U2FLUNEKU6VE63OI3HUYP64BVD4LMD6KE7OQC BJDGFYBMECTJG7BHLNHLSCUCBVYHAY6OGY37FIJP6JDGNDXQNQVAC W4XMGPEHBCV6AAPJBI4SSEMCDB6KKCGRUC2X2F5YLBY22OR3ICPAC X7A7HYGU2NPWCZCG5SYFD4NINYDP6UYWFFE3WP6YNLSDIABG2KJAC GKKJ75HX2ERLVBZVE2CUB6T3J2SUT7R3UKEKTEYNOG43ZKX6X5MQC } else if (group.grouptype == CCTK_SCALAR) {assert(group.vartype == CCTK_VARIABLE_REAL);assert(group.disttype == CCTK_DISTRIB_CONSTANT);assert(group.dim == 0);globaldata.scalargroupdata.at(gi) =make_unique<GHExt::GlobalData::ScalarGroupData>();GHExt::GlobalData::ScalarGroupData &scalargroupdata =*globaldata.scalargroupdata.at(gi);scalargroupdata.groupindex = gi;scalargroupdata.firstvarindex = CCTK_FirstVarIndexI(gi);scalargroupdata.numvars = group.numvars;scalargroupdata.do_checkpoint = get_group_checkpoint_flag(gi);scalargroupdata.do_restrict = get_group_restrict_flag(gi);
assert(group.grouptype == CCTK_SCALAR);assert(group.vartype == CCTK_VARIABLE_REAL);assert(group.disttype == CCTK_DISTRIB_CONSTANT);assert(group.dim == 0);
// Set up dynamic datascalargroupdata.dimension = 0;scalargroupdata.activetimelevels = 1;// Allocate datascalargroupdata.data.resize(group.numtimelevels);scalargroupdata.valid.resize(group.numtimelevels);for (int tl = 0; tl < int(scalargroupdata.data.size()); ++tl) {scalargroupdata.data.at(tl).resize(scalargroupdata.numvars);why_valid_t why([] { return "SetupGlobals"; });scalargroupdata.valid.at(tl).resize(scalargroupdata.numvars, why);for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {// TODO: decide that valid_bnd == false always and rely on// initialization magic?valid_t valid;valid.valid_int = false;valid.valid_outer = true;valid.valid_ghosts = true;scalargroupdata.valid.at(tl).at(vi).set(valid,[] { return "SetupGlobals"; });// TODO: make poison_invalid and check_invalid virtual members of// CommonGroupDatapoison_invalid(scalargroupdata, vi, tl);check_valid(scalargroupdata, vi, tl, [] { return "SetupGlobals"; });}}} else {assert(group.grouptype == CCTK_ARRAY);assert(group.vartype == CCTK_VARIABLE_REAL);assert(group.disttype == CCTK_DISTRIB_CONSTANT);assert(group.dim > 0 && group.dim <= dim);globaldata.arraygroupdata.at(gi) =make_unique<GHExt::GlobalData::ArrayGroupData>();GHExt::GlobalData::ArrayGroupData &arraygroupdata =*globaldata.arraygroupdata.at(gi);arraygroupdata.groupindex = gi;arraygroupdata.firstvarindex = CCTK_FirstVarIndexI(gi);arraygroupdata.numvars = group.numvars;arraygroupdata.do_checkpoint = get_group_checkpoint_flag(gi);arraygroupdata.do_restrict = get_group_restrict_flag(gi);
globaldata.scalargroupdata.at(gi) =make_unique<GHExt::GlobalData::ScalarGroupData>();GHExt::GlobalData::ScalarGroupData &scalargroupdata =*globaldata.scalargroupdata.at(gi);scalargroupdata.groupindex = gi;scalargroupdata.firstvarindex = CCTK_FirstVarIndexI(gi);scalargroupdata.numvars = group.numvars;scalargroupdata.do_checkpoint = get_group_checkpoint_flag(gi);scalargroupdata.do_restrict = get_group_restrict_flag(gi);
CCTK_INT const *const *const sz = CCTK_GroupSizesI(gi);arraygroupdata.array_size = 1;for (int d = 0; d < group.dim; ++d) {arraygroupdata.array_size = arraygroupdata.array_size * *sz[d];}
// Allocate datascalargroupdata.data.resize(group.numtimelevels);scalargroupdata.valid.resize(group.numtimelevels);for (int tl = 0; tl < int(scalargroupdata.data.size()); ++tl) {scalargroupdata.data.at(tl).resize(scalargroupdata.numvars);why_valid_t why([] { return "SetupGlobals"; });scalargroupdata.valid.at(tl).resize(scalargroupdata.numvars, why);for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {// TODO: decide that valid_bnd == false always and rely on// initialization magic?valid_t valid;valid.valid_int = false;valid.valid_outer = true;valid.valid_ghosts = true;scalargroupdata.valid.at(tl).at(vi).set(valid,[] { return "SetupGlobals"; });
// Set up dynamic dataarraygroupdata.dimension = group.dim;arraygroupdata.activetimelevels = 1;for (int d = 0; d < group.dim; ++d) {arraygroupdata.lsh[d] = *sz[d];arraygroupdata.ash[d] = *sz[d];arraygroupdata.gsh[d] = *sz[d];arraygroupdata.nghostzones[d] = 0;arraygroupdata.lbnd[d] = 0;arraygroupdata.ubnd[d] = *sz[d]-1;arraygroupdata.bbox[2*d] = arraygroupdata.bbox[2*d+1] = 1;}// Allocate dataarraygroupdata.data.resize(group.numtimelevels);arraygroupdata.valid.resize(group.numtimelevels);for (int tl = 0; tl < int(arraygroupdata.data.size()); ++tl) {arraygroupdata.data.at(tl).resize(arraygroupdata.numvars*arraygroupdata.array_size);why_valid_t why([] { return "SetupGlobals"; });arraygroupdata.valid.at(tl).resize(arraygroupdata.numvars, why);for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {// TODO: decide that valid_bnd == false always and rely on// initialization magic?valid_t valid;valid.valid_int = false;valid.valid_outer = true;valid.valid_ghosts = true;arraygroupdata.valid.at(tl).at(vi).set(valid,[] { return "SetupGlobals"; });
// TODO: make poison_invalid and check_invalid virtual members of// CommonGroupDatapoison_invalid(scalargroupdata, vi, tl);check_valid(scalargroupdata, vi, tl, [] { return "SetupGlobals"; });
// TODO: make poison_invalid and check_invalid virtual members of// CommonGroupDatapoison_invalid(arraygroupdata, vi, tl);check_valid(arraygroupdata, vi, tl, [] { return "SetupGlobals"; });}
YAML::Emitter &operator<<(YAML::Emitter &yaml,const GHExt::GlobalData::ArrayGroupData &arraygroupdata) {yaml << YAML::LocalTag("arraygroupdata-1.0.0");yaml << YAML::BeginMap;yaml << YAML::Key << "commongroupdata" << YAML::Value<< (GHExt::CommonGroupData)arraygroupdata;yaml << YAML::Key << "data" << YAML::Value << arraygroupdata.data;yaml << YAML::EndMap;return yaml;}
}return 0;}int GroupDynamicData(const cGH *cctkGH, int gi, cGroupDynamicData *data) {// Return values:// 0 for success// -1 if given pointer to data structure is NULL// -3 if given GH pointer is invalid// (-77 if group has zero variables)// -78 if group does not existif (not cctkGH)return -3;if (not(gi >= 0 and gi < CCTK_NumGroups()))return -78;if (not data)return -1;cGroup group;int ierr = CCTK_GroupData(gi, &group);assert(!ierr);if (group.grouptype != CCTK_SCALAR and group.grouptype != CCTK_ARRAY) {data->dim = group.dim;data->lsh = cctkGH->cctk_lsh;data->ash = cctkGH->cctk_ash;data->gsh = cctkGH->cctk_gsh;data->lbnd = cctkGH->cctk_lbnd;data->ubnd = cctkGH->cctk_ubnd;data->bbox = cctkGH->cctk_bbox;data->nghostzones = cctkGH->cctk_nghostzones;data->activetimelevels = CCTK_ActiveTimeLevelsGI(cctkGH, gi);} else if (group.grouptype == CCTK_SCALAR) {GHExt::GlobalData &globaldata = ghext->globaldata;GHExt::GlobalData::ScalarGroupData &scalargroupdata =*globaldata.scalargroupdata.at(gi);data->dim = scalargroupdata.dimension;data->lsh = scalargroupdata.lsh;data->ash = scalargroupdata.ash;data->gsh = scalargroupdata.gsh;data->lbnd = scalargroupdata.lbnd;data->ubnd = scalargroupdata.ubnd;data->bbox = scalargroupdata.bbox;data->nghostzones = scalargroupdata.nghostzones;data->activetimelevels = scalargroupdata.activetimelevels;} else { // CCTK_ARRAYGHExt::GlobalData &globaldata = ghext->globaldata;GHExt::GlobalData::ArrayGroupData &arraygroupdata =*globaldata.arraygroupdata.at(gi);data->dim = arraygroupdata.dimension;data->lsh = arraygroupdata.lsh;data->ash = arraygroupdata.ash;data->gsh = arraygroupdata.gsh;data->lbnd = arraygroupdata.lbnd;data->ubnd = arraygroupdata.ubnd;data->bbox = arraygroupdata.bbox;data->nghostzones = arraygroupdata.nghostzones;data->activetimelevels = arraygroupdata.activetimelevels;
ArrayGroupData() {dimension = -1;activetimelevels = -1;for (int d = 0; d < dim; d++) {lsh[d] = -1;ash[d] = -1;gsh[d] = -1;lbnd[d] = -1;ubnd[d] = -1;bbox[2*d] = bbox[2*d+1] = -1;nghostzones[d] = -1;}}friend YAML::Emitter &operator<<(YAML::Emitter &yaml,const ArrayGroupData &arraygroupdata);};// TODO: right now this is sized for the total number of groupsvector<unique_ptr<ArrayGroupData> > arraygroupdata; // [group index]
}// Ensure grid arrays are validvoid error_if_invalid(const GHExt::GlobalData::ArrayGroupData &groupdata,int vi, int tl, const valid_t &required,const function<string()> &msg) {const valid_t &have = groupdata.valid.at(tl).at(vi).get();if (CCTK_BUILTIN_EXPECT((required & ~have).valid_any(), false))CCTK_VERROR("%s: Grid array \"%s\" is invalid on time level %d; ""required %s, found %s",msg().c_str(), CCTK_FullVarName(groupdata.firstvarindex + vi),tl, string(required).c_str(),string(groupdata.valid.at(tl).at(vi)).c_str());}void warn_if_invalid(const GHExt::GlobalData::ArrayGroupData &groupdata,int vi, int tl, const valid_t &required,const function<string()> &msg) {const valid_t &have = groupdata.valid.at(tl).at(vi).get();if (CCTK_BUILTIN_EXPECT((required & ~have).valid_any(), false))CCTK_VWARN(CCTK_WARN_ALERT,"%s: Grid array \"%s\" is invalid on time level %d; ""required %s, found %s",msg().c_str(), CCTK_FullVarName(groupdata.firstvarindex + vi),tl, string(required).c_str(),string(groupdata.valid.at(tl).at(vi)).c_str());}// Set (distrib=const) grid arrays to nanvoid poison_invalid(const GHExt::GlobalData::ArrayGroupData &arraygroupdata,int vi, int tl) {DECLARE_CCTK_PARAMETERS;if (!poison_undefined_values)return;const valid_t &valid = arraygroupdata.valid.at(tl).at(vi).get();if (valid.valid_all())return;//TODO: poison needs to poison entire array, not just the first elementif (!valid.valid_int) {CCTK_REAL *restrict const ptr =const_cast<CCTK_REAL *>(&arraygroupdata.data.at(tl).at(vi));*ptr = 0.0 / 0.0;}}// Ensure grid arrays are not nanvoid check_valid(const GHExt::GlobalData::ArrayGroupData &arraygroupdata,int vi, int tl, const function<string()> &msg) {DECLARE_CCTK_PARAMETERS;if (!poison_undefined_values)return;const valid_t &valid = arraygroupdata.valid.at(tl).at(vi).get();if (!valid.valid_any())return;// arrays have no boundary so we expect them to alway be validassert(valid.valid_outer && valid.valid_ghosts);//TODO: nan checker needs to check every element of the arrays// int ubnd = *arraygroupdata.info->ubnd;atomic<size_t> nan_count{0};if (valid.valid_int) {const CCTK_REAL *restrict const ptr = &arraygroupdata.data.at(tl).at(vi);// for (int i = 0; i < ubnd; i++) {if (CCTK_BUILTIN_EXPECT(!CCTK_isfinite(*ptr), false)) {++nan_count;}// }}if (CCTK_BUILTIN_EXPECT(nan_count > 0, false))CCTK_VERROR("%s: Grid Array \"%s\" has %td nans on time level %d; ""expected valid %s",msg().c_str(),CCTK_FullVarName(arraygroupdata.firstvarindex + vi),size_t(nan_count), tl,string(arraygroupdata.valid.at(tl).at(vi)).c_str());
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] =const_cast<CCTK_REAL *>(&vars.at(vi));
} else if (group.grouptype == CCTK_SCALAR) {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] =const_cast<CCTK_REAL *>(&vars.at(vi));}
} else { // CCTK_ARRAYauto &restrict arraygroupdata = *globaldata.arraygroupdata.at(gi);for (int tl = 0; tl < int(arraygroupdata.data.size()); ++tl) {const auto &restrict vars = arraygroupdata.data.at(tl);for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {cctkGH->data[arraygroupdata.firstvarindex + vi][tl] =const_cast<CCTK_REAL *>(&vars.at(vi*arraygroupdata.array_size));}}
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;
} else if (group.grouptype == CCTK_SCALAR) {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;}}} else { // CCTK_ARRAYauto &restrict arraygroupdata = *globaldata.arraygroupdata.at(gi);for (int tl = 0; tl < int(arraygroupdata.data.size()); ++tl) {for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {cctkGH->data[arraygroupdata.firstvarindex + vi][tl] = nullptr;}
}}}} else { // CCTK_ARRAYauto &restrict globaldata = ghext->globaldata;auto &restrict arraygroupdata = *globaldata.arraygroupdata.at(gi);if (!arraygroupdata.do_checkpoint) {// Invalidate all time levelsconst int ntls = arraygroupdata.data.size();for (int tl = 0; tl < ntls; ++tl) {for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {// TODO: handle this more nicelyarraygroupdata.valid.at(tl).at(vi).set_int(false, [] {return "InvalidateTimelevels (invalidate all non-checkpointed ""variables)";});poison_invalid(arraygroupdata, vi, tl);
[&]() { return "CycleTimelevels"; });} else { // CCTK_ARRAYauto &restrict globaldata = ghext->globaldata;auto &restrict arraygroupdata = *globaldata.arraygroupdata.at(gi);const int ntls = arraygroupdata.data.size();// Rotate time levels and invalidate current time levelif (ntls > 1) {rotate(arraygroupdata.data.begin(), arraygroupdata.data.end() - 1,arraygroupdata.data.end());rotate(arraygroupdata.valid.begin(), arraygroupdata.valid.end() - 1,arraygroupdata.valid.end());for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {arraygroupdata.valid.at(0).at(vi).set_int(false, [] {return "CycletimeLevels (invalidate current time level)";});poison_invalid(arraygroupdata, vi, 0);}}for (int tl = 0; tl < ntls; ++tl)for (int vi = 0; vi < arraygroupdata.numvars; ++vi)check_valid(arraygroupdata, vi, tl,
ostringstream buf;buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "<< attribute->where << ": " << attribute->thorn<< "::" << attribute->routine << " checking input";return buf.str();});} else { // CCTK_ARRAYconst auto &restrict arraygroupdata =*ghext->globaldata.arraygroupdata.at(rd.gi);const valid_t &need = rd.valid;error_if_invalid(arraygroupdata, rd.vi, rd.tl, need, [&] {ostringstream buf;buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "<< attribute->where << ": " << attribute->thorn<< "::" << attribute->routine << " checking input";return buf.str();});check_valid(arraygroupdata, rd.vi, rd.tl, [&] {
} else { // CCTK_ARRAYauto &restrict arraygroupdata =*ghext->globaldata.arraygroupdata.at(wr.gi);const valid_t &provided = wr.valid;arraygroupdata.valid.at(wr.tl).at(wr.vi).set_and(need | ~provided,[iteration = cctkGH->cctk_iteration, where = attribute->where,thorn = attribute->thorn, routine = attribute->routine] {ostringstream buf;buf << "CallFunction iteration " << iteration << " " << where<< ": " << thorn << "::" << routine<< ": Poison output variables that are not input variables";return buf.str();});poison_invalid(arraygroupdata, wr.vi, wr.tl);
ostringstream buf;buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "<< attribute->where << ": " << attribute->thorn<< "::" << attribute->routine << " checking output";return buf.str();});} else { // CCTK_ARRAYauto &restrict arraygroupdata =*ghext->globaldata.arraygroupdata.at(wr.gi);const valid_t &provided = wr.valid;arraygroupdata.valid.at(wr.tl).at(wr.vi).set_or(provided,[iteration = cctkGH->cctk_iteration, where = attribute->where,thorn = attribute->thorn, routine = attribute->routine] {ostringstream buf;buf << "CallFunction iteration " << iteration << " " << where<< ": " << thorn << "::" << routine<< ": Mark output variables as valid";return buf.str();});check_valid(arraygroupdata, wr.vi, wr.tl, [&]() {
ostringstream buf;buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "<< attribute->where << ": " << attribute->thorn<< "::" << attribute->routine << " checking output";return buf.str();});} else { // CCTK_ARRAYauto &restrict arraygroupdata =*ghext->globaldata.arraygroupdata.at(inv.gi);const valid_t &provided = inv.valid;arraygroupdata.valid.at(inv.tl).at(inv.vi).set_and(~provided,[iteration = cctkGH->cctk_iteration, where = attribute->where,thorn = attribute->thorn, routine = attribute->routine] {ostringstream buf;buf << "CallFunction iteration " << iteration << " " << where<< ": " << thorn << "::" << routine<< ": Mark invalid variables as invalid";return buf.str();});check_valid(arraygroupdata, inv.vi, inv.tl, [&]() {
void error_if_invalid(const GHExt::GlobalData::ArrayGroupData &groupdata,int vi, int tl, const valid_t &required,const function<string()> &msg);void warn_if_invalid(const GHExt::GlobalData::ArrayGroupData &groupdata,int vi, int tl, const valid_t &required,const function<string()> &msg);void poison_invalid(const GHExt::GlobalData::ArrayGroupData &groupdata, int vi,int tl);void check_valid(const GHExt::GlobalData::ArrayGroupData &groupdata, int vi,int tl, const function<string()> &msg);