19#include <Kokkos_Core.hpp>
30 std::fprintf(stderr, "CHECK failed: %s\n at %s:%d\n", #cond, __FILE__, __LINE__); \
39std::vector<double>
sphereSdf(
double cx,
double cy,
double cz,
double R,
bool solidInside) {
40 std::vector<double> s((std::size_t)
N *
N *
N);
41 for (
int z = 0; z <
N; ++z)
42 for (
int y = 0; y <
N; ++y)
43 for (
int x = 0; x <
N; ++x) {
44 const double r = std::sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy) + (z - cz) * (z - cz));
45 s[(std::size_t)x + (std::size_t)y *
N + (std::size_t)z *
N *
N] =
46 solidInside ? r - R : R - r;
51using HV = Kokkos::View<double*, Kokkos::HostSpace>;
53 return Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), f);
62 s.setDomainBc(0, 1, 0, 0, 0);
63 s.setDomainBc(1, 1, 0, 0, 0);
65 s.setSolid(
sphereSdf(11.3, 12.6, 11.9, 6.4,
true),
false);
71 s.addScalar(
"c", 1.3, 1, 50,
true);
72 s.solveScalarSteady(
"c");
73 const auto& gm =
s.scalarCutGeometry();
74 auto unk = host(gm.unknown);
75 const HV sa[3] = {host(gm.sax), host(gm.say), host(gm.saz)};
76 auto&
sc =
s.scalarField(
"c");
77 auto AC = host(
sc.AC),
b = host(
sc.b);
78 const HV
lo[3] = {host(
sc.AW), host(
sc.AS), host(
sc.AB)};
79 const HV hi[3] = {host(
sc.AE), host(
sc.AN), host(
sc.AT)};
80 const int ex =
N + 2 *
G;
81 const long st[3] = {1, ex, (long)ex * ex};
82 long guarded = 0, asym = 0, badId = 0, badSum = 0, nUnk = 0;
84 for (
int z =
G;
z <
N +
G; ++
z)
85 for (
int y =
G;
y <
N +
G; ++
y)
86 for (
int x =
G;
x <
N +
G; ++
x) {
87 const long i = (long)x + (
long)
y *
st[1] + (long)z * st[2];
88 if (!(unk(i) > 0.5)) {
89 bool id =
AC(i) == 1.0 &&
b(i) == 0.0;
90 for (
int a = 0;
a < 3; ++
a)
91 id =
id && lo[a](i) == 0.0 && hi[
a](
i) == 0.0;
97 for (
int a = 0;
a < 3; ++
a) {
100 if (sa[a](i) > 0.0 && !(unk(i - st[a]) > 0.5))
102 if (sa[a](i + st[a]) > 0.0 && !(unk(i + st[a]) > 0.5))
104 const long j =
i +
st[
a];
105 const int c[3] = {
x,
y,
z};
106 if (c[a] + 1 <
N +
G && unk(j) > 0.5 && hi[a](i) != lo[a](j))
109 maxRow = std::fmax(maxRow, std::fabs(row) /
AC(i));
110 if (std::fabs(row) > 1e-14 *
AC(i))
114 "structure: %ld unknowns, guard fires on %ld interior faces, %ld asymmetric pairs, "
115 "%ld bad identity rows, max |row sum|/AC %.1e\n",
116 nUnk, guarded, asym, badId, maxRow);
124double maxDevUnknown(
IbmSolver& s,
double v) {
125 auto unk = host(
s.scalarCutGeometry().unknown);
126 auto c = host(
s.scalarField(
"c").c);
127 const int ex =
N + 2 *
G;
129 for (
int z =
G;
z <
N +
G; ++
z)
130 for (
int y =
G;
y <
N +
G; ++
y)
131 for (
int x =
G;
x <
N +
G; ++
x) {
132 const long i = (long)x + (
long)
y * ex + (long)z * ex * ex;
134 m = std::fmax(m, std::fabs(
c(i) -
v));
139void testConstants() {
143 s.addScalar(
"c", 0.9, 1, 50,
true);
144 s.setScalarWall(
"c", 1, 1.0, 0.0, -1);
145 s.setScalarTolerance(
"c", 1e-12);
146 s.setScalarMaxIterations(
"c", 3000);
147 s.solveScalarSteady(
"c");
148 const double d = maxDevUnknown(s, 1.0);
149 std::printf(
"constants: steady Dirichlet g = 1 -> max|c - 1| = %.2e (%d iterations)\n", d,
150 s.scalarField(
"c").cut->iterations);
152 CHECK(
s.scalarField(
"c").cut->converged);
157 s.addScalar(
"c", 0.9, 1, 50,
true);
158 std::vector<double> five((std::size_t)
N *
N *
N, 5.0);
159 s.setField(
"c", five);
160 for (
int k = 0;
k < 3; ++
k)
162 const double d = maxDevUnknown(s, 5.0);
163 std::printf(
"constants: transient insulating, c = 5 -> max|c - 5| = %.2e\n", d);
171 s.addScalar(
"c", 0.9, 1, 50,
true);
172 s.setScalarWall(
"c", 0, 0.1, 0.0, -1);
173 s.setScalarSource(
"c", 0.05);
174 s.setScalarMaxIterations(
"c", 3000);
175 s.solveScalarSteady(
"c");
176 const auto&
st = *
s.scalarField(
"c").cut;
177 auto unk = host(
s.scalarCutGeometry().unknown);
178 auto kap = host(
s.scalarCutGeometry().kappa);
179 auto c = host(
s.scalarField(
"c").c);
180 double kc = 0.0, kac = 0.0;
181 const int ex =
N + 2 *
G;
182 for (
int z =
G;
z <
N +
G; ++
z)
183 for (
int y =
G;
y <
N +
G; ++
y)
184 for (
int x =
G;
x <
N +
G; ++
x) {
185 const long i = (long)x + (
long)
y * ex + (long)z * ex * ex;
188 kac += kap(i) * std::fabs(
c(i));
192 "singular: incompatibility %.3e, %d iterations, converged %d, residual %.2e, "
193 "sum kappa c = %.2e (sum kappa |c| = %.2e)\n",
194 st.incompatibility,
st.iterations, (
int)
st.converged,
st.residual, kc, kac);
196 CHECK(
st.incompatibility > 0.1);
198 CHECK(std::fabs(kc) <= 1e-10 * kac);
205 s.addScalar(
"c", 1.1, 1, 50,
true);
206 s.setScalarBc(
"c", 0, 2, 0.25);
207 s.setScalarBc(
"c", 1, 2, 1.5);
208 s.setScalarWall(
"c", 2, 2.0, 0.5, -1);
209 s.setScalarSource(
"c", 0.3);
210 std::vector<double> init((std::size_t)
N *
N *
N);
211 for (std::size_t k = 0;
k < init.size(); ++
k)
212 init[k] = 0.5 + 0.25 * std::sin(0.37 * (
double)k);
213 s.setField(
"c", init);
215 s.solveScalarSteady(
"c");
217 for (
int k = 0;
k < 2; ++
k)
219 const auto b =
s.scalarBudget(
"c");
224 const double dtB =
steady ? 1.0 :
s.scalarField(
"c").cut->dt;
227 dtB * ((std::fabs(
b.wallIn) + std::fabs(
b.boundaryIn)) + std::fabs(
b.sourceIn));
229 "budget (%s): d_mass %.6e wall %.6e boundary %.6e source %.6e defect %.2e "
230 "identity %.2e (rel %.1e)\n",
231 steady ?
"steady" :
"transient",
b.dMass,
b.wallIn,
b.boundaryIn,
b.sourceIn,
b.defect,
232 b.identityError, std::fabs(
b.identityError) /
scale);
233 CHECK(std::fabs(
b.identityError) <= 1e-11 * scale);
234 CHECK(std::fabs(
b.wallIn) > 0.0 && std::fabs(
b.boundaryIn) > 0.0 &&
b.sourceIn > 0.0);
236 const auto wf =
s.scalarWallFlux(
"c");
237 CHECK(wf.size() == 1 && std::fabs(wf[0] -
b.wallIn) <= 1e-13 * std::fabs(
b.wallIn));
245 s.addScalar(
"c", 1.0, 1, 50,
true);
246 s.setScalarBc(
"c", 2, 2, 1.0);
250 }
catch (
const std::runtime_error&) {
258 s.addScalar(
"c", 1.0, 1, 50,
true);
261 s.solveScalarSteady(
"c");
262 }
catch (
const std::runtime_error&) {
270int main(
int argc,
char** argv) {
271 Kokkos::initialize(argc, argv);
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
Kokkos::View< double *, CCMem > CCField
Solver< Staggered > IbmSolver
steady(s, probe, maxit=3000, tol=1e-9)
static std::vector< double > sphereSdf()
static constexpr double AC