USPPNUMNL5HU5WEOIWJMIFAX6TBZERVAV67XJUJQ6KSNLG55JAGQC
FS7Q6TUHBK5WSRDC3TM6KV2BPGWATRBLDHFGEJ72BR3FRDEOC3WAC
X7A7HYGU2NPWCZCG5SYFD4NINYDP6UYWFFE3WP6YNLSDIABG2KJAC
IV3MLV677VWS7GLESBQZ4HRFNW5TBFBIGIBWXTCHAER3FQ7VG3GQC
BSMJ4V7GV3EOGY4KCSTOJQUOFE2OOCIKQETE4WC2WRNLWBQIBW3QC
BVR7DVINVPQG7PA6Z7QYVYNQ43YZL7XCC6AOMSMWMGAAB2Q43STAC
YIQN7NJTGEVKW7JZHL6CTH6EPCIXCNBYNURIGXPYZAOUX3VAJQMAC
2DKSL6DKZAIYQUJGDULORCKU5K4Z5Z3W4RIKQYDSLKMCNQNDZFBAC
KG47IF4CPCUT3BHS34WDRHTH5HYMBTY4OSTB3X7APR2E5ZJ32IYQC
W4XMGPEHBCV6AAPJBI4SSEMCDB6KKCGRUC2X2F5YLBY22OR3ICPAC
KCIWCVZOHG44WBOLKI2XK33WPHPRI5FWCETF4AOGTPZISKCW3CLQC
BPRNUTY7MHK7LK4EY5MY5OFFG3ABOL7LWXD574L35M74YSQPULFAC
GQVQJCNQNO2KD7ZMC7RESCUAMUAP7OED6CTA6SYLZKQGXKXZ6T3QC
LSOYKV2LJ6WOBTNCW43WXV47RIQEBNZFEJJZM5QA7XDZF4D2PANQC
UTHNLH3J3VG7BBJPOKGE6DY7Z2QHDLY72TR2VMEDQYP73SIWZGKAC
BJDGFYBMECTJG7BHLNHLSCUCBVYHAY6OGY37FIJP6JDGNDXQNQVAC
struct tiletag_t {
int level;
Box tilebox;
int gi, vi, tl;
tiletag_t() = delete;
friend bool operator==(const tiletag_t &x, const tiletag_t &y) {
return make_tuple(x.level, x.tilebox, x.gi, x.vi, x.tl) ==
make_tuple(y.level, y.tilebox, y.gi, y.vi, y.tl);
}
friend bool operator<(const tiletag_t &x, const tiletag_t &y) {
return make_tuple(x.level, x.tilebox, x.gi, x.vi, x.tl) <
make_tuple(y.level, y.tilebox, y.gi, y.vi, y.tl);
}
friend ostream &operator<<(ostream &os, const tiletag_t &x) {
return os << "tiletag_t{"
<< "level:" << x.level << ","
<< "tilebox:" << x.tilebox << ","
<< "gi:" << x.gi << ","
<< "vi:" << x.vi << ","
<< "tl:" << x.tl << "}";
}
operator string() const {
ostringstream buf;
buf << *this;
return buf.str();
}
};
struct checksum_t {
valid_t where;
uLong crc;
checksum_t() = default;
inline checksum_t(const valid_t &where)
: where(where), crc(crc32_z(0, nullptr, 0)) {}
template <typename T> inline void add(const T &x) {
crc =
crc32_z(crc, static_cast<const Bytef *>(static_cast<const void *>(&x)),
sizeof x);
}
friend bool operator==(const checksum_t &x, const checksum_t &y) {
return x.where == y.where && x.crc == y.crc;
}
friend bool operator!=(const checksum_t &x, const checksum_t &y) {
return !(x == y);
}
friend ostream &operator<<(ostream &os, const checksum_t &x) {
return os << "checksum_t{where:" << x.where << ",crc:0x" << hex
<< setfill('0') << setw(8) << x.crc << "}";
}
operator string() const {
ostringstream buf;
buf << *this;
return buf.str();
}
};
typedef map<tiletag_t, checksum_t> checksums_t;
checksums_t
calculate_checksums(const vector<vector<vector<valid_t> > > &will_write,
const int min_level, const int max_level) {
DECLARE_CCTK_PARAMETERS;
checksums_t checksums;
if (!poison_undefined_values)
return checksums;
for (int level = min_level; level < max_level; ++level) {
auto &restrict leveldata = ghext->leveldata.at(level);
auto mfitinfo = MFItInfo().SetDynamic(true).EnableTiling(
{max_tile_size_x, max_tile_size_y, max_tile_size_z});
#pragma omp parallel
for (MFIter mfi(*leveldata.mfab0, mfitinfo); mfi.isValid(); ++mfi) {
for (const auto &groupdataptr : leveldata.groupdata) {
auto &restrict groupdata = *groupdataptr;
const GridPtrDesc1 grid(leveldata, groupdata, mfi);
for (int vi = 0; vi < groupdata.numvars; ++vi) {
for (int tl = 0; tl < int(groupdata.valid.size()); ++tl) {
const tiletag_t tiletag{level, mfi.tilebox(), groupdata.groupindex,
vi, tl};
const auto &valid = groupdata.valid.at(tl).at(vi);
const auto &wr = will_write.at(groupdata.groupindex).at(vi).at(tl);
valid_t to_check = valid & ~wr;
// Check only those variables which are valid, and where
// some part (but not everything) is written
if (!(wr.any() && to_check.any()))
continue;
const Array4<const CCTK_REAL> &vars =
groupdata.mfab.at(tl)->array(mfi);
const GF3D1<const CCTK_REAL> var_ = grid.gf3d(vars, vi);
checksum_t checksum(to_check);
checksum.add(tiletag);
const auto add_point{
[&](const Loop::PointDesc &p) { checksum.add(var_(p.I)); }};
if (to_check.valid_int)
grid.loop_idx(where_t::interior, groupdata.indextype,
groupdata.nghostzones, add_point);
if (to_check.valid_outer)
grid.loop_idx(where_t::boundary, groupdata.indextype,
groupdata.nghostzones, add_point);
if (to_check.valid_ghosts)
grid.loop_idx(where_t::ghosts, groupdata.indextype,
groupdata.nghostzones, add_point);
#pragma omp critical
checksums[tiletag] = checksum;
}
}
}
}
}
return checksums;
}
void check_checksums(const checksums_t checksums, const int min_level,
const int max_level) {
DECLARE_CCTK_PARAMETERS;
if (!poison_undefined_values)
return;
if (checksums.empty())
return;
for (int level = min_level; level < max_level; ++level) {
auto &restrict leveldata = ghext->leveldata.at(level);
auto mfitinfo = MFItInfo().SetDynamic(true).EnableTiling(
{max_tile_size_x, max_tile_size_y, max_tile_size_z});
#pragma omp parallel
for (MFIter mfi(*leveldata.mfab0, mfitinfo); mfi.isValid(); ++mfi) {
for (const auto &groupdataptr : leveldata.groupdata) {
auto &restrict groupdata = *groupdataptr;
const GridPtrDesc1 grid(leveldata, groupdata, mfi);
for (int vi = 0; vi < groupdata.numvars; ++vi) {
for (int tl = 0; tl < int(groupdata.valid.size()); ++tl) {
const tiletag_t tiletag{level, mfi.tilebox(), groupdata.groupindex,
vi, tl};
if (!checksums.count(tiletag))
continue;
const auto &old_checksum = checksums.at(tiletag);
const auto &did_check = old_checksum.where;
assert(did_check.any());
const Array4<const CCTK_REAL> &vars =
groupdata.mfab.at(tl)->array(mfi);
const GF3D1<const CCTK_REAL> var_ = grid.gf3d(vars, vi);
checksum_t checksum(did_check);
checksum.add(tiletag);
const auto add_point{
[&](const Loop::PointDesc &p) { checksum.add(var_(p.I)); }};
if (did_check.valid_int)
grid.loop_idx(where_t::interior, groupdata.indextype,
groupdata.nghostzones, add_point);
if (did_check.valid_outer)
grid.loop_idx(where_t::boundary, groupdata.indextype,
groupdata.nghostzones, add_point);
if (did_check.valid_ghosts)
grid.loop_idx(where_t::ghosts, groupdata.indextype,
groupdata.nghostzones, add_point);
if (checksum != old_checksum)
CCTK_VERROR(
"Checksum mismatch: variable %s, tile %s, old checksum %s, "
"new checksum %s",
CCTK_FullVarName(groupdata.firstvarindex + tiletag.vi),
string(tiletag).c_str(), string(old_checksum).c_str(),
string(checksum).c_str());
}
}
}
}
}
}
CCTK_VERROR(
"Found invalid input data: iteration %d %s: %s::%s, level %d, "
"variable %s%s: need %s, have %s",
cctkGH->cctk_iteration, attribute->where, attribute->thorn,
attribute->routine, leveldata.level,
CCTK_FullVarName(groupdata.firstvarindex + rd.vi),
string("_p", rd.tl).c_str(), string(need).c_str(),
string(have).c_str());
CCTK_VERROR("Found invalid input data: iteration %d %s: %s::%s, "
"level %d, "
"variable %s%s: need %s, have %s",
cctkGH->cctk_iteration, attribute->where,
attribute->thorn, attribute->routine, leveldata.level,
CCTK_FullVarName(groupdata.firstvarindex + rd.vi),
string("_p", rd.tl).c_str(), string(need).c_str(),
string(have).c_str());
uLong crc = crc32_z(0, nullptr, 0);
for (int level = min_level; level < max_level; ++level) {
auto &restrict leveldata = ghext->leveldata.at(level);
auto mfitinfo = MFItInfo().SetDynamic(true).EnableTiling(
{max_tile_size_x, max_tile_size_y, max_tile_size_z});
for (MFIter mfi(*leveldata.mfab0, mfitinfo); mfi.isValid(); ++mfi) {
for (const auto &groupdataptr : leveldata.groupdata) {
auto &restrict groupdata = *groupdataptr;
const GridPtrDesc1 grid(leveldata, groupdata, mfi);
for (int vi = 0; vi < groupdata.numvars; ++vi) {
for (int tl = 0; tl < int(groupdata.valid.size()); ++tl) {
const auto &gf = gfs.at(groupdata.groupindex).at(vi).at(tl);
// Check only those variables where some part is written
if (gf.any()) {
const Array4<const CCTK_REAL> &vars =
groupdata.mfab.at(tl)->array(mfi);
const GF3D1<const CCTK_REAL> var_ = grid.gf3d(vars, vi);
const auto addcrc{[&](const Loop::PointDesc &p) {
crc = crc32_z(crc,
static_cast<const Bytef *>(
static_cast<const void *>(&var_(p.I))),
sizeof var_(p.I));
}};
if (!gf.valid_int)
grid.loop_idx(where_t::interior, groupdata.indextype,
groupdata.nghostzones, addcrc);
if (!gf.valid_outer)
grid.loop_idx(where_t::boundary, groupdata.indextype,
groupdata.nghostzones, addcrc);
if (!gf.valid_ghosts)
grid.loop_idx(where_t::ghosts, groupdata.indextype,
groupdata.nghostzones, addcrc);
}
}
}
}
}
}
CCTK_VINFO("CRC-32: 0x%08lx", (unsigned long)crc);
checksums = calculate_checksums(gfs, min_level, max_level);