105static void compare(
const char* tag,
int n,
const std::vector<double>& gsdf,
FlowSetup flow,
106 ScalarSetup scalar,
Solve solve,
bool checkLevels =
false,
bool gated =
true,
107 bool cutcellPressure =
false,
Post post =
nullptr,
108 double identityBound = 1e-12) {
109 peclet::core::decomp::BlockDecomposer<3> dec =
110 peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(
size_), n, n, n);
111 const auto blk = dec.block(
rank_);
112 Block B{{(int)blk.origin[0], (
int)blk.origin[1], (int)blk.origin[2]},
113 {(int)blk.size[0], (
int)blk.size[1], (int)blk.size[2]}};
114 std::vector<double> lsdf((std::size_t)B.l[0] * B.l[1] * B.l[2]);
115 for (
int z = 0; z < B.l[2]; ++z)
116 for (
int y = 0; y < B.l[1]; ++y)
117 for (
int x = 0; x < B.l[0]; ++x)
118 lsdf[(std::size_t)x + (std::size_t)y * B.l[0] + (std::size_t)z * B.l[0] * B.l[1]] =
119 gsdf[(std::size_t)(x + B.o[0]) + (std::size_t)(y + B.o[1]) * n +
120 (std::size_t)(z + B.o[2]) * n * n];
123 sd.initMpi(n, n, n, MPI_COMM_WORLD);
129 scalar(sr,
Block{{0, 0, 0}, {n, n, n}});
134 const Run D = solve(sd);
135 const Run R = solve(sr);
136 auto cd = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), sd.
scalarField(
"c").
c);
137 auto cr = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), sr.
scalarField(
"c").
c);
138 const long dsy = B.l[0] + 2 *
G, dsz = dsy * (B.l[1] + 2 *
G), rsy = n + 2 *
G,
139 rsz = rsy * (n + 2 *
G);
140 double maxDiff = 0.0, maxRef = 0.0;
142 for (
int z = 0; z < B.l[2]; ++z)
143 for (
int y = 0; y < B.l[1]; ++y)
144 for (
int x = 0; x < B.l[0]; ++x) {
145 const double a = cd((x +
G) + (y +
G) * dsy + (z +
G) * dsz);
146 const double b = cr((x + B.o[0] +
G) + (y + B.o[1] +
G) * rsy + (z + B.o[2] +
G) * rsz);
148 maxRef = std::fmax(maxRef, std::fabs(b));
149 notSame +=
same(a, b) ? 0 : 1;
151 double g[2] = {
maxDiff, maxRef}, gg[2];
152 MPI_Allreduce(g, gg, 2, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
154 MPI_Allreduce(¬Same, &ns, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
158 "[%s%s] np=%d: max|c - c_1| = %.2e (max|c_1| %.3f), %ld cells not bitwise; "
159 "mg levels np %d single %d\n",
160 tag, gated ?
"" :
" @ default rtol 1e-10, information only",
size_, gg[0], gg[1], ns, lvD,
162 std::printf(
" iterations np:");
163 for (
int it : D.iters)
164 std::printf(
" %d", it);
165 std::printf(
" single:");
166 for (
int it : R.iters)
167 std::printf(
" %d", it);
168 std::printf(
"\n wall flux np: %.15e single: %.15e\n", D.flux.back(), R.flux.back());
170 for (std::size_t k = 0; k < D.identity.size(); ++k)
171 idm = std::fmax(idm, std::fmax(std::fabs(D.identity[k]), std::fabs(R.identity[k])));
172 std::printf(
" budget identity (rel) <= %.1e\n", idm);
178 CHECK(D.iters.size() == R.iters.size());
179 for (std::size_t k = 0; k < D.identity.size(); ++k) {
180 CHECK(std::fabs(D.identity[k]) <= identityBound);
181 CHECK(std::fabs(R.identity[k]) <= identityBound);
185 for (std::size_t k = 0; k < D.iters.size(); ++k)
186 CHECK(D.iters[k] == R.iters[k]);
187 for (std::size_t k = 0; k < D.flux.size(); ++k)
190 CHECK(gg[0] <= 1e-10 * gg[1]);
191 for (std::size_t k = 0; k < D.iters.size(); ++k)
192 CHECK(std::abs(D.iters[k] - R.iters[k]) <= 1);
193 for (std::size_t k = 0; k < D.flux.size(); ++k)
194 CHECK(std::fabs(D.flux[k] - R.flux[k]) <= 1e-10 * std::fabs(R.flux[k]));
200 const double w[3] = {1.0, 1.0, 1.0}, hp[3] = {1.0, 1.0, 1.0};
202 vmg.initMpi(dec, 64, MPI_COMM_WORLD);
203 bool eq = vmg.
levels() == mg.levels();
204 for (
int L = 0; eq && L < mg.levels(); ++L) {
205 const auto& a = vmg.
level(L);
206 const auto& b = mg.level(L);
207 eq = a.inner.x == b.inner.x && a.inner.y == b.inner.y && a.inner.z == b.inner.z &&
208 a.ratio.x == b.ratio.x && a.ratio.y == b.ratio.y && a.ratio.z == b.ratio.z &&
209 a.og.x == b.og.x && a.og.y == b.og.y && a.og.z == b.og.z;
211 int all = eq ? 1 : 0, allMin = 0;
212 MPI_Allreduce(&all, &allMin, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
214 std::printf(
" level table: %d levels, %s VelocityMG::initMpi\n", mg.levels(),
215 allMin ?
"==" :
"DIFFERS from");
220int main(
int argc,
char** argv) {
221 MPI_Init(&argc, &argv);
222 MPI_Comm_rank(MPI_COMM_WORLD, &
rank_);
223 MPI_Comm_size(MPI_COMM_WORLD, &
size_);
224 Kokkos::initialize(argc, argv);
229 auto profile = [](
int y,
int z) {
return 0.4 + 0.1 * std::sin(0.3 * y) * std::cos(0.2 * z); };
236 s.setDomainBc(0, 1, 0.0, 0.0, 0.0);
237 s.setDomainBc(1, 1, 0.0, 0.0, 0.0);
240 s.addScalar(
"c", 1.2, 1, 50,
true);
241 s.setScalarBc(
"c", 0, 2, 0.15);
242 std::vector<double>
prof((std::size_t)B.l[1] * B.l[2]);
243 for (
int z = 0; z < B.l[2]; ++z)
244 for (
int y = 0; y < B.l[1]; ++y)
245 prof[(std::size_t)y + (std::size_t)z * B.l[1]] = profile(y + B.o[1], z + B.o[2]);
246 s.setScalarBcProfile(
"c", 1,
prof, B.l[1], B.l[2]);
250 s.setScalarWall(
"c", 1, 1.0, 0.0, -1);
251 s.solveScalarSteady(
"c");
253 s.setScalarWall(
"c", 2, 0.3, 0.7, -1);
254 s.setScalarSource(
"c", 0.1);
255 for (
int k = 0; k < 3; ++k) {
266 const double R = 16.0, c0[3] = {31.87, 32.21, 31.66};
267 for (
const bool gated : {
true,
false})
274 for (
int f = 0; f < 6; ++f)
275 s.setDomainBc(f, 1, 0.0, 0.0, 0.0);
278 s.addScalar(
"c", 0.7, 1, 50,
true);
279 for (
int f = 0; f < 6; ++f) {
281 const int t1 = (a == 0) ? 1 : 0, t2 = (a == 2) ? 1 : 2;
282 const double xa = (f % 2 == 0) ? -0.5 :
N - 0.5;
283 std::vector<double>
prof((std::size_t)B.l[t1] * B.l[t2]);
284 for (
int j2 = 0; j2 < B.l[t2]; ++j2)
285 for (
int j1 = 0; j1 < B.l[t1]; ++j1) {
288 p[t1] = j1 + B.o[t1];
289 p[t2] = j2 + B.o[t2];
290 const double r = std::sqrt((p[0] - c0[0]) * (p[0] - c0[0]) +
291 (p[1] - c0[1]) * (p[1] - c0[1]) +
292 (p[2] - c0[2]) * (p[2] - c0[2]));
293 prof[(std::size_t)j1 + (std::size_t)j2 * B.l[t1]] = R / r;
295 s.setScalarBc(
"c", f, 2, 0.0);
296 s.setScalarBcProfile(
"c", f,
prof, B.l[t1], B.l[t2]);
298 s.setScalarWall(
"c", 1, 1.0, 0.0, -1);
302 s.solveScalarSteady(
"c");
312 "singular",
N,
sphereSdf(
N, 15.3, 16.1, 14.7, 9.3),
319 s.addScalar(
"c", 0.9, 1, 50,
true);
320 s.setScalarWall(
"c", 0, 0.4, 0.0, -1);
321 s.setScalarSource(
"c", -0.05);
325 s.solveScalarSteady(
"c");
326 r.iters.push_back(s.scalarField(
"c").cut->iterations);
327 r.flux.push_back(s.scalarWallFlux(
"c")[0]);
328 CHECK(s.scalarField(
"c").cut->singular);
340 const double cx = 17.78, cy = 18.13, Ri = 6.4, Ro = 16.0, Om = 0.5 / (std::sqrt(2.0) * Ro);
341 std::vector<double> gsdf((std::size_t)
N *
N *
N);
342 for (
int z = 0; z <
N; ++z)
343 for (
int y = 0; y <
N; ++y)
344 for (
int x = 0; x <
N; ++x) {
345 const double r = std::hypot(x - cx, y - cy);
346 gsdf[(std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N] =
347 std::fmin(r - Ri, Ro - r);
356 std::vector<double> vx((std::size_t)
N *
N *
N), vy((std::size_t)
N *
N *
N);
360 g.setSolid(gsdf,
true);
361 const std::vector<double> ox = g.getOpennessProj(0), oy = g.getOpennessProj(1);
362 auto I = [&](
int x,
int y) {
363 return (std::size_t)((x +
N) %
N) + (std::size_t)((y +
N) %
N) *
N;
365 std::vector<double> P((std::size_t)
N *
N);
366 for (
int y = 0; y <
N; ++y)
367 for (
int x = 0; x <
N; ++x) {
368 const double r = std::hypot(x - 0.5 - cx, y - 0.5 - cy);
369 const double rc = std::fmin(std::fmax(r, Ri), Ro);
370 const double wall = r < 0.5 * (Ri + Ro) ? Ri : Ro;
371 const bool mark = !(ox[I(x, y)] > 0.0) || !(ox[I(x, y - 1)] > 0.0) ||
372 !(oy[I(x, y)] > 0.0) || !(oy[I(x - 1, y)] > 0.0);
373 P[I(x, y)] = -0.5 * Om * (mark ? wall * wall : rc * rc);
375 for (
int z = 0; z <
N; ++z)
376 for (
int y = 0; y <
N; ++y)
377 for (
int x = 0; x <
N; ++x) {
378 const std::size_t k = (std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N;
379 const double fx = P[I(x, y + 1)] - P[I(x, y)], fy = -(P[I(x + 1, y)] - P[I(x, y)]);
380 vx[k] = ox[k] > 0.0 ? fx / ox[k] : 0.0;
381 vy[k] = oy[k] > 0.0 ? fy / oy[k] : 0.0;
385 "g9",
N, gsdf, flowG9,
387 s.addScalar(
"c", 0.0, 1, 50,
true);
388 const std::size_t nl = (std::size_t)B.l[0] * B.l[1] * B.l[2];
389 std::vector<double> u(nl), v(nl), w(nl, 0.0), c(nl);
390 for (
int z = 0; z < B.l[2]; ++z)
391 for (
int y = 0; y < B.l[1]; ++y)
392 for (
int x = 0; x < B.l[0]; ++x) {
393 const std::size_t l =
394 (std::size_t)x + (std::size_t)y * B.l[0] + (std::size_t)z * B.l[0] * B.l[1];
395 const int gx = x + B.o[0], gy = y + B.o[1], gz = z + B.o[2];
396 const std::size_t k =
397 (std::size_t)gx + (std::size_t)gy *
N + (std::size_t)gz *
N *
N;
400 const double dx = gx - cx - 0.7 * Ro, dy = gy - cy, sg = 0.08 * Ro;
401 c[l] = gsdf[k] > 0.0 ? std::exp(-(dx * dx + dy * dy) / (2.0 * sg * sg)) : 0.0;
410 for (
int k = 0; k < 50; ++k) {
412 const auto& st = *s.scalarField(
"c").cut;
413 r.iters.push_back(st.iterations);
415 r.flux.push_back((
double)st.numSmall + 1e4 * (double)st.numImplicitFaces);
416 const auto b = s.scalarBudget(
"c");
417 r.identity.push_back(b.identityError / b.mass);
419 const auto& st = *s.scalarField(
"c").cut;
421 std::printf(
" [g9] C_bulk %.3f, small cells %ld, implicit faces %ld of %ld\n",
422 st.bulkCourant, st.numSmall, st.numImplicitFaces, st.numFluxFaces);
423 CHECK(st.numSmall > 0 && st.numImplicitFaces > 0);
438 std::vector<double> gsdf((std::size_t)
N *
N *
N);
439 for (
int z = 0; z <
N; ++z)
440 for (
int y = 0; y <
N; ++y)
441 for (
int x = 0; x <
N; ++x) {
442 const double a = std::sqrt((x - 13.3) * (x - 13.3) + (y - 17.1) * (y - 17.1) +
443 (z - 11.4) * (z - 11.4)) -
445 const double b = std::sqrt((x - 15.6) * (x - 15.6) + (y - 16.5) * (y - 16.5) +
446 (z - 34.6) * (z - 34.6)) -
448 gsdf[(std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N] = std::fmin(a, b);
454 for (
int f = 0; f < 4; ++f)
455 s.setDomainBc(f, 1, 0.0, 0.0, 0.0);
456 s.setDomainBc(4, 2, 0.0, 0.0, 1.0);
457 s.setDomainBc(5, 3, 0.0, 0.0, 0.0);
461 "g9c",
N, gsdf, flowG9c,
463 s.addScalar(
"c", 0.3, 0, 50,
true);
464 for (
int f = 0; f < 4; ++f)
465 s.setScalarBc(
"c", f, 1, 0.0);
466 s.setScalarBc(
"c", 4, 2, 1.0);
467 s.setScalarBc(
"c", 5, 1, 0.0);
468 const std::vector<double> unk = s.scalarGeometryField(4);
469 std::vector<double> c(unk.size());
470 for (std::size_t k = 0; k < c.size(); ++k)
471 c[k] = unk[k] > 0.5 ? 0.2 : 0.0;
476 const bool ref = call++ == 1;
478 long outletSmall = 0, small = 0, impl = 0;
479 for (
int k = 0; k < 30; ++k) {
481 const auto& st = *s.scalarField(
"c").cut;
482 small = std::max(small, st.numSmall);
483 impl = std::max(impl, st.numImplicitFaces);
484 r.iters.push_back(st.iterations);
485 r.flux.push_back((
double)st.numSmall + 1e4 * (
double)st.numImplicitFaces);
486 const auto b = s.scalarBudget(
"c");
487 r.identity.push_back(b.identityError / b.mass);
489 auto h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), st.small);
490 const int lx = s.nx(), ly = s.ny(), lz = s.nz();
491 const long sy = lx + 2 *
G, sz = sy * (ly + 2 *
G);
492 for (
int y = 0; y < ly; ++y)
493 for (
int x = 0; x < lx; ++x)
494 outletSmall += h((x +
G) + (y +
G) * sy + (lz - 1 +
G) * sz) > 0.5 ? 1 : 0;
498 " [g9c %s] small cells <= %ld (in the outlet layer, summed over the "
499 "steps, rank 0: %ld), implicit faces <= %ld\n",
500 ref ?
"single" :
"np", small, outletSmall, impl);
501 CHECK(small > 0 && impl > 0);
503 CHECK(outletSmall > 0);
515 const std::vector<double> gsdf =
sphereSdf(
N, 31.87, 31.28, 32.11, 16.0);
522 s.addScalar(
"c", 0.7, 1, 50,
true);
523 s.setScalarWall(
"c", 1, 1.0, 0.0, -1);
524 s.setScalarSource(
"c", -0.3);
526 std::vector<double> gv[3];
527 const char* nm[3] = {
"u",
"v",
"w"};
531 g.setSolid(gsdf,
true);
532 g.setBodyForce(1e-3, 4e-4, 2e-4);
533 for (
int k = 0; k < 20; ++k)
536 g.solveScalarSteady(
"c");
537 const double k = 1.0 / g.scalarField(
"c").cut->maxCellPeclet;
538 for (
int a = 0; a < 3; ++a) {
539 gv[a] = g.getField(nm[a]);
540 for (
double& v : gv[a])
545 "steady_adv",
N, gsdf, flowAdv,
547 const std::size_t nl = (std::size_t)B.l[0] * B.l[1] * B.l[2];
548 for (
int a = 0; a < 3; ++a) {
549 std::vector<double> f(nl);
550 for (
int z = 0; z < B.l[2]; ++z)
551 for (
int y = 0; y < B.l[1]; ++y)
552 for (
int x = 0; x < B.l[0]; ++x)
553 f[(std::size_t)x + (std::size_t)y * B.l[0] + (std::size_t)z * B.l[0] * B.l[1]] =
554 gv[a][(std::size_t)(x + B.o[0]) + (std::size_t)(y + B.o[1]) *
N +
555 (std::size_t)(z + B.o[2]) *
N *
N];
556 s.setField(nm[a], f);
562 s.solveScalarSteady(
"c");
567 const auto b = s.scalarBudget(
"c");
568 r.identity.back() = b.identityError / (std::fabs(b.wallIn) + std::fabs(b.sourceIn) +
569 std::fabs(b.boundaryIn));
570 const auto& st = *s.scalarField(
"c").cut;
572 std::printf(
" [steady_adv] census max_cell_peclet %.6g, %d levels, %d iterations\n",
573 st.maxCellPeclet, st.mgLevels, st.iterations);
574 CHECK(st.advecting && st.steady && std::fabs(st.maxCellPeclet - 1.0) <= 1e-12);
583 const std::vector<double> unk = s.scalarGeometryField(4);
584 std::vector<double> rv(unk.size());
585 for (
int z = 0; z < b.l[2]; ++z)
586 for (
int y = 0; y < b.l[1]; ++y)
587 for (
int x = 0; x < b.l[0]; ++x) {
588 const std::size_t l =
589 (std::size_t)x + (std::size_t)y * b.l[0] + (std::size_t)z * b.l[0] * b.l[1];
591 (double)((x + b.o[0]) + (y + b.o[1]) *
N + (
long)(z + b.o[2]) *
N *
N);
592 rv[l] = unk[l] > 0.5 ? std::sin(0.37 * gk) * (1.0 + 0.2 * std::cos(1e-3 * gk))
595 auto& sc = s.scalarField(
"c");
597 const std::size_t n = sc.c.extent(0);
599 Kokkos::deep_copy(r, sc.c);
600 sc.cut->mg->apply(z, r);
601 return Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), z);
603 const auto zd = zOf(sd, B);
604 const auto zr = zOf(sr,
Block{{0, 0, 0}, {
N,
N,
N}});
605 const long dsy = B.l[0] + 2 *
G, dsz = dsy * (B.l[1] + 2 *
G), rsy =
N + 2 *
G,
606 rsz = rsy * (
N + 2 *
G);
607 long notSame = 0, cells = 0;
608 for (
int z = 0; z < B.l[2]; ++z)
609 for (
int y = 0; y < B.l[1]; ++y)
610 for (
int x = 0; x < B.l[0]; ++x) {
611 const double a = zd((x +
G) + (y +
G) * dsy + (z +
G) * dsz);
613 zr((x + B.o[0] +
G) + (y + B.o[1] +
G) * rsy + (z + B.o[2] +
G) * rsz);
614 notSame +=
same(a, b) ? 0 : 1;
617 long t[2] = {notSame, cells}, tt[2];
618 MPI_Allreduce(t, tt, 2, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
621 " [steady_adv] advective V-cycle z = M^-1 r: %ld of %ld cells not "
622 "bitwise vs single rank\n",
624 CHECK(tt[0] == 0 && tt[1] == (
long)
N *
N *
N);
634 const double R = 16.0, D = 0.7,
U = 10.0 * D / R, cx = 19.83, cy = 20.27;
635 std::vector<double> gsdf((std::size_t)
N *
N *
N);
636 for (
int z = 0; z <
N; ++z)
637 for (
int y = 0; y <
N; ++y)
638 for (
int x = 0; x <
N; ++x)
639 gsdf[(std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N] =
640 R - std::sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
647 for (
int f = 0; f < 4; ++f)
648 s.setDomainBc(f, 1, 0.0, 0.0, 0.0);
651 std::vector<double> w((std::size_t)B.l[0] * B.l[1] * B.l[2]);
652 for (
int z = 0; z < B.l[2]; ++z)
653 for (
int y = 0; y < B.l[1]; ++y)
654 for (
int x = 0; x < B.l[0]; ++x) {
655 const double dx = x + B.o[0] - cx, dy = y + B.o[1] - cy;
656 w[(std::size_t)x + (std::size_t)y * B.l[0] + (std::size_t)z * B.l[0] * B.l[1]] =
657 std::fmax(2.0 *
U * (1.0 - (dx * dx + dy * dy) / (R * R)), 0.0);
660 s.addScalar(
"c", D, 1, 50,
true);
661 for (
int f = 0; f < 4; ++f)
662 s.setScalarBc(
"c", f, 1, 0.0);
663 s.setScalarMeanGradient(
"c", {0.0, 0.0, 1.0});
667 s.solveScalarSteady(
"c");
668 r.iters.push_back(s.scalarField(
"c").cut->iterations);
670 r.flux.push_back(s.scalarMeanFlux(
"c")[2]);
674 auto& sc = s.scalarField(
"c");
675 auto hb = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), sc.b);
676 const int ext[3] = {s.nx() + 2 *
G, s.ny() + 2 *
G, s.nz() + 2 *
G};
678 for (
int z =
G; z < ext[2] -
G; ++z)
679 for (
int y =
G; y < ext[1] -
G; ++y)
680 for (
int x =
G; x < ext[0] -
G; ++x)
681 g += std::fabs(hb(x + (
long)y * ext[0] + (
long)z * ext[0] * ext[1]));
683 MPI_Allreduce(&g, &gg, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
684 r.identity.push_back(s.scalarBudget(
"c").identityError / gg);
685 const auto& st = *sc.cut;
688 " [g8] census max_cell_peclet %.6g, singular %d, %d levels, %d iterations, "
689 "mean flux z %.15e\n",
690 st.maxCellPeclet, (
int)st.singular, st.mgLevels, st.iterations, r.flux.back());
691 CHECK(st.advecting && st.steady && st.singular && st.meanGradOn);
694 false,
true,
true,
nullptr, 1e-11);
703 const double R = 8.0, Ro = 16.0, c0[3] = {19.83, 20.17, 19.71};
704 const double mu = 2.6588142379399775 / (R * R);
705 std::vector<int> ni = {1, -1, -1, 3, -1, -1, 1, -1, -1, 34, 1, 2};
706 std::vector<double> nr(4 * 16, 0.0);
707 for (
int k = 0; k < 4; ++k) {
708 nr[16 * k + 14] = 1.0;
709 nr[16 * k + 15] = 1.0;
712 nr[16 + 0] = nr[16 + 1] = nr[16 + 2] = 1e3;
714 std::vector<int> ii = {0, -1, 3, -1};
715 std::vector<double> ir(2 * 18, 0.0);
716 for (
int k = 0; k < 2; ++k) {
717 for (
int d = 0; d < 3; ++d)
718 ir[18 * k + d] = c0[d];
719 ir[18 * k + 6] = 1.0;
720 ir[18 * k + 7] = 1.0;
722 peclet::core::decomp::BlockDecomposer<3> dec =
723 peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(
size_),
N,
N,
N);
724 const auto blk = dec.block(
rank_);
725 const Block B{{(int)blk.origin[0], (
int)blk.origin[1], (int)blk.origin[2]},
726 {(int)blk.size[0], (
int)blk.size[1], (int)blk.size[2]}};
731 for (
int f = 0; f < 6; ++f)
732 s.setDomainBc(f, 1, 0.0, 0.0, 0.0);
734 s.initMpi(
N,
N,
N, MPI_COMM_WORLD);
735 s.setScene(ni, nr, ii, ir,
false);
736 s.setSolidFromScene(
false);
737 s.addScalar(
"c", 1.0, 1, 50,
true);
738 for (
int f = 0; f < 6; ++f)
739 s.setScalarBc(
"c", f, 1, 0.0);
740 s.setScalarWall(
"c", 1, 0.0, 0.0, 1);
741 s.setScalarSolid(
"c", 10.0, 1.0, 1.0, 0.0, 0);
742 s.setScalarTolerance(
"c", 1e-13);
744 for (
const char* nm : {
"c",
"c_solid"}) {
745 auto f = s.fieldView(nm);
746 auto h = Kokkos::create_mirror_view(f);
747 const long sy = b.l[0] + 2 *
G, sz = sy * (b.l[1] + 2 *
G);
748 for (
int z = 0; z < b.l[2]; ++z)
749 for (
int y = 0; y < b.l[1]; ++y)
750 for (
int x = 0; x < b.l[0]; ++x) {
751 const double dx = x + b.o[0] - c0[0], dy = y + b.o[1] - c0[1],
752 dz = z + b.o[2] - c0[2];
753 h((x +
G) + (y +
G) * sy + (z +
G) * sz) =
754 1.0 - (dx * dx + dy * dy + dz * dz) / (Ro * Ro);
756 Kokkos::deep_copy(f, h);
762 build(sr,
Block{{0, 0, 0}, {
N,
N,
N}},
false);
763 std::vector<int> itD, itR;
764 std::vector<double> fxD, fxR, idD, idR;
765 for (
int k = 0; k < 20; ++k) {
766 for (
int w = 0; w < 2; ++w) {
769 const auto fl = s.scalarWallFlux(
"c");
770 const auto bu = s.scalarBudget(
"c");
771 (w == 0 ? itD : itR).push_back(s.scalarField(
"c").cut->iterations);
772 (w == 0 ? fxD : fxR).push_back(fl[0]);
773 (w == 0 ? fxD : fxR).push_back(fl[1]);
774 (w == 0 ? idD : idR).push_back(bu.identityError / std::fabs(bu.dMass));
777 double gg[4] = {0, 0, 0, 0};
779 for (
int ph = 0; ph < 2; ++ph) {
780 const char* nm = ph == 0 ?
"c" :
"c_solid";
781 auto cd = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), sd.
fieldView(nm));
782 auto cr = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), sr.
fieldView(nm));
783 const long dsy = B.l[0] + 2 *
G, dsz = dsy * (B.l[1] + 2 *
G), rsy =
N + 2 *
G,
784 rsz = rsy * (
N + 2 *
G);
785 double md = 0.0, mr = 0.0;
787 for (
int z = 0; z < B.l[2]; ++z)
788 for (
int y = 0; y < B.l[1]; ++y)
789 for (
int x = 0; x < B.l[0]; ++x) {
790 const double a = cd((x +
G) + (y +
G) * dsy + (z +
G) * dsz);
792 cr((x + B.o[0] +
G) + (y + B.o[1] +
G) * rsy + (z + B.o[2] +
G) * rsz);
793 md = std::fmax(md, std::fabs(a - b));
794 mr = std::fmax(mr, std::fabs(b));
795 nsl +=
same(a, b) ? 0 : 1;
797 double g2[2] = {md, mr}, o2[2];
798 MPI_Allreduce(g2, o2, 2, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
800 gg[2 * ph + 1] = o2[1];
802 MPI_Allreduce(&nsl, &o, 1, MPI_LONG, MPI_SUM, MPI_COMM_WORLD);
806 for (std::size_t k = 0; k < idD.size(); ++k)
807 idm = std::fmax(idm, std::fmax(std::fabs(idD[k]), std::fabs(idR[k])));
811 "[g6 case 1] np=%d: max|c - c_1| = %.2e (max %.3f), max|psi_s - psi_s1| = %.2e "
812 "(max %.3f), %ld cells not bitwise; %ld solid unknowns, %d levels\n",
813 size_, gg[0], gg[1], gg[2], gg[3], ns, st.numSolidUnknowns, st.mgLevels);
814 std::printf(
" iterations np:");
816 std::printf(
" %d", it);
817 std::printf(
" single:");
819 std::printf(
" %d", it);
820 std::printf(
"\n last fluxes np: %.15e %.15e single: %.15e %.15e\n", fxD[fxD.size() - 2],
821 fxD.back(), fxR[fxR.size() - 2], fxR.back());
822 std::printf(
" budget identity (rel to |d_mass|) <= %.1e\n", idm);
824 CHECK(st.conj && st.numSolidUnknowns > 0);
825 CHECK(itD.size() == itR.size());
829 for (std::size_t k = 0; k < itD.size(); ++k)
830 CHECK(itD[k] == itR[k]);
831 for (std::size_t k = 0; k < fxD.size(); ++k)
834 CHECK(gg[0] <= 1e-10 * gg[1]);
835 CHECK(gg[2] <= 1e-10 * gg[3]);
836 for (std::size_t k = 0; k < itD.size(); ++k)
837 CHECK(std::abs(itD[k] - itR[k]) <= 1);
838 for (std::size_t k = 0; k < fxD.size(); ++k)
839 CHECK(std::fabs(fxD[k] - fxR[k]) <= 1e-10 * std::fmax(std::fabs(fxR[k]), 1e-300));
845 MPI_Allreduce(&
failures, &all, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
847 std::printf(all ?
"%d failure(s)\n" :
"OK\n", all);