48#include <Kokkos_Core.hpp>
53#include "peclet/core/common/types.hpp"
54#include "peclet/core/decomp/block_decomposer.hpp"
56using peclet::core::IVec;
59static constexpr int NX = 16,
NY = 32,
NZ = 8;
62static constexpr double FZ = 1e-2;
76static double srcAt(
int,
int y,
int) {
77 return std::cos(2.0 *
M_PI * y /
NY);
82 std::vector<double> v((std::size_t)
lnx *
lny *
lnz);
83 for (
int z = 0; z <
lnz; ++z)
84 for (
int y = 0; y <
lny; ++y)
85 for (
int x = 0; x <
lnx; ++x)
86 v[(std::size_t)x + (std::size_t)y *
lnx + (std::size_t)z *
lnx *
lny] =
87 f(x + ox, y + oy, z + oz);
105 s.
setField(
"mu",
blockOf([&](
int x,
int y,
int z) {
return muAt(c, x, y, z); }, ox, oy, oz,
lnx,
123static std::vector<double>
gatherGlobal(
const std::vector<double>&
local,
int ox,
int oy,
int oz,
124 int lnx,
int lny,
int lnz,
int rank,
int size) {
125 std::vector<double>
global;
128 for (
int r = 0; r < size; ++r) {
132 for (
int z = 0; z <
lnz; ++z)
133 for (
int y = 0; y <
lny; ++y)
134 std::memcpy(&
global[(std::size_t)ox + (std::size_t)(y + oy) *
NX +
135 (std::size_t)(z + oz) *
NX *
NY],
137 (std::size_t)
lnx *
sizeof(
double));
143 }
else if (rank == 0) {
148 for (
int z = 0; z <
meta[5]; ++z)
149 for (
int y = 0; y <
meta[4]; ++y)
150 std::memcpy(&
global[(std::size_t)
meta[0] + (std::size_t)(y +
meta[1]) *
NX +
151 (std::size_t)(z +
meta[2]) *
NX *
NY],
153 (std::size_t)
meta[3] *
sizeof(
double));
159static double maxAbsDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
164 for (std::size_t i = 0; i < b.size(); ++i) {
165 const double d = std::fabs(a[i] - b[i]);
172static double maxAbs(
const std::vector<double>& a) {
175 m = std::fmax(m, std::fabs(v));
182 const double tau =
ULID / (0.5 /
MU1 + 0.5 /
MU2);
184 return tau * yc /
MU1;
185 return tau * 0.5 /
MU1 + tau * (yc - 0.5) /
MU2;
189 for (
int y = 0; y <
NY; ++y) {
190 const std::size_t i =
191 (std::size_t)(
NX / 2) + (std::size_t)y *
NX + (std::size_t)(
NZ / 2) *
NX *
NY;
199 Kokkos::initialize(
argc, argv);
202 int rank = 0, size = 1;
206 auto dec = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
NX,
NY,
NZ);
207 auto blk =
dec.block(rank);
208 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
209 const int lnx = (int)blk.size[0],
lny = (
int)blk.size[1],
lnz = (int)blk.size[2];
210 const int gn[3] = {
NX,
NY,
NZ};
211 bool cut[3] = {
false,
false,
false};
212 for (
const auto& sz :
dec.sizes())
213 for (
int a = 0; a < 3; ++a)
214 if ((
int)sz[a] != gn[a])
217 std::printf(
"VARMU MPI np=%d grid %dx%dx%d block %dx%dx%d cut axes: %s%s%s\n", size,
NX,
218 NY,
NZ,
lnx,
lny,
lnz, cut[0] ?
"x" :
"", cut[1] ?
"y" :
"", cut[2] ?
"z" :
"");
225 if (size > 1 && !cut[1]) {
228 " [%-9s np=%d] FAIL — the decomposition does NOT cut the walled y axis; "
229 "this test exists to gate the domain-BC / property-ghost rank ownership on "
230 "a CUT walled axis (WO-F)\n",
238 for (
int it = 0; it < c.steps; ++it)
240 std::vector<double>
gu[3];
241 for (
int comp = 0; comp < 3; ++comp)
245 const std::vector<double>
gp =
251 for (
int it = 0; it < c.steps; ++it)
253 double du = 0,
umag = 0;
254 for (
int comp = 0; comp < 3; ++comp) {
255 du = std::fmax(du,
maxAbsDiff(
gu[comp], ref.getVelocity(comp)));
258 const double rel = du / (
umag + 1e-300);
260 const double pmag =
maxAbs(ref.getPressure());
267 const double utol = (size == 1) ? 0.0 : std::fmax(1e-15, 1e-11 *
umag);
268 const double ptol = (size == 1) ? 0.0 : std::fmax(1e-14, 1e-11 *
pmag);
273 ok = ok &&
aerr < 5e-3;
277 std::snprintf(
extra,
sizeof(
extra),
" analytic err=%.4f%%",
aerr * 100.0);
279 " [%-9s np=%d] du=%.3e (rel %.2e, tol %.1e) | dp=%.3e (|P|=%.2e, tol %.1e)"
288 std::printf(
"VARMU MPI (np=%d): %s\n", size,
fail ?
"FAIL" :
"PASS");
void setDomainBc(int face, int type, double vx, double vy, double vz)
void setPropertyMode(bool variable, bool harmonic)
CCField addField(const std::string &name)
void exchangeField(const std::string &name)
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 setVelocityIterations(int it)
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 setPressurePcg(bool on, int maxit, double rtol)
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 std::vector< double > blockOf(Fn f, int ox, int oy, int oz, int lnx, int lny, int lnz)
static constexpr double FZ
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 double muAt(const Config &, int, int y, int)
static double couetteError(const std::vector< double > &u)
static double srcAt(int, int y, int)
static constexpr double RHO
static constexpr double MU1
static double maxAbsDiff(const std::vector< double > &a, const std::vector< double > &b)
static constexpr int STEPS_PERY
static constexpr double DT
static constexpr double ULID
static double couetteExact(double yc)
static constexpr int STEPS_COUETTE
static constexpr std::size_t GCELLS
static constexpr double MU2
static void configure(IbmSolver &s, const Config &c, int ox, int oy, int oz, int lnx, int lny, int lnz)