flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_vardensity_projection.cpp
Go to the documentation of this file.
1// Variable-density projection: (a) the hydrostatic acid test — a stratified two-layer fluid at
2// rest under gravity must stay at rest with the discrete pressure gradient exactly rho_face*g
3// (any inconsistency between the momentum face density, the force face value, and the projection
4// face coefficient shows up as a spurious velocity); (b) uniform-rho reduction — the varRho path
5// with rho == rho_ reproduces the constant-density solver.
6#include <cmath>
7#include <cstdio>
8#include <Kokkos_Core.hpp>
9#include <vector>
10
11#include "flow_ibm.hpp"
12
13namespace {
14int failures = 0;
15#define CHECK(cond) \
16 do { \
17 if (!(cond)) { \
18 std::fprintf(stderr, "CHECK failed: %s\n at %s:%d\n", #cond, __FILE__, __LINE__); \
19 ++failures; \
20 } \
21 } while (0)
22
23double maxAbs(const std::vector<double>& v) {
24 double m = 0;
25 for (double x : v)
26 m = std::fmax(m, std::fabs(x));
27 return m;
28}
29
30void hydrostatic(double ratio) {
31 const int N = 8, NZ = 24;
32 const double g = 0.1;
34 s.setRho(1.0);
35 s.setMu(0.0); // inviscid: the balance is exact (no viscous wall layer in the predictor)
36 s.setDt(1.0);
37 s.setDomainBc(4, 1, 0, 0, 0);
38 s.setDomainBc(5, 1, 0, 0, 0); // walls +-z, periodic x,y
39 s.setPressureGeometry(std::vector<double>((std::size_t)N * N * NZ, 10.0));
40 std::vector<double> rho((std::size_t)N * N * NZ);
41 for (int z = 0; z < NZ; ++z)
42 for (int y = 0; y < N; ++y)
43 for (int x = 0; x < N; ++x)
44 rho[(std::size_t)x + (std::size_t)y * N + (std::size_t)z * N * N] =
45 (z < NZ / 2) ? ratio : 1.0; // heavy below (stable stratification)
46 s.addField("rho");
47 s.setField("rho", rho);
48 s.setDensityMode(true);
49 s.setPropertyModel("force_z", peclet::flow::ClosureKind::LinearMix, "rho", "", {0.0, -g});
50 double last = 1e300;
51 for (int it = 0; it < 100; ++it) {
52 s.step();
53 last = std::fmax(maxAbs(s.getVelocity(0)),
54 std::fmax(maxAbs(s.getVelocity(1)), maxAbs(s.getVelocity(2))));
55 CHECK(!std::isnan(last));
56 if (std::isnan(last))
57 return;
58 }
59 // steady state: velocity at machine zero, dP/dz = -g*rho_face to machine precision
60 auto p = s.getPressure();
61 double perr = 0;
62 const int xc = N / 2, yc = N / 2;
63 for (int z = 1; z < NZ; ++z) {
64 const double dp = p[(std::size_t)xc + (std::size_t)yc * N + (std::size_t)z * N * N] -
65 p[(std::size_t)xc + (std::size_t)yc * N + (std::size_t)(z - 1) * N * N];
66 const double rf = 0.5 * (((z < NZ / 2) ? ratio : 1.0) + ((z - 1 < NZ / 2) ? ratio : 1.0));
67 perr = std::fmax(perr, std::fabs(dp + g * rf) / (g * ratio));
68 }
69 std::printf("hydrostatic ratio %g: final max|u| %.2e P-grad rel-err %.2e\n", ratio, last, perr);
70 CHECK(last < 1e-12);
71 CHECK(perr < 1e-11);
72}
73
74void uniformReduction() {
75 // Periodic body-force Stokes flow past an immersed cylinder: varRho(rho==rho_) vs constant.
76 const int N = 12, NZ = 6;
77 std::vector<std::vector<double>> uu, pp;
78 for (int var = 0; var < 2; ++var) {
80 s.setRho(2.0);
81 s.setMu(0.1);
82 s.setDt(5.0);
83 s.setBodyForce(1e-3, 0, 0);
84 std::vector<double> sdf((std::size_t)N * N * NZ);
85 for (int z = 0; z < NZ; ++z)
86 for (int y = 0; y < N; ++y)
87 for (int x = 0; x < N; ++x)
88 sdf[(std::size_t)x + (std::size_t)y * N + (std::size_t)z * N * N] =
89 std::sqrt(std::pow(x - N / 2.0, 2) + std::pow(y - N / 2.0, 2)) - N / 5.0;
90 s.setSolid(sdf, true);
91 if (var)
92 s.setDensityMode(true); // rho field seeded == rho_
93 for (int it = 0; it < 40; ++it)
94 s.step();
95 uu.push_back(s.getVelocity(0));
96 pp.push_back(s.getPressure());
97 }
98 double du = 0, dp = 0, us = 0;
99 for (std::size_t i = 0; i < uu[0].size(); ++i) {
100 du = std::fmax(du, std::fabs(uu[0][i] - uu[1][i]));
101 dp = std::fmax(dp, std::fabs(pp[0][i] - pp[1][i]));
102 us = std::fmax(us, std::fabs(uu[0][i]));
103 }
104 std::printf("uniform-rho reduction: rel du %.2e dp %.2e\n", du / us, dp);
105 CHECK(du / us < 1e-6); // different pressure driver (Chebyshev vs PCG) -> solver tolerance
106}
107} // namespace
108
109int main(int argc, char** argv) {
110 Kokkos::initialize(argc, argv);
111 hydrostatic(3.0);
112 hydrostatic(1000.0);
113 uniformReduction();
114 Kokkos::finalize();
115 if (failures == 0) {
116 std::printf("OK\n");
117 return 0;
118 }
119 std::fprintf(stderr, "%d failure(s)\n", failures);
120 return 1;
121}
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
hydrostatic(ratio, mu=0.0, steps=100, g=0.1, dt=1.0, N=8, NZ=24)
static constexpr int N
int main(int argc, char **argv)
#define CHECK(cond)