flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_velocitymg_mpi.cpp
Go to the documentation of this file.
1// cfd-gpu — the PRODUCTION VelocityMG (staircase velocity multigrid), multi-rank.
2//
3// Folds the distributed halo into the real velocity-MG (gated behind PECLET_FLOW_MPI). VelocityMG
4// has NO global reductions (the backward-Euler velocity operator is non-singular -> no mean
5// removal, and the V-cycle is a fixed iteration, not a Krylov method), so the fold is purely
6// fill()->per-level halo exchange + the block- origin red-black parity -- and the distributed
7// V-cycle is therefore BIT-tight to the single-rank one (no Allreduce reordering at all). Solves an
8// all-fluid periodic backward-Euler diffusion (fine stencil = idiag*I - beta*Lap; staircase coarse
9// op with theta=1, no pin, full clean-fluid mask) distributed (initMpi) vs single-rank (init() on
10// the full grid). Build with -DCFD_MPI.
11#include <mpi.h>
12
13#include <cmath>
14#include <cstdio>
15#include <Kokkos_Core.hpp>
16
17#include "mac_velocity_mg.hpp"
18#include "peclet/core/common/types.hpp"
19#include "peclet/core/decomp/block_decomposer.hpp"
20#include "peclet/core/halo/grid_halo_topology.hpp"
21
22using peclet::core::IVec;
29
30static constexpr int G = 2, NLEV = 4, NVCYC = 6;
31static constexpr double IDIAG = 1.0, BETA = 0.2;
32static double source(int gx, int gy, int gz, IVec<3> gs) {
33 return std::sin(2.0 * M_PI * gx / gs[0]) +
34 std::cos(4.0 * M_PI * gy / gs[1]) * std::sin(2.0 * M_PI * gz / gs[2]);
35}
36
37static void fillSource(CCField b, C3 ext, C3 og, IVec<3> gs) {
38 auto hb = Kokkos::create_mirror_view(b);
39 for (std::size_t c = 0; c < b.extent(0); ++c)
40 hb(c) = 0.0;
41 for (int z = G; z < ext.z - G; ++z)
42 for (int y = G; y < ext.y - G; ++y)
43 for (int x = G; x < ext.x - G; ++x)
44 hb((long)x + (long)y * ext.x + (long)z * (long)ext.x * ext.y) =
45 source(x - G + og.x, y - G + og.y, z - G + og.z, gs);
46 Kokkos::deep_copy(b, hb);
47}
48
49int main(int argc, char** argv) {
50 MPI_Init(&argc, &argv);
51 Kokkos::initialize(argc, argv);
52 int fail = 0, size = 1, rank = 0;
53 {
54 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
55 MPI_Comm_size(MPI_COMM_WORLD, &size);
56 IVec<3> gs{32, 32, 32};
57
58 auto setupAndSolve = [&](VelocityMG& vmg, C3 ext, C3 og) {
59 const std::size_t n = (std::size_t)ext.x * ext.y * ext.z;
60 // fine stencil = backward-Euler diffusion (idiag+6beta diagonal, -beta off-diagonals)
61 FPV AC("AC", n), AW("AW", n), AE("AE", n), AS("AS", n), AN("AN", n), AB("AB", n), AT("AT", n);
62 Kokkos::deep_copy(AC, (float)(IDIAG + 6.0 * BETA));
63 for (FPV* p : {&AW, &AE, &AS, &AN, &AB, &AT})
64 Kokkos::deep_copy(*p, (float)(-BETA));
65 vmg.setFineStencil(FPC(AC), FPC(AW), FPC(AE), FPC(AS), FPC(AN), FPC(AB), FPC(AT));
66 // all-fluid geometry: theta=1, no solid pin, full clean-fluid mask
67 CCField th("th", n), solid("solid", n), clean("clean", n);
68 Kokkos::deep_copy(th, 1.0);
69 Kokkos::deep_copy(solid, 0.0);
70 Kokkos::deep_copy(clean, 1.0);
71 vmg.setStaircase(CCConst(th), CCConst(solid), CCConst(clean), BETA, IDIAG, 0.5);
72 CCField b("b", n), x("x", n);
73 fillSource(b, ext, og, gs);
74 Kokkos::deep_copy(x, 0.0);
75 vmg.solve(CCConst(b), x, NVCYC, 2, 2, 8);
76 auto hx = Kokkos::create_mirror_view(x);
77 Kokkos::deep_copy(hx, x);
78 return hx;
79 };
80
81 VelocityMG vmg;
82 vmg.initMpi(gs[0], gs[1], gs[2], NLEV, MPI_COMM_WORLD);
83 VelocityMG::Level& l0 = vmg.level(0);
84 auto hx = setupAndSolve(vmg, l0.ext, l0.og);
85
86 VelocityMG ref;
87 ref.init(gs[0], gs[1], gs[2], NLEV);
88 const C3 re{(int)gs[0] + 2 * G, (int)gs[1] + 2 * G, (int)gs[2] + 2 * G}, ro{0, 0, 0};
89 auto hr = setupAndSolve(ref, re, ro);
90
91 double maxdiff = 0.0;
92 for (int z = G; z < l0.ext.z - G; ++z)
93 for (int y = G; y < l0.ext.y - G; ++y)
94 for (int x = G; x < l0.ext.x - G; ++x) {
95 const int gx = x - G + l0.og.x, gy = y - G + l0.og.y, gz = z - G + l0.og.z;
96 const double a = hx((long)x + (long)y * l0.ext.x + (long)z * (long)l0.ext.x * l0.ext.y);
97 const double rr =
98 hr((long)(gx + G) + (long)(gy + G) * re.x + (long)(gz + G) * (long)re.x * re.y);
99 const double d = std::fabs(a - rr);
100 if (d > maxdiff)
101 maxdiff = d;
102 }
103 if (maxdiff > 1e-11) {
104 ++fail;
105 std::fprintf(stderr, "[rank %d] max|distributed - single-rank VelocityMG| = %.3e\n", rank,
106 maxdiff);
107 } else if (rank == 0)
108 std::printf(" max|distributed - single-rank| = %.3e (np=%d)\n", maxdiff, size);
109 }
110 int totalFail = 0;
111 MPI_Allreduce(&fail, &totalFail, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
112 if (rank == 0) {
113 if (totalFail == 0)
114 std::printf("OK (np=%d): production VelocityMG V-cycle distributed == single-rank\n", size);
115 else
116 std::fprintf(stderr, "FAILED (np=%d): %d ranks differ\n", size, totalFail);
117 }
118 Kokkos::finalize();
119 MPI_Finalize();
120 return totalFail == 0 ? 0 : 1;
121}
void setFineStencil(FPC AC, FPC AW, FPC AE, FPC AS, FPC AN, FPC AB, FPC AT)
void solve(CCConst b, CCField x, int nvc, int pre, int post, int bottom)
void setStaircase(CCConst theta0, CCConst solid0, CCConst resmask0, double nu_dt, double idiag, double thresh)
flow — portable (Kokkos) velocity (momentum) multigrid for the IBM diffusion solve: the STAIRCASE coa...
Kokkos::View< const MReal *, CCMem > FPC
Kokkos::View< double *, CCMem > CCField
Kokkos::View< MReal *, CCMem > FPV
Kokkos::View< const double *, CCMem > CCConst
static constexpr double AC
static constexpr int NVCYC
int main(int argc, char **argv)
static constexpr double IDIAG
static void fillSource(CCField b, C3 ext, C3 og, IVec< 3 > gs)
static double source(int gx, int gy, int gz, IVec< 3 > gs)
static constexpr int G
static constexpr int NLEV
static constexpr double BETA