6OFN2SJK2MPLZQWYF4RBKSVAZ6BX3LINXR3OXUJED6CWLDTAU7UQC
N3ST2ENQFPLBIKAALNBVNOK4G7Q4TM2RZT4ZOH5ZPOR25MLDBM2QC
D6H2FWRX5NTSSGXL2263KT7DHM3BXQBAYXTNKNJTSMRPD7VEJYHAC
3QWZBYJLGJFSLSL2ZG4JVCSUGF73TQJNPHV3MRMIIBUA7XNUU7NAC
722HZ7UFINNE3YKSYKP2NHZ5XEG5QQLQHSKC7PREJZR3EX6RDYUAC
5B6D6UREX556XOAM75B3WOIGE6DT43HIS6JOVJYNXUT3FSZDUPBAC
ANVJBTFKJDVQBSYMHQ455IQVAOCD3YVYZLDH5K2BS67UTSF5JNBQC
M5R6KQLXLGYSVKHVAX5AJKD6NYE6IM5Z6WVTR3BTKPJDNNKF3ARAC
RCLGQ2LZMFVPBPTU2G55DJ6HZPOGGTPZRZCY54VGP6YLHANJ2LAQC
FS7Q6TUHBK5WSRDC3TM6KV2BPGWATRBLDHFGEJ72BR3FRDEOC3WAC
N42E473LAYAM5NC4UXPM6WD37FLCUM26JCCKCARQEMXM7V6GWYNQC
WASO7G5FJXRXWNH2U2FLUNEKU6VE63OI3HUYP64BVD4LMD6KE7OQC
TPRT57JJWUDQ6C24ZJETKIDWODKWGYDISPYR3B42BNA25UAOVT3AC
67UXOK4QSZFAPVZXU2MJMD7I2232JCK4QDMIOMVMEQNQUGN7632AC
J3SP5HQRWGMM6EM4ZIWPNUIY5HYFRJA4SH2X4OWGESSK7AWA3RNQC
BVR7DVINVPQG7PA6Z7QYVYNQ43YZL7XCC6AOMSMWMGAAB2Q43STAC
JN2TPHENEBIY2OE5FRCQ2E6QCL6FPVHJHUCP4UODD6DITRVV2LIQC
ZARZZPSISIOCXZOWNJQMMQSQPXFSZLDDIDAFY35X2GV37RBB7WUAC
T3TZRPPAIA24I3YL3JFB4XEAYCWU3HJAJUCF7NNIFMP4I5X4SM5QC
EHF2P5PKVTMAUL5R5QSZ3DS3VLE7Z6SHJTCZAGRBTQ66Y7HZKNYQC
UEZKNPXXK5WU6B5LYRKGGYGBZ6T6TAZI26CWTJFUBUW2SJJOMV2AC
LHPZHX4FMRYBM7NI22QTP3VZDBYFRSNTY3L6BEEFPPF5KWCFFIHQC
R5ZPKCVY742K4RWVAJ4O6OGMIYH563GNCSVVSVF2Y66ILIUH7B4AC
WV2J4VRLSW42SGIRDLF326LLC7L2ABAMSZ3YKABS532K27U3X3CAC
IV3MLV677VWS7GLESBQZ4HRFNW5TBFBIGIBWXTCHAER3FQ7VG3GQC
WZPFZTNOJMA2ANRX22OL6QUCU6KUWSZVQJSL46KKBEB37MWRVNNAC
3HPNY5XHNPWR6RVX4LYEVDFJQWSB2CMS7J6XPAKATQ2UPFTXD33QC
XU5HOJREK4XY4NBCJINLZPKQNKSYOLUDTWR47REFSNQKDOSNDXLQC
AUKF4PR4JSOVB2EE3YFXJTH3DK2OY7HXV5AXUWVYHOSAQLY2CYEQC
WNYN6LX3FYXXW3TKGRA7GRLFMIR4YXQMFAWJCB76QAXLY6JR4Q7AC
VMCDMDXKME66ESRMB3PYSUZZH2XG2GIQMEOEKRH33WGCEBPXTWUQC
FYLM4H3VFAC5MR4QQH5Q4LQKVEIIMVAE65BSGS6A7EP6CG47RXFQC
3I2VE3RJ4E4WZZSUGJKOMHP2FKOAZA6SLVMVYE3B54SZCYXGIU4QC
W4XMGPEHBCV6AAPJBI4SSEMCDB6KKCGRUC2X2F5YLBY22OR3ICPAC
BPRNUTY7MHK7LK4EY5MY5OFFG3ABOL7LWXD574L35M74YSQPULFAC
KCIWCVZOHG44WBOLKI2XK33WPHPRI5FWCETF4AOGTPZISKCW3CLQC
RFUF3QUEOYDFA5H5BZJP7HVQ5LMCWCIO7MV32RQBDMVDULGQGO5QC
FEMASUBNU32NSG4DNXZX54CGCA57PVRGYO46L3A6F2EJ4BCSJ3SAC
} 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);
// Set up dynamic data
scalargroupdata.dimension = 0;
scalargroupdata.activetimelevels = 1;
// Allocate data
scalargroupdata.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
// CommonGroupData
poison_invalid(scalargroupdata, vi, tl);
check_valid(scalargroupdata, vi, tl, [] { return "SetupGlobals"; });
}
}
const GHExt::GlobalData::ScalarGroupData &scalargroupdata) {
yaml << YAML::LocalTag("scalargroupdata-1.0.0");
yaml << YAML::BeginMap;
yaml << YAML::Key << "commongroupdata" << YAML::Value
<< (GHExt::CommonGroupData)scalargroupdata;
yaml << YAML::Key << "data" << YAML::Value << scalargroupdata.data;
yaml << YAML::EndMap;
return yaml;
}
YAML::Emitter &
operator<<(YAML::Emitter &yaml,
yaml << YAML::Key << "scalargroupdata" << YAML::Value << YAML::BeginSeq;
for (const auto &scalargroupdata : globaldata.scalargroupdata)
if (scalargroupdata)
yaml << *scalargroupdata;
yaml << YAML::Key << "arraygroupdata" << YAML::Value << YAML::BeginSeq;
for (const auto &arraygroupdata : globaldata.arraygroupdata)
if (arraygroupdata)
yaml << *arraygroupdata;
} 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_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {
file << sep << scalargroupdata.data.at(tl).at(vi);
for (int vi = 0; vi < arraygroupdata.numvars; ++vi) {
file << sep << arraygroupdata.data.at(tl).at(vi);
}
}
// Ensure grid scalars are valid
void error_if_invalid(const GHExt::GlobalData::ScalarGroupData &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 Scalar \"%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::ScalarGroupData &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 Scalar \"%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 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).get();
if (valid.valid_all())
return;
if (!valid.valid_int) {
CCTK_REAL *restrict const ptr =
const_cast<CCTK_REAL *>(&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, const function<string()> &msg) {
DECLARE_CCTK_PARAMETERS;
if (!poison_undefined_values)
return;
const valid_t &valid = scalargroupdata.valid.at(tl).at(vi).get();
if (!valid.valid_any())
return;
// scalars have no boundary so we expect them to alway be valid
assert(valid.valid_outer && valid.valid_ghosts);
atomic<size_t> nan_count{0};
if (valid.valid_int) {
const CCTK_REAL *restrict const ptr = &scalargroupdata.data.at(tl).at(vi);
if (CCTK_BUILTIN_EXPECT(!CCTK_isfinite(*ptr), false)) {
++nan_count;
}
}
if (CCTK_BUILTIN_EXPECT(nan_count > 0, false))
CCTK_VERROR("%s: Grid Scalar \"%s\" has %td nans on time level %d; "
"expected valid %s",
msg().c_str(),
CCTK_FullVarName(scalargroupdata.firstvarindex + vi),
size_t(nan_count), tl,
string(scalargroupdata.valid.at(tl).at(vi)).c_str());
}
// Ensure grid arrays are valid
// Ensure arrays are valid
int dimension = arraygroupdata.dimension;
atomic<size_t> nan_count{0};
if (dimension == 0) {
return;
} else {
const int *gsh = arraygroupdata.gsh;
int n_elems = 1;
for (int i = 0; i < dimension; i++) n_elems *= gsh[i];
if (valid.valid_int) {
CCTK_REAL *restrict const ptr =
const_cast<CCTK_REAL *>(&arraygroupdata.data.at(tl).at(vi));
for (int i = 0; i < n_elems; i++) {
ptr[i] = 0.0 / 0.0;
}
if (!valid.valid_int) {
int dimension = arraygroupdata.dimension;
atomic<size_t> nan_count{0};
CCTK_REAL *restrict const ptr =
const_cast<CCTK_REAL *>(&arraygroupdata.data.at(tl).at(vi));
if (dimension == 0) {
*ptr = 0.0 / 0.0;
} else {
const int *gsh = arraygroupdata.gsh;
int n_elems = 1;
for (int i = 0; i < dimension; i++) n_elems *= gsh[i];
for (int i = 0; i < n_elems; i++) ptr[i] = 0.0 / 0.0;
if (dimension == 0) {
return;
} else {
const int *gsh = arraygroupdata.gsh;
int n_elems = 1;
for (int i = 0; i < dimension; i++) n_elems *= gsh[i];
if (valid.valid_int) {
const CCTK_REAL *restrict const ptr = &arraygroupdata.data.at(tl).at(vi);
if (valid.valid_int) {
const CCTK_REAL *restrict const ptr = &arraygroupdata.data.at(tl).at(vi);
int dimension = arraygroupdata.dimension;
if (dimension == 0) {
if (CCTK_BUILTIN_EXPECT(!CCTK_isfinite(*ptr), false)) {
++nan_count;
}
} else {
const int *gsh = arraygroupdata.gsh;
int n_elems = 1;
for (int i = 0; i < dimension; i++) {
n_elems *= gsh[i];
}
} 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_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
} 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_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
auto &restrict scalargroupdata = *globaldata.scalargroupdata.at(gi);
if (!scalargroupdata.do_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) {
// TODO: handle this more nicely
scalargroupdata.valid.at(tl).at(vi).set_int(false, [] {
return "InvalidateTimelevels (invalidate all non-checkpointed "
"variables)";
});
poison_invalid(scalargroupdata, vi, tl);
}
}
}
} else { // CCTK_ARRAY
auto &restrict globaldata = ghext->globaldata;
} else if (group.grouptype == CCTK_SCALAR) {
auto &restrict globaldata = ghext->globaldata;
auto &restrict scalargroupdata = *globaldata.scalargroupdata.at(gi);
const int ntls = scalargroupdata.data.size();
// Rotate time levels and invalidate current time level
if (ntls > 1) {
rotate(scalargroupdata.data.begin(), scalargroupdata.data.end() - 1,
scalargroupdata.data.end());
rotate(scalargroupdata.valid.begin(), scalargroupdata.valid.end() - 1,
scalargroupdata.valid.end());
for (int vi = 0; vi < scalargroupdata.numvars; ++vi) {
scalargroupdata.valid.at(0).at(vi).set_int(false, [] {
return "CycletimeLevels (invalidate current time level)";
});
poison_invalid(scalargroupdata, vi, 0);
}
}
for (int tl = 0; tl < ntls; ++tl)
for (int vi = 0; vi < scalargroupdata.numvars; ++vi)
check_valid(scalargroupdata, vi, tl,
[&]() { return "CycleTimelevels"; });
} else { // CCTK_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
} else if (CCTK_GroupTypeI(rd.gi) == CCTK_SCALAR) {
const auto &restrict scalargroupdata =
*ghext->globaldata.scalargroupdata.at(rd.gi);
const valid_t &need = rd.valid;
error_if_invalid(scalargroupdata, 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(scalargroupdata, rd.vi, rd.tl, [&] {
ostringstream buf;
buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "
<< attribute->where << ": " << attribute->thorn
<< "::" << attribute->routine << " checking input";
return buf.str();
});
} else { // CCTK_ARRAY
} else if (CCTK_GroupTypeI(wr.gi) == CCTK_SCALAR) {
auto &restrict scalargroupdata =
*ghext->globaldata.scalargroupdata.at(wr.gi);
const valid_t &provided = wr.valid;
scalargroupdata.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(scalargroupdata, wr.vi, wr.tl);
} else { // CCTK_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
} else if (CCTK_GroupTypeI(wr.gi) == CCTK_SCALAR) {
auto &restrict scalargroupdata =
*ghext->globaldata.scalargroupdata.at(wr.gi);
const valid_t &provided = wr.valid;
scalargroupdata.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(scalargroupdata, 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_ARRAY
} else { // CCTK_ARRAY or CCTK_SCALAR
});
} else if (CCTK_GroupTypeI(inv.gi) == CCTK_SCALAR) {
auto &restrict scalargroupdata =
*ghext->globaldata.scalargroupdata.at(inv.gi);
const valid_t &provided = inv.valid;
scalargroupdata.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(scalargroupdata, inv.vi, inv.tl, [&]() {
ostringstream buf;
buf << "CallFunction iteration " << cctkGH->cctk_iteration << " "
<< attribute->where << ": " << attribute->thorn
<< "::" << attribute->routine << " checking output";
return buf.str();
void error_if_invalid(const GHExt::GlobalData::ScalarGroupData &groupdata,
int vi, int tl, const valid_t &required,
const function<string()> &msg);
void warn_if_invalid(const GHExt::GlobalData::ScalarGroupData &groupdata,
int vi, int tl, const valid_t &required,
const function<string()> &msg);
void poison_invalid(const GHExt::GlobalData::ScalarGroupData &groupdata, int vi,
int tl);
void check_valid(const GHExt::GlobalData::ScalarGroupData &groupdata, int vi,
int tl, const function<string()> &msg);