44#include <Kokkos_Core.hpp>
59 std::fprintf(stderr, "CHECK failed: %s\n at %s:%d\n", #cond, __FILE__, __LINE__); \
64std::size_t idx(
int x,
int y,
int z,
int n) {
65 return (std::size_t)x + (std::size_t)y * n + (std::size_t)z * (std::size_t)n * n;
67double maxAbsDev(
const std::vector<double>& v,
double ref) {
70 m = std::fmax(
m, std::fabs(
x -
ref));
73double maxAbsDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
78 for (std::size_t i = 0;
i <
a.size(); ++
i) {
79 const double d = std::fabs(a[i] - b[i]);
90std::vector<double> sceneSlab(
int n) {
91 std::vector<double>
c((std::size_t)n * n * n, 0.0);
92 for (
int z = n / 4;
z < 3 *
n / 4; ++
z)
93 for (
int y = 0;
y <
n; ++
y)
94 for (
int x = 0;
x <
n; ++
x)
95 c[idx(x, y, z, n)] = 1.0;
101std::vector<double> sceneTilted(
int n) {
102 double m[3] = {0.6, -0.5, 0.62456};
103 const double l1 = std::fabs(m[0]) + std::fabs(m[1]) + std::fabs(m[2]);
106 const double alpha = 0.5 * (
m[0] +
m[1] +
m[2]) * n;
107 std::vector<double>
c((std::size_t)n * n * n);
108 for (
int z = 0;
z <
n; ++
z)
109 for (
int y = 0;
y <
n; ++
y)
110 for (
int x = 0;
x <
n; ++
x)
111 c[idx(x, y, z, n)] = peclet::flow::vof::plicVolume(
112 m[0], m[1], m[2], alpha - (m[0] * x + m[1] * y + m[2] * z));
115std::vector<double> sceneSphere(
int n) {
116 const double r = 0.28 *
n, cc = 0.5 *
n;
117 std::vector<double>
c((std::size_t)n * n * n);
118 for (
int z = 0;
z <
n; ++
z)
119 for (
int y = 0;
y <
n; ++
y)
120 for (
int x = 0;
x <
n; ++
x)
121 c[idx(x, y, z, n)] = peclet::flow::vof::sphereCellFraction(cc, cc, cc, r, x, y, z, 1.0, 4);
127std::unique_ptr<IbmSolver> makeSolver(
int n,
const std::vector<double>& C,
double rhoG,
double rhoL,
128 double dt,
const double U[3],
bool momentum) {
129 auto s = std::make_unique<IbmSolver>(n, n, n);
133 s->setPressureGeometry(std::vector<double>((std::size_t)n * n * n, 10.0));
134 s->setPressureChebyshev(
true, 300, 1e-13);
137 s->setPropertyModel(
"rho", ClosureKind::LinearMix,
"C",
"", {rhoG, rhoL - rhoG});
139 s->enableVofMomentum(rhoG, rhoL);
140 const std::size_t
nc = (std::size_t)n * n * n;
141 s->uploadVelocity(std::vector<double>(nc,
U[0]), std::vector<double>(nc,
U[1]),
142 std::vector<double>(nc,
U[2]));
160void uniformIdentity() {
162 const double U[3] = {1.0, 0.6, -0.4};
163 const double dt = 0.2;
164 const char*
names[3] = {
"slab",
"tilted",
"sphere"};
165 std::vector<double> scenes[3] = {sceneSlab(n), sceneTilted(n), sceneSphere(n)};
166 for (
int sc = 0;
sc < 3; ++
sc) {
167 for (
double R : {10.0, 1
e2, 1e3, 1e4}) {
168 auto s = makeSolver(n, scenes[sc], 1.0, R, dt,
U,
true);
171 for (
int c = 0;
c < 3; ++
c)
172 one = std::fmax(one,
maxAbsDev(
s->getVofAdvectedVelocity(c),
U[c]));
173 std::printf(
"K1 %-7s ratio %-8g step 1: max|u_adv - U| = %.17g%s\n", names[sc], R, one,
174 one == 0.0 ?
" (BITWISE)" :
"");
176 const auto d =
s->vofMomentumDiagnostics();
181 for (
double R : {10.0, 1e3}) {
182 auto s = makeSolver(n, sceneTilted(n), 1.0, R, dt,
U,
true);
183 for (
int k = 0;
k < 40; ++
k)
186 for (
int c = 0;
c < 3; ++
c)
187 w = std::fmax(w,
maxAbsDev(
s->getVelocity(c),
U[c]));
189 "K1 tilted ratio %-8g 40 coupled steps: max|u - U| = %.4e "
190 "(the solver's float momentum-diagonal floor, not this rung)\n",
199 const double U[3] = {1.0, 0.6, -0.4};
200 for (
bool clamp : {
true,
false}) {
201 auto s = makeSolver(n, sceneTilted(n), 1.0, 1e3, 0.2,
U,
true);
202 s->setVofFluxClamp(clamp);
203 bool diverged =
false;
204 const int steps = clamp ? 20 : 4;
205 for (
int k = 0;
k <
steps; ++
k) {
208 }
catch (
const std::exception& ex) {
209 std::printf(
"K2 clamp OFF diverged at step %d (%s)\n", k, ex.what());
214 const auto d =
s->vofMomentumDiagnostics();
215 double lo = 1e300, hi = -1e300;
216 for (
int c = 0;
c < 3; ++
c) {
217 lo = std::fmin(lo,
d.minCc[c]);
218 hi = std::fmax(hi,
d.maxCc[c]);
220 std::printf(
"K2 clamp %-5s C^e in [%.4e, %.12f] min rho^e %.4g clamped fluxes %ld%s\n",
221 clamp ?
"ON" :
"OFF",
lo, hi,
d.minRhoC,
d.clamped, diverged ?
" DIVERGED" :
"");
226 CHECK(hi <= 1.0 + 1e-13);
242 const double U[3] = {1.0, 0.6, -0.4};
243 for (
double val : {1.0, 0.0}) {
244 std::vector<double>
C((std::size_t)n * n * n, val);
245 std::vector<double>
ref[3];
246 for (
double R : {1.0, 1
e2, 1e4}) {
247 auto s = makeSolver(n, C, 1.0, R, 0.2,
U,
true);
248 for (
int k = 0;
k < 10; ++
k)
250 if (ref[0].empty()) {
251 for (
int c = 0;
c < 3; ++
c)
252 ref[c] =
s->getVofAdvectedVelocity(c);
256 for (
int c = 0;
c < 3; ++
c)
257 d = std::fmax(d,
maxAbsDiff(
s->getVofAdvectedVelocity(c), ref[c]));
258 std::printf(
"K3 C == %.0f, ratio %-8g vs ratio 1: max|du_adv| = %.3e\n", val, R, d);
265void momentumConservation() {
267 const double U[3] = {1.3, 0.2, -0.1};
268 auto s = makeSolver(n, sceneSphere(n), 1.0, 1e3, 0.15,
U,
true);
270 const std::size_t
nc = (std::size_t)n * n * n;
271 std::vector<double> uu(nc), vv(nc,
U[1]), ww(nc,
U[2]);
272 for (
int z = 0;
z <
n; ++
z)
273 for (
int y = 0;
y <
n; ++
y)
274 for (
int x = 0;
x <
n; ++
x)
275 uu[idx(x, y, z, n)] =
U[0] + 0.3 * std::sin(2 * M_PI * (z + 0.5) / n);
276 s->uploadVelocity(uu, vv, ww);
277 double worst[3] = {0, 0, 0};
278 for (
int k = 0;
k < 100; ++
k) {
280 const auto d =
s->vofMomentumDiagnostics();
281 for (
int c = 0;
c < 3; ++
c)
282 worst[c] = std::fmax(
283 worst[c], std::fabs(
d.sumM[c] -
d.sumM0[c]) / std::fmax(1e-30, std::fabs(
d.sumM0[c])));
285 for (
int c = 0;
c < 3; ++
c) {
286 std::printf(
"K4 component %d: worst per-step |d sum(rho^e u)| / |sum| over 100 steps = %.3e\n",
292 CHECK(worst[c] < 1e-11);
299 const double U[3] = {0.8, 0.5, -0.3};
300 std::vector<double> u0[2][3],
p0[2], c0[2];
301 for (
int variant = 0; variant < 2; ++variant) {
306 auto s = makeSolver(n, sceneSphere(n), 1.0, 10.0, 0.2,
U,
false);
308 s->setVofRhoFloorFrac(1e-3);
309 s->setVofMomentumMuscl(
true);
310 s->setVofMomentumCellFlag(
true);
312 for (
int k = 0;
k < 15; ++
k)
314 for (
int c = 0;
c < 3; ++
c)
315 u0[variant][c] =
s->getVelocity(c);
316 p0[variant] =
s->getPressure();
317 c0[variant] =
s->getVof();
320 for (
int c = 0;
c < 3; ++
c)
321 du = std::fmax(du,
maxAbsDiff(u0[0][c], u0[1][c]));
324 std::printf(
"K5 feature OFF, knobs touched vs untouched: du %.3e dp %.3e dC %.3e\n", du, dp,
333int main(
int argc,
char** argv) {
334 std::setvbuf(stdout,
nullptr, _IONBF, 0);
335 Kokkos::initialize(argc, argv);
340 momentumConservation();
348 std::fprintf(stderr,
"%d failure(s)\n",
failures);
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
static double maxAbsDiff(const std::vector< double > &a, const std::vector< double > &b)
static constexpr double U
static double maxAbsDev(const std::vector< double > &a, double r)