flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_march_state.cpp
Go to the documentation of this file.
1
13#include <algorithm>
14#include <array>
15#include <cmath>
16#include <cstdio>
17#include <Kokkos_Core.hpp>
18#include <stdexcept>
19#include <string>
20#include <vector>
21
22#include "flow_ibm.hpp"
23#include "peclet/core/geom/scene_builder.hpp"
24
25using peclet::core::solver::AndersonRole;
28
29namespace {
30
31int failures = 0;
32
33void check(bool ok, const std::string& what) {
34 std::printf(" [%s] %s\n", ok ? "ok" : "FAIL", what.c_str());
35 if (!ok)
36 ++failures;
37}
38
39constexpr int N = 12;
40
41std::vector<double> sphereSdf(double radius) {
42 std::vector<double> sdf((std::size_t)N * N * N);
43 const double c = 0.5 * N;
44 for (int z = 0; z < N; ++z)
45 for (int y = 0; y < N; ++y)
46 for (int x = 0; x < N; ++x) {
47 const double dx = x + 0.5 - c, dy = y + 0.5 - c, dz = z + 0.5 - c;
48 sdf[(std::size_t)x + (std::size_t)N * (y + (std::size_t)N * z)] =
49 std::sqrt(dx * dx + dy * dy + dz * dz) - radius;
50 }
51 return sdf;
52}
53
54std::vector<double> allFluid() {
55 return std::vector<double>((std::size_t)N * N * N, 1.0);
56}
57
58template <class S>
59void basics(S& s) {
60 s.setRho(1.0);
61 s.setMu(1.0);
62 s.setDt(6.0);
63 s.setBodyForce(1e-3, 0.0, 0.0);
64 s.setPressurePcg(true, 200, 1e-8);
65}
66
68template <class S>
69void checkFields(S& s, const typename S::MarchState& ms, const std::vector<std::string>& names,
70 int carriedFrom, const std::string& tag) {
71 check(ms.fields.size() == names.size() && ms.roles.size() == names.size(),
72 tag + ": " + std::to_string(names.size()) + " fields and roles");
73 if (ms.fields.size() != names.size() || ms.roles.size() != names.size())
74 return;
75 const std::size_t nPad = (std::size_t)ms.e.x * ms.e.y * ms.e.z;
76 check(ms.G == 2 && ms.e.x == N + 4 && ms.e.y == N + 4 && ms.e.z == N + 4,
77 tag + ": e = n + 2G, G = 2");
78 for (std::size_t f = 0; f < names.size(); ++f) {
79 const AndersonRole want = (int)f < carriedFrom ? AndersonRole::Velocity : AndersonRole::Carried;
80 const bool same = ms.fields[f].data() == s.fieldView(names[f]).data();
81 check(ms.roles[f] == want && ms.fields[f].extent(0) == nPad && same,
82 tag + ": field " + std::to_string(f) + " is '" + names[f] + "' (" +
83 (want == AndersonRole::Velocity ? "Velocity" : "Carried") + ", padded)");
84 }
85}
86
87void gateRows() {
88 std::printf("rows of §3.1\n");
89 {
90 Stag s(N, N, N);
91 basics(s);
92 s.setAdvection(true);
93 s.setSolid(sphereSdf(3.0), true);
94 const auto ms = s.marchState();
95 checkFields(s, ms, {"u", "v", "w", "p"}, 3, "staggered + advection");
96 check(ms.signature[0] == 6.0 && ms.signature[1] == 1.0 && ms.signature[2] == 1.0 &&
97 ms.signature[3] == 1e-3 && ms.signature[4] == 0.0 && ms.signature[5] == 0.0,
98 "staggered: signature (dt, rho, mu, F) in cell units");
99 check(ms.signature[6] == 1.0 && ms.signature[7] == 0.0 && ms.signature[8] == 0.0,
100 "staggered: signature advection (on, scheme SOU, explicit)");
101 s.setAdvectionScheme(1);
102 s.setImplicitAdvection(true);
103 const auto ms2 = s.marchState();
104 check(ms2.signature[7] == 1.0 && ms2.signature[8] == 1.0,
105 "staggered: signature follows set_advection_scheme / set_implicit_advection");
106 }
107 {
108 Colo s(N, N, N); // AUTO scheme, Stokes: resolves to 'ghost' at set_solid
109 basics(s);
110 s.setAdvection(false);
111 s.setSolid(sphereSdf(3.0), true);
112 checkFields(s, s.marchState(), {"u", "v", "w", "p"}, 3, "collocated AUTO ghost, Stokes");
113 }
114 {
115 Colo s(N, N, N);
116 basics(s);
117 s.setCollocatedScheme("ghost");
118 s.setAdvection(true);
119 s.setUfAdvection(false);
120 s.setSolid(sphereSdf(3.0), true);
121 checkFields(s, s.marchState(), {"u", "v", "w", "p"}, 3,
122 "collocated ghost + advection, set_uf_advection(False)");
123 }
124 {
125 Colo s(N, N, N);
126 basics(s);
127 s.setCollocatedScheme("ghost");
128 s.setAdvection(true);
129 s.setSolid(sphereSdf(3.0), true);
130 const auto ms = s.marchState();
131 // uf/vf/wf are not in the field registry; compare them by position after u, v, w, p.
132 auto first4 = ms;
133 first4.fields.resize(std::min<std::size_t>(4, ms.fields.size()));
134 first4.roles.resize(std::min<std::size_t>(4, ms.roles.size()));
135 checkFields(s, first4, {"u", "v", "w", "p"}, 3,
136 "collocated ghost + projected-face advection (first 4)");
137 bool faces = ms.fields.size() == 7;
138 for (std::size_t f = 4; faces && f < 7; ++f)
139 faces = ms.roles[f] == AndersonRole::Carried &&
140 ms.fields[f].extent(0) == (std::size_t)ms.e.x * ms.e.y * ms.e.z;
141 if (faces) {
142 bool distinct = true; // three distinct buffers, none of them u, v, w or p
143 for (std::size_t f = 4; f < 7; ++f)
144 for (std::size_t g = 0; g < f; ++g)
145 distinct = distinct && ms.fields[f].data() != ms.fields[g].data();
146 faces = distinct;
147 }
148 check(faces, "collocated ghost + projected-face advection: + uf, vf, wf (Carried, padded)");
149 }
150}
151
154template <class S, class Make>
155void refusal(const std::string& tag, const std::string& token, Make make) {
156 S s(N, N, N);
157 basics(s);
158 std::string what;
159 try {
160 make(s);
161 (void)s.marchState();
162 } catch (const std::runtime_error& e) {
163 what = e.what();
164 }
165 const bool own = what.find(token) != std::string::npos;
166 const bool hint = what.find("pass accelerate=False") != std::string::npos;
167 check(own && hint, "refusal " + tag + ": \"" + what + "\"");
168}
169
170void sphereScene(Stag& s, double radius) {
171 namespace g = peclet::core::geom;
172 std::vector<int> ni(g::kNodeIntStride, 0), ii(g::kInstanceIntStride, 0);
173 std::vector<double> nr(g::kNodeRealStride, 0.0), ir(g::kInstanceRealStride, 0.0);
174 ni[0] = g::kSphere;
175 ni[1] = -1;
176 ni[2] = -1;
177 nr[0] = radius;
178 nr[14] = 1.0;
179 nr[15] = 1.0;
180 ii[0] = 0;
181 ii[1] = -1;
182 ir[0] = ir[1] = ir[2] = 0.5 * N;
183 ir[6] = 1.0;
184 ir[7] = 1.0;
185 s.setScene(ni, nr, ii, ir, /*periodic=*/true);
186 s.setSolidFromScene(true);
187}
188
189void gateRefusals() {
190 std::printf("refusals (§5.3)\n");
191 refusal<Colo>("1 collocated gauge-exact", "not the fluid-only 'ghost' projection", [](Colo& s) {
192 s.setCollocatedScheme("gauge-exact");
193 s.setSolid(sphereSdf(3.0), true);
194 });
195 refusal<Colo>("1 collocated embed", "not the fluid-only 'ghost' projection", [](Colo& s) {
196 s.setCollocatedScheme("embed");
197 s.setSolid(sphereSdf(3.0), true);
198 });
199 refusal<Stag>("2 VoF", "VoF", [](Stag& s) {
200 s.setPressureGeometry(allFluid());
201 s.enableVof();
202 });
203 refusal<Stag>("3 phase change", "phase change", [](Stag& s) {
204 s.setPressureGeometry(allFluid());
205 s.enablePhaseChange(1.0, 10.0, 1.0);
206 });
207 refusal<Stag>("4 scalar", "transported scalar", [](Stag& s) { s.addScalar("T", 0.1, 0, 1); });
208 refusal<Stag>("5 porous", "porous", [](Stag& s) { s.setPorousContinuity(true); });
209 refusal<Stag>("6 variable rho (closure)", "variable density or viscosity", [](Stag& s) {
210 s.addField("phase");
211 s.setPropertyModel("rho", peclet::flow::ClosureKind::LinearMix, "phase", "", {1.0, 0.0});
212 });
213 refusal<Stag>("6 mu field", "variable density or viscosity", [](Stag& s) { s.addField("mu"); });
214 refusal<Stag>("7 drag", "drag_beta", [](Stag& s) { s.enableDrag(); });
215 refusal<Stag>("8 cell force", "cell force", [](Stag& s) { s.enableCellForce(); });
216 refusal<Stag>("9 moving scene", "moving scene", [](Stag& s) {
217 sphereScene(s, 3.0);
218 s.setInstanceMotion(0, {1e-3, 0.0, 0.0}, {0.0, 0.0, 0.0}, nullptr);
219 });
220 refusal<Stag>("10 superficial velocity", "set_superficial_velocity",
221 [](Stag& s) { s.setSuperficialVelocity(true, 0, 1e-3); });
222 refusal<Stag>("11 pressure warm start", "warm start",
223 [](Stag& s) { s.setPressureWarmstart(true); });
224 refusal<Stag>("12 balanced-force projection", "balanced-force projection",
225 [](Stag& s) { s.setBalancedForceProjection(true); });
226 // A static scene is allowed.
227 {
228 Stag s(N, N, N);
229 basics(s);
230 sphereScene(s, 3.0);
231 bool ok = true;
232 try {
233 (void)s.marchState();
234 } catch (const std::exception&) {
235 ok = false;
236 }
237 check(ok, "a static scene is allowed");
238 }
239}
240
241} // namespace
242
243int main(int argc, char** argv) {
244 Kokkos::initialize(argc, argv);
245 {
246 gateRows();
247 gateRefusals();
248 }
249 Kokkos::finalize();
250 if (failures) {
251 std::fprintf(stderr, "\n%d CHECK(s) failed\n", failures);
252 return 1;
253 }
254 std::printf("\nAll march-state checks passed.\n");
255 return 0;
256}
int main()
Definition dbg_scene.cpp:13
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
static constexpr int N
static std::vector< double > sphereSdf()
static void sphereScene(std::vector< int > &ni, std::vector< double > &nr, std::vector< int > &ii, std::vector< double > &ir)
static bool same(double a, double b)