52#include <Kokkos_Core.hpp>
56#include "peclet/core/common/types.hpp"
57#include "peclet/core/decomp/block_decomposer.hpp"
74 static const char* fn[3] = {
"force_x",
"force_y",
"force_z"};
87 c.walls ? std::vector<double>{0.0, -GRAV} : std::vector<double>{
FORCE, 0.0});
95static std::vector<double>
gatherGlobal(
const std::vector<double>&
local,
int ox,
int oy,
int oz,
96 int lnx,
int lny,
int lnz,
int rank,
int size) {
97 std::vector<double>
global;
100 for (
int r = 0; r < size; ++r) {
104 for (
int z = 0; z <
lnz; ++z)
105 for (
int y = 0; y <
lny; ++y)
106 std::memcpy(&
global[(std::size_t)ox + (std::size_t)(y + oy) *
NX +
107 (std::size_t)(z + oz) *
NX *
NY],
109 (std::size_t)
lnx *
sizeof(
double));
115 }
else if (rank == 0) {
120 for (
int z = 0; z <
meta[5]; ++z)
121 for (
int y = 0; y <
meta[4]; ++y)
122 std::memcpy(&
global[(std::size_t)
meta[0] + (std::size_t)(y +
meta[1]) *
NX +
123 (std::size_t)(z +
meta[2]) *
NX *
NY],
125 (std::size_t)
meta[3] *
sizeof(
double));
131static double maxAbsDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
136 for (std::size_t i = 0; i < b.size(); ++i) {
137 const double d = std::fabs(a[i] - b[i]);
144static double maxAbs(
const std::vector<double>& a) {
147 m = std::fmax(m, std::fabs(v));
157 for (
int z = 1; z <
NZ; ++z) {
158 const std::size_t i0 =
159 (std::size_t)(
NX / 2) + (std::size_t)(
NY / 2) *
NX + (std::size_t)(z - 1) *
NX *
NY;
172 Kokkos::initialize(
argc, argv);
175 int rank = 0, size = 1;
179 auto dec = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
NX,
NY,
NZ);
180 auto blk =
dec.block(rank);
181 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
182 const int lnx = (int)blk.size[0],
lny = (
int)blk.size[1],
lnz = (int)blk.size[2];
183 const int gn[3] = {
NX,
NY,
NZ};
184 bool cut[3] = {
false,
false,
false};
185 for (
const auto& sz :
dec.sizes())
186 for (
int a = 0; a < 3; ++a)
187 if ((
int)sz[a] != gn[a])
190 std::printf(
"BODYFORCE-GHOST MPI np=%d grid %dx%dx%d block %dx%dx%d cut axes: %s%s%s\n",
198 {
"per-x", 0,
false,
false,
false},
199 {
"walls-z", 2,
true,
true,
true}};
202 if (c.needCut && size > 1 && !cut[c.comp]) {
205 " [%-7s np=%d] FAIL — the decomposition does NOT cut the forced axis %d; "
206 "this test exists to gate the force ghost ACROSS a rank boundary (WO-G)\n",
207 c.name, size, c.comp);
214 for (
int it = 0; it <
STEPS; ++it)
217 std::vector<double>
gu[3];
218 for (
int comp = 0; comp < 3; ++comp)
220 const std::vector<double>
gp =
226 for (
int it = 0; it <
STEPS; ++it)
228 double du = 0,
umag = 0;
229 for (
int comp = 0; comp < 3; ++comp) {
230 du = std::fmax(du,
maxAbsDiff(
gu[comp], ref.getVelocity(comp)));
234 const double pmag =
maxAbs(ref.getPressure());
235 const double utol = (size == 1) ? 0.0 : std::fmax(1e-15, 1e-11 *
umag);
236 const double ptol = (size == 1) ? 0.0 : std::fmax(1e-12, 1e-11 *
pmag);
239 char extra[160] =
"";
242 const std::vector<double>&
uf =
gu[c.comp];
243 double lo =
uf[0], hi =
uf[0];
244 for (
double v :
uf) {
245 lo = std::fmin(lo, v);
246 hi = std::fmax(hi, v);
249 const double spread = hi - lo,
verr = std::fabs(0.5 * (hi + lo) - want) / want;
252 for (
int comp = 0; comp < 3; ++comp)
255 ok = ok &&
spread <= 1e-13 * want &&
verr <= 1e-13 &&
cross <= 1e-13 * want;
257 " | u_f spread=%.3e (want 0) value=%.17g (want %.17g) cross=%.2e",
spread,
258 0.5 * (hi + lo), want,
cross);
263 ok = ok && umax < 1e-13 && perr < 1e-11;
264 std::snprintf(
extra,
sizeof(
extra),
" | max|u|=%.2e dP/dz err=%.3e (worst plane z=%d)",
267 std::printf(
" [%-7s np=%d] du=%.3e dp=%.3e (tol %.1e/%.1e)%s %s\n", c.name, size, du, dp,
275 std::printf(
"BODYFORCE-GHOST MPI (np=%d): %s\n", size,
fail ?
"FAIL" :
"PASS");
void setDomainBc(int face, int type, double vx, double vy, double vz)
void setAdvection(bool on)
void setPropertyModel(const std::string &target, ClosureKind kind, const std::string &in0, const std::string &in1, const std::vector< double > ¶ms)
void setPressureGeometry(const std::vector< double > &sdfInner)
void setField(const std::string &name, const std::vector< double > &v)
std::vector< double > getVelocity(int c)
void setDensityMode(bool variable)
void setMu(double m)
Dynamic viscosity, in the caller's units.
void setRho(double r)
Fluid density, in the caller's units.
std::vector< double > getPressure()
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
static double maxAbs(const std::vector< double > &a)
static constexpr double GRAV
static constexpr double RHO0
static std::vector< double > gatherGlobal(const std::vector< double > &local, int ox, int oy, int oz, int lnx, int lny, int lnz, int rank, int size)
static constexpr double FORCE
static constexpr int STEPS
static double maxAbsDiff(const std::vector< double > &a, const std::vector< double > &b)
static constexpr double DT
static void configure(IbmSolver &s, const Config &c, int lnx, int lny, int lnz)
static constexpr std::size_t GCELLS
static double pressureGradientError(const std::vector< double > &p, int *worstPlane)
static int worstPlane(const std::vector< double > &u, int axis)