16#include <Kokkos_Core.hpp>
19#include "../synthetic_sdf.hpp"
27double fld(
int c,
int gx,
int gy,
int gz, std::array<int, 3> gd) {
28 const double x = 2.0 * M_PI * gx / gd[0],
y = 2.0 * M_PI * gy / gd[1],
29 z = 2.0 * M_PI * gz / gd[2];
32 return std::sin(x) * std::cos(y) + 0.3 * std::cos(2 * z);
34 return std::cos(x) * std::sin(z) - 0.2 * std::sin(y);
36 return std::sin(y) * std::sin(z) + 0.1 * std::cos(x);
38 return std::cos(x + y) + 0.5 * std::sin(z - x);
40 const double s = 0.5 + 0.5 * std::sin(x + 2 * y - z);
41 return s < 0.02 ? 0.0 :
s;
46bool close(
double a,
double b,
double tol) {
47 return std::fabs(a - b) <= tol;
50int runConfig(
const char* name,
bool withOpen, MPI_Comm comm) {
51 const std::array<int, 3> gd{36, 30, 24};
52 const std::array<float, 3> org{0.5f, -1.0f, 2.0f};
53 const std::array<float, 3> spc{0.5f, 1.0f, 1.5f};
54 const std::array<double, 3> gp{1.0e-3, -2.0e-3, 0.5e-3};
56 MPI_Comm_rank(comm, &rank);
58 std::array<int, 3> bo{}, bs{};
60 const std::size_t nl = std::size_t(bs[0]) * bs[1] * bs[2];
61 std::vector<float> sdfL(nl);
62 std::vector<double> fldL[7];
63 for (
int c = 0; c < 7; ++c)
65 for (
int z = 0;
z < bs[2]; ++
z)
66 for (
int y = 0;
y < bs[1]; ++
y)
67 for (
int x = 0;
x < bs[0]; ++
x) {
68 const std::size_t i = (std::size_t(z) * bs[1] +
y) * bs[0] + x;
69 const int gx = bo[0] +
x, gy = bo[1] +
y, gz = bo[2] +
z;
71 for (
int c = 0; c < 4; ++c)
72 fldL[c][i] = fld(c, gx, gy, gz, gd);
73 for (
int c = 4; c < 7; ++c)
74 fldL[c][i] = fld(4, gx + c, gy, gz, gd);
76 std::vector<double> none;
78 withOpen ? fldL[4] : none, withOpen ? fldL[5] : none,
79 withOpen ? fldL[6] : none, gp, comm);
83 const std::size_t n = std::size_t(gd[0]) * gd[1] * gd[2];
84 std::vector<float> sdfG(n);
85 std::vector<double> fldG[7];
86 for (
int c = 0; c < 7; ++c)
88 for (
int z = 0;
z < gd[2]; ++
z)
89 for (
int y = 0;
y < gd[1]; ++
y)
90 for (
int x = 0;
x < gd[0]; ++
x) {
91 const std::size_t i = (std::size_t(z) * gd[1] +
y) * gd[0] + x;
93 for (
int c = 0; c < 4; ++c)
94 fldG[c][i] = fld(c, x, y, z, gd);
95 for (
int c = 4; c < 7; ++c)
96 fldG[c][i] = fld(4, x + c, y, z, gd);
99 withOpen ? fldG[4] : none, withOpen ? fldG[5] : none,
100 withOpen ? fldG[6] : none, gp);
102 for (
double q : orc.throat_flow)
103 qs = std::max(qs, std::fabs(q));
104 if (dist.throats != orc.throats) {
105 std::printf(
"[%s] FAIL throat list: %zu vs %zu\n", name, dist.throats.size(),
109 for (std::size_t t = 0; t < orc.throats.size() && !fail; ++t) {
110 if (!close(dist.throat_flow[t], orc.throat_flow[t], 1e-10 * qs) ||
111 !close(dist.throat_area[t], orc.throat_area[t], 1e-10 * qs) ||
112 !close(dist.throat_dp[t], orc.throat_dp[t], 1e-8)) {
113 std::printf(
"[%s] FAIL throat %zu: Q %.15e vs %.15e A %.15e vs %.15e dp %g vs %g\n",
114 name, t, dist.throat_flow[t], orc.throat_flow[t], dist.throat_area[t],
115 orc.throat_area[t], dist.throat_dp[t], orc.throat_dp[t]);
120 if (dist.pores.size() != orc.pores.size()) {
121 std::printf(
"[%s] FAIL pore count %zu vs %zu\n", name, dist.pores.size(), orc.pores.size());
124 for (std::size_t k = 0; k < orc.pores.size() && !fail; ++k) {
125 const Pore &a = dist.pores[k], &b = orc.pores[k];
126 if (a.
radius != b.radius || !close(a.
x, b.x, 1e-5 * spc[0]) ||
127 !close(a.
y, b.y, 1e-5 * spc[1]) || !close(a.
z, b.z, 1e-5 * spc[2]) ||
128 !close(dist.pore_pressure[k], orc.pore_pressure[k], 1e-9) ||
129 !close(dist.pore_residual[k], orc.pore_residual[k], 1e-10 * qs)) {
130 std::printf(
"[%s] FAIL pore %zu (r %.9g vs %.9g, p %.15e vs %.15e)\n", name, k, a.
radius,
131 b.radius, dist.pore_pressure[k], orc.pore_pressure[k]);
137 std::printf(
"[%s] PASS: %zu pores, %zu throats match the single-rank oracle\n", name,
138 orc.pores.size(), orc.throats.size());
140 MPI_Bcast(&fail, 1, MPI_INT, 0, comm);
146int main(
int argc,
char** argv) {
147 MPI_Init(&argc, &argv);
150 Kokkos::ScopeGuard kokkos(argc, argv);
151 fail += runConfig(
"openness",
true, MPI_COMM_WORLD);
152 fail += runConfig(
"fully_open",
false, MPI_COMM_WORLD);
float sphereLatticeSdf(int gx, int gy, int gz, std::array< int, 3 > gd)
2x2x2 lattice of SOLID spheres in a periodic box (min-image distance); pores at the interstices.
NetworkFlow extract_network_flow_k(const std::vector< float > &sdf_h, std::array< int, 3 > resolution, std::array< float, 3 > origin, std::array< float, 3 > spacing, const std::vector< double > &u_h, const std::vector< double > &v_h, const std::vector< double > &w_h, const std::vector< double > &p_h, const std::vector< double > &ox_h, const std::vector< double > &oy_h, const std::vector< double > &oz_h, std::array< double, 3 > grad_p)
NetworkFlow extract_network_flow_mpi(const std::vector< float > &sdf_local, std::array< int, 3 > gdims, std::array< float, 3 > origin, std::array< float, 3 > spacing, const std::vector< double > &u_h, const std::vector< double > &v_h, const std::vector< double > &w_h, const std::vector< double > &p_h, const std::vector< double > &ox_h, const std::vector< double > &oy_h, const std::vector< double > &oz_h, std::array< double, 3 > grad_p, MPI_Comm comm)
void mpi_block_of(std::array< int, 3 > gdims, MPI_Comm comm, std::array< int, 3 > &offset, std::array< int, 3 > &size)
This rank's ORB block of the global grid (deterministic; same partition as flow/dem): offset = the bl...
int main(int argc, char **argv)