I4P6OKQG6OD3JX2KV23QLKMG7DSNYMTYUZCIOKNPTHOFHOFLMSNAC
BJDGFYBMECTJG7BHLNHLSCUCBVYHAY6OGY37FIJP6JDGNDXQNQVAC
5XGIB7XMEZNBLA5ZLQTXRTC3AZ5CTRGMXWBPVMWXG4DPHKWDF4ZAC
VAF66DTVLDWNG7N2PEQYEH4OH5SPSMFBXKPR2PU67IIM6CVPCJ7AC
YIQN7NJTGEVKW7JZHL6CTH6EPCIXCNBYNURIGXPYZAOUX3VAJQMAC
KG47IF4CPCUT3BHS34WDRHTH5HYMBTY4OSTB3X7APR2E5ZJ32IYQC
FEMASUBNU32NSG4DNXZX54CGCA57PVRGYO46L3A6F2EJ4BCSJ3SAC
BPRNUTY7MHK7LK4EY5MY5OFFG3ABOL7LWXD574L35M74YSQPULFAC
JD6PQOJ6YYNQYEEWEXO2NM7NVYNBUI6V7ZU6Q3FNHGAT2VYOF5WAC
template <typename T> MPI_Datatype reduction_mpi_datatype() {
static MPI_Datatype datatype = MPI_DATATYPE_NULL;
if (datatype == MPI_DATATYPE_NULL) {
MPI_Type_contiguous(sizeof(reduction<T>) / sizeof(T),
mpi_datatype<T>::value, &datatype);
char name[MPI_MAX_OBJECT_NAME];
int namelen;
MPI_Type_get_name(mpi_datatype<T>::value, name, &namelen);
ostringstream buf;
buf << "reduction<" << name << ">";
string newname = buf.str();
MPI_Type_set_name(datatype, newname.c_str());
MPI_Type_commit(&datatype);
}
return datatype;
}
if (*datatype == MPI_FLOAT)
return mpi_reduce_typed<float>(x, y, length);
if (*datatype == MPI_DOUBLE)
return mpi_reduce_typed<double>(x, y, length);
if (*datatype == MPI_LONG_DOUBLE)
return mpi_reduce_typed<long double>(x, y, length);
// Analyze MPI datatype
int num_integers, num_addresses, num_datatypes, combiner;
MPI_Type_get_envelope(*datatype, &num_integers, &num_addresses,
&num_datatypes, &combiner);
assert(combiner == MPI_COMBINER_CONTIGUOUS);
assert(num_integers == 1);
assert(num_addresses = 1);
assert(num_datatypes == 1);
vector<int> integers(num_integers);
vector<MPI_Aint> addresses(num_addresses);
vector<MPI_Datatype> datatypes(num_datatypes);
MPI_Type_get_contents(*datatype, num_integers, num_addresses, num_datatypes,
integers.data(), addresses.data(), datatypes.data());
MPI_Datatype inner_datatype = datatypes.at(0);
if (inner_datatype == MPI_FLOAT)
return mpi_reduce_typed<reduction<float> >(x, y, length);
if (inner_datatype == MPI_DOUBLE)
return mpi_reduce_typed<reduction<double> >(x, y, length);
if (inner_datatype == MPI_LONG_DOUBLE)
return mpi_reduce_typed<reduction<long double> >(x, y, length);
reduction<T> reduce_array(const Geometry &geom,
const GHExt::LevelData::GroupData &groupdata,
const GridPtrDesc1 &grid, const GF3D1<const T> ptr_,
const Array4<const int> *restrict finemask_array4) {
const CCTK_REAL *restrict dx = geom.CellSize();
CCTK_REAL dV = 1.0;
for (int d = 0; d < dim; ++d)
dV *= dx[d];
reduction<T> reduce_array(const Array4<const T> &restrict vars, int n,
const array<int, dim> &imin,
const array<int, dim> &imax,
const Array4<const int> *restrict finemask, T dV) {
grid.loop_idx(
where_t::interior, groupdata.indextype, [&](const Loop::PointDesc &p) {
if (!finemask_array4 || !(*finemask_array4)(grid.cactus_offset.x + p.i,
grid.cactus_offset.y + p.j,
grid.cactus_offset.z + p.k))
red = reduction<T>(red, reduction<T>(dV, ptr_(p.I)));
});
for (int k = imin[2]; k < imax[2]; ++k) {
for (int j = imin[1]; j < imax[1]; ++j) {
// #pragma omp simd reduction(red : reduction_CCTK_REAL)
for (int i = imin[0]; i < imax[0]; ++i) {
bool is_masked = finemask && (*finemask)(i, j, k);
if (!is_masked)
red += reduction<T>(dV, vars(i, j, k, n));
}
}
}
for (MFIter mfi(*leveldata.mfab0, mfitinfo); mfi.isValid(); ++mfi) {
GridPtrDesc1 grid(leveldata, groupdata, mfi);
unique_ptr<Array4<const int> > finemask_array4;
if (finemask)
finemask_array4 = make_unique<Array4<const int> >(finemask->array(mfi));
for (MFIter mfi(mfab, mfitinfo); mfi.isValid(); ++mfi) {
const Box &bx = mfi.tilebox(); // current region (without ghosts)
const array<int, dim> imin{bx.smallEnd(0), bx.smallEnd(1),
bx.smallEnd(2)};
const array<int, dim> imax{bx.bigEnd(0) + 1, bx.bigEnd(1) + 1,
bx.bigEnd(2) + 1};
const GF3D1<const CCTK_REAL> ptr_ = grid.gf3d(vars, vi);
red += reduce_array(geom, groupdata, grid, ptr_, finemask_array4.get());
unique_ptr<Array4<const int> > finemask;
if (finemask_imfab)
finemask = make_unique<Array4<const int> >(finemask_imfab->array(mfi));
red += reduce_array(vars, vi, imin, imax, finemask.get(), dV);
template <typename T> struct mpi_datatype;
template <> struct mpi_datatype<float> {
static constexpr MPI_Datatype value = MPI_FLOAT;
};
template <> struct mpi_datatype<double> {
static constexpr MPI_Datatype value = MPI_DOUBLE;
};
template <> struct mpi_datatype<long double> {
static constexpr MPI_Datatype value = MPI_LONG_DOUBLE;
};
friend ostream &operator<<(ostream &os, const reduction &red) {
return os << "reduction{min:" << red.min << ",max:" << red.max
<< ",sum:" << red.sum << ",sum2:" << red.sum2
<< ",vol:" << red.vol << ",maxabs:" << red.maxabs
<< ",sumabs:" << red.sumabs << ",sum2abs:" << red.sum2abs << "}";
}