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 datatypeint 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 << "}";}