106static std::vector<double>
gatherGlobal(
const std::vector<double>& local,
int ox,
int oy,
int oz,
107 int lnx,
int lny,
int lnz,
int rank,
int size) {
108 std::vector<double> global;
110 global.assign(
GCELLS, 0.0);
111 for (
int r = 0; r < size; ++r) {
112 int meta[6] = {ox, oy, oz, lnx, lny, lnz};
115 for (
int z = 0; z < lnz; ++z)
116 for (
int y = 0; y < lny; ++y)
117 std::memcpy(&global[(std::size_t)ox + (std::size_t)(y + oy) *
NX +
118 (std::size_t)(z + oz) *
NX *
NY],
119 &local[(std::size_t)y * lnx + (std::size_t)z * lnx * lny],
120 (std::size_t)lnx *
sizeof(
double));
124 MPI_Send(meta, 6, MPI_INT, 0, 100 + r, MPI_COMM_WORLD);
125 MPI_Send(local.data(), (
int)local.size(), MPI_DOUBLE, 0, 200 + r, MPI_COMM_WORLD);
126 }
else if (rank == 0) {
127 MPI_Recv(meta, 6, MPI_INT, r, 100 + r, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
128 std::vector<double> buf((std::size_t)meta[3] * meta[4] * meta[5]);
129 MPI_Recv(buf.data(), (
int)buf.size(), MPI_DOUBLE, r, 200 + r, MPI_COMM_WORLD,
131 for (
int z = 0; z < meta[5]; ++z)
132 for (
int y = 0; y < meta[4]; ++y)
133 std::memcpy(&global[(std::size_t)meta[0] + (std::size_t)(y + meta[1]) *
NX +
134 (std::size_t)(z + meta[2]) *
NX *
NY],
135 &buf[(std::size_t)y * meta[3] + (std::size_t)z * meta[3] * meta[4]],
136 (std::size_t)meta[3] *
sizeof(
double));
162int main(
int argc,
char** argv) {
163 MPI_Init(&argc, &argv);
164 Kokkos::initialize(argc, argv);
167 int rank = 0, size = 1;
168 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
169 MPI_Comm_size(MPI_COMM_WORLD, &size);
171 auto dec = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
NX,
NY,
NZ);
172 auto blk = dec.block(rank);
173 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
174 const int lnx = (int)blk.size[0], lny = (
int)blk.size[1], lnz = (int)blk.size[2];
175 const int gn[3] = {
NX,
NY,
NZ};
176 bool cut[3] = {
false,
false,
false};
177 for (
const auto& sz : dec.sizes())
178 for (
int a = 0; a < 3; ++a)
179 if ((
int)sz[a] != gn[a])
182 std::printf(
"VOF COLLOCATED MPI np=%d grid %dx%dx%d block %dx%dx%d cut axes: %s%s%s\n",
183 size,
NX,
NY,
NZ, lnx, lny, lnz, cut[0] ?
"x" :
"", cut[1] ?
"y" :
"",
186 const Config configs[] = {{
"hydro-z", 1000.0,
true, 20}, {
"vof-z", 10.0,
false, 10}};
188 for (
const Config& c : configs) {
191 if (size > 1 && !cut[2]) {
193 std::printf(
" [%-7s np=%d] FAIL — the decomposition does NOT cut z\n", c.name, size);
197 Colo sd(lnx, lny, lnz);
198 sd.initMpi(dec, MPI_COMM_WORLD);
199 configure(sd, c, ox, oy, oz, lnx, lny, lnz);
200 std::vector<long> itd;
201 for (
int it = 0; it < c.steps; ++it) {
205 std::vector<double> gu[3], gf[3];
206 for (
int comp = 0; comp < 3; ++comp) {
210 const std::vector<double> gp =
212 const std::vector<double> gc =
218 std::vector<long> itr;
219 for (
int it = 0; it < c.steps; ++it) {
221 itr.push_back(ref.lastPressureIterations());
223 double du = 0, df = 0, su = 0, sf = 0;
224 for (
int comp = 0; comp < 3; ++comp) {
225 du = std::fmax(du,
maxAbsDiff(gu[comp], ref.getVelocity(comp)));
226 df = std::fmax(df,
maxAbsDiff(gf[comp], ref.getFaceVelocity(comp)));
230 su = std::fmax(su,
maxAbs(ref.getVelocity(comp)));
231 sf = std::fmax(sf,
maxAbs(ref.getFaceVelocity(comp)));
233 const double dp =
maxAbsDiff(gp, ref.getPressure());
234 const double dc =
maxAbsDiff(gc, ref.getField(
"C"));
235 const double sp =
maxAbs(ref.getPressure());
236 long dit = 0, sumd = 0, sumr = 0, maxd = 0, maxr = 0;
237 for (std::size_t k = 0; k < itd.size(); ++k) {
238 dit = std::max(dit, std::labs(itd[k] - itr[k]));
241 maxd = std::max(maxd, itd[k]);
242 maxr = std::max(maxr, itr[k]);
262 const bool itOk = (size == 1) ? (dit == 0)
263 : (maxd <= maxr + 1 &&
264 std::labs(sumd - sumr) <=
static_cast<long>(itd.size()));
272 const double uRef = std::fmax(su, c.walls ?
GRAV *
DT : 0.0);
273 const double fRef = std::fmax(sf, c.walls ?
GRAV *
DT : 0.0);
274 const double tolU = (size == 1) ? 0.0 : 1e-11 * std::fmax(uRef, 1e-12);
275 const double tolF = (size == 1) ? 0.0 : 1e-11 * std::fmax(fRef, 1e-12);
276 const double tolP = (size == 1) ? 0.0 : 1e-9 * std::fmax(sp, 1e-12);
277 const double tolC = (size == 1) ? 0.0 : 1e-11;
278 const bool ok = du <= tolU && df <= tolF && dp <= tolP && dc <= tolC && itOk;
280 " [%-7s np=%d] du %.3e (|u| %.3e) duf %.3e (|uf| %.3e) dP %.3e (|P| %.3e)"
281 " dC %.3e d(iters) %ld iters max %ld/%ld sum %ld/%ld %s\n",
282 c.name, size, du, su, df, sf, dp, sp, dc, dit, maxd, maxr, sumd, sumr,
283 ok ?
"OK" :
"*** FAIL ***");
286 " face |uf| %.3e (the gated hydrostatic quantity), cell |u| %.3e "
287 "(carries the approximate projection's invisible checkerboard)\n",
288 maxAbs(ref.getFaceVelocity(2)),
maxAbs(ref.getVelocity(2)));
293 std::printf(
" iteration counts (step: np/ref):");
294 for (std::size_t k = 0; k < itd.size(); ++k)
295 if (itd[k] != itr[k])
296 std::printf(
" %zu: %ld/%ld", k, itd[k], itr[k]);
302 MPI_Bcast(&fail, 1, MPI_INT, 0, MPI_COMM_WORLD);
305 std::printf(
"%s\n", fail ?
"FAILED" :
"all collocated VoF MPI gates passed");