79#include <Kokkos_Core.hpp>
83#include "peclet/core/common/types.hpp"
84#include "peclet/core/decomp/block_decomposer.hpp"
85#include "peclet/core/geom/scene_builder.hpp"
89static constexpr int N = 48,
STEPS = 60;
90static constexpr std::size_t
GCELLS = (std::size_t)
N *
N *
N;
91static constexpr double DIAM = 8.0;
92static constexpr double U = 0.05;
93static constexpr double RE = 20.0;
95static constexpr double RHO = 1.0;
96static constexpr double DT = 4.0;
97static constexpr double OFF = 0.3;
106 const char* v = std::getenv(
"GATE7_SHIFT");
107 return v ? std::atof(v) : 0.0;
118 std::vector<double>&
ir) {
119 namespace g = peclet::core::geom;
120 ni.assign(g::kNodeIntStride, 0);
121 nr.assign(g::kNodeRealStride, 0.0);
128 ii.assign(g::kInstanceIntStride, 0);
129 ir.assign(g::kInstanceRealStride, 0.0);
140 const char* v = std::getenv(k);
141 return !v || std::atoi(v) != 0;
153 std::vector<int>
ni,
ii;
154 std::vector<double>
nr,
ir;
158 const double m =
envOn(
"GATE7_MOVE") ? 1.0 : 0.0;
167 const double m =
envOn(
"GATE7_MOVE") ? 1.0 : 0.0;
168 const double x =
X0() + m *
DIRX *
U *
DT * it;
169 const double y =
Y0() + m *
DIRY *
U *
DT * it;
177static std::vector<double>
gatherGlobal(
const std::vector<double>&
local,
int ox,
int oy,
int oz,
178 int lnx,
int lny,
int lnz,
int rank,
int size) {
179 std::vector<double>
global;
182 for (
int r = 0; r < size; ++r) {
186 for (
int z = 0; z <
lnz; ++z)
187 for (
int y = 0; y <
lny; ++y)
188 std::memcpy(&
global[(std::size_t)ox + (std::size_t)(y + oy) *
N +
189 (std::size_t)(z + oz) *
N *
N],
191 (std::size_t)
lnx *
sizeof(
double));
197 }
else if (rank == 0) {
202 for (
int z = 0; z <
meta[5]; ++z)
203 for (
int y = 0; y <
meta[4]; ++y)
204 std::memcpy(&
global[(std::size_t)
meta[0] + (std::size_t)(y +
meta[1]) *
N +
205 (std::size_t)(z +
meta[2]) *
N *
N],
207 (std::size_t)
meta[3] *
sizeof(
double));
213static double maxAbsDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
215 for (std::size_t i = 0; i < b.size(); ++i)
216 m = std::fmax(m, std::fabs(a[i] - b[i]));
219static double maxAbs(
const std::vector<double>& a) {
222 m = std::fmax(m, std::fabs(v));
228 Kokkos::initialize(
argc, argv);
231 int rank = 0, size = 1;
235 auto dec = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
N,
N,
N);
236 auto blk =
dec.block(rank);
237 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
238 const int lnx = (int)blk.size[0],
lny = (
int)blk.size[1],
lnz = (int)blk.size[2];
239 bool cut[3] = {
false,
false,
false};
240 for (
const auto& sz :
dec.sizes())
241 for (
int a = 0; a < 3; ++a)
250 for (std::size_t r = 0; r <
dec.sizes().size(); ++r) {
251 const auto b =
dec.block(r);
252 const double bx = (
double)b.origin[0],
by = (
double)b.origin[1];
253 if (
bx > 0.0 && ((
X0() -
bx) * (
x1 -
bx) < 0.0))
255 if (
by > 0.0 && ((
Y0() -
by) * (y1 -
by) < 0.0))
260 "MOVING-SCENE ADVECT MPI np=%d grid %d^3 block %dx%dx%d cut axes: %s%s%s "
261 "sphere d=%g Re=%g mu=%g dt=%g steps=%d tow (%.2f,%.2f)->(%.2f,%.2f) "
262 "cut-plane crossings=%d\n",
263 size,
N,
lnx,
lny,
lnz, cut[0] ?
"x" :
"", cut[1] ?
"y" :
"", cut[2] ?
"z" :
"",
DIAM,
RE,
269 " FAIL — the towed sphere never crosses an ORB cut plane; this test exists "
270 "to gate the moving wall + its advective inputs ACROSS a rank boundary\n");
280 std::fprintf(
stderr,
" FAIL — the scene instance is not moving (setInstanceMotion)\n");
283 for (
int it = 0; it <
STEPS; ++it)
288 std::vector<double>
gu[3];
289 for (
int c = 0; c < 3; ++c)
291 const std::vector<double>
gp =
301 ref.setPressureBottomSolver(2);
302 for (
int it = 0; it <
STEPS; ++it)
304 const std::vector<double>
frRef = ref.hydroForceTorqueReaction();
306 double du = 0,
umag = 0;
307 for (
int c = 0; c < 3; ++c) {
308 du = std::fmax(du,
maxAbsDiff(
gu[c], ref.getVelocity(c)));
312 const double pmag =
maxAbs(ref.getPressure());
313 double dF = 0,
dT = 0;
314 for (
int k = 0; k < 3; ++k) {
315 dF = std::fmax(dF, std::fabs(
frDist[k] -
frRef[k]));
319 std::fmax(std::fmax(std::fabs(
frRef[0]), std::fabs(
frRef[1])), std::fabs(
frRef[2]));
321 std::fmax(std::fmax(std::fabs(
frRef[3]), std::fabs(
frRef[4])), std::fabs(
frRef[5]));
325 const double rel = (size == 1) ? 0.0 : 3e-7;
326 const double utol = rel * std::fmax(
umag, 1e-300);
327 const double ptol = rel * std::fmax(
pmag, 1e-300);
334 const double relF = (size == 1) ? 1e-12 : 3e-7;
343 " np=%d du=%.3e (|u|=%.4e) dp=%.3e (|p|=%.4e) dF=%.3e dT=%.3e "
344 "div=%.2e tol %.1e/%.1e rel\n",
346 std::printf(
" np=%d F_dist=(%.17g, %.17g, %.17g)\n", size,
frDist[0],
frDist[1],
frDist[2]);
347 std::printf(
" np=%d F_ref =(%.17g, %.17g, %.17g) T_ref=(%.3e, %.3e, %.3e)\n", size,
350 std::fprintf(
stderr,
" FAIL — degenerate case (|u|=%.3e, |F|=%.3e)\n",
umag,
fmagv);
356 std::printf(
"MOVING-SCENE ADVECT MPI (np=%d): %s\n", size,
fail ?
"FAIL" :
"PASS");
void setInstanceTransform(int i, const std::array< double, 3 > &translation, const std::array< double, 4 > &quat)
Move one instance (Layer 3 rung 4).
bool hasMovingInstance() const
True when at least one instance carries a nonzero velocity – i.e.
double maxOpenDivergence()
void rebuildGeometry()
Re-derive ALL geometry from the current instance transforms (Layer 3 rung 4): rebuild the accelerated...
void setAdvection(bool on)
void setSolidFromScene(bool cutcellPressure)
Sample the scene onto this rank's inner grid and install it as the solid, entirely on device – no nx*...
void setVelocityIterations(int it)
void setPressureLevels(int levels)
void setInstanceMotion(int i, const std::array< double, 3 > &lin, const std::array< double, 3 > &ang, const double *center=nullptr)
Rigid-body motion of one scene instance (Layer 3 rung 2).
void setBodyForce(double fx, double fy, double fz)
Body force per unit volume, in the caller's units (e.g. a mean pressure gradient, or rho*g).
std::vector< double > getVelocity(int c)
void setAdvectionScheme(int s)
void setPressurePcg(bool on, int maxit, double rtol)
void setMu(double m)
Dynamic viscosity, in the caller's units.
void setScene(const std::vector< int > &nodeInts, const std::vector< double > &nodeReals, const std::vector< int > &instInts, const std::vector< double > &instReals, bool periodic=false)
Install an analytic scene from core's flat node/instance encoding (peclet/core/geom/scene_builder....
void setRho(double r)
Fluid density, in the caller's units.
std::vector< double > hydroForceTorqueReaction()
Hydrodynamic force and torque per instance from the DISCRETE REACTION (route (b) of the design note's...
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 X0C
static constexpr double RE
static void towStep(IbmSolver &s, int it)
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 Z0
static constexpr double RHO
static constexpr double MU
static constexpr double Y0C
static constexpr double DIRX
static constexpr int STEPS
static constexpr double DIRY
static double maxAbsDiff(const std::vector< double > &a, const std::vector< double > &b)
static void sphereScene(std::vector< int > &ni, std::vector< double > &nr, std::vector< int > &ii, std::vector< double > &ir)
static constexpr double OFF
static constexpr double DT
static constexpr double DIAM
static void configure(IbmSolver &s)
static bool envOn(const char *k)
static constexpr std::size_t GCELLS
static constexpr double U