31#include <Kokkos_Core.hpp>
35#include "peclet/core/common/types.hpp"
36#include "peclet/core/decomp/block_decomposer.hpp"
46static constexpr int NX = 16,
NY = 16,
NZ = 32;
47static constexpr double XW = 5.25,
RD = 6.0,
THETA = 60.0;
50static double sdfAt(
double x,
double,
double) {
57 for (
int a = 0; a < 4; ++a)
58 for (
int b = 0; b < 4; ++b)
59 for (
int c = 0; c < 4; ++c) {
60 const double px =
ix + (a + 0.5) / 4.0, py =
iy + (b + 0.5) / 4.0,
61 pz =
iz + (c + 0.5) / 4.0;
65 const double dx = px -
XW, dy = py - 8.0, dz = pz - 16.0;
66 if (dx * dx + dy * dy + dz * dz <
RD *
RD)
74 std::vector<double> v((std::size_t)
lnx *
lny *
lnz);
75 for (
int z = 0; z <
lnz; ++z)
76 for (
int y = 0; y <
lny; ++y)
77 for (
int x = 0; x <
lnx; ++x)
78 v[(std::size_t)x + (std::size_t)y *
lnx + (std::size_t)z *
lnx *
lny] =
79 f(x + ox, y + oy, z + oz);
82static std::vector<double>
sliceOf(
const std::vector<double>& g,
int ox,
int oy,
int oz,
int lnx,
85 [&](
int x,
int y,
int z) {
86 return g[(std::size_t)x + (std::size_t)y *
NX + (std::size_t)z *
NX *
NY];
90static std::vector<double>
gatherGlobal(
const std::vector<double>&
local,
int ox,
int oy,
int oz,
91 int lnx,
int lny,
int lnz,
int rank,
int size) {
92 std::vector<double>
global;
95 for (
int r = 0; r < size; ++r) {
99 for (
int z = 0; z <
lnz; ++z)
100 for (
int y = 0; y <
lny; ++y)
101 std::memcpy(&
global[(std::size_t)ox + (std::size_t)(y + oy) *
NX +
102 (std::size_t)(z + oz) *
NX *
NY],
104 (std::size_t)
lnx *
sizeof(
double));
110 }
else if (rank == 0) {
115 for (
int z = 0; z <
meta[5]; ++z)
116 for (
int y = 0; y <
meta[4]; ++y)
117 std::memcpy(&
global[(std::size_t)
meta[0] + (std::size_t)(y +
meta[1]) *
NX +
118 (std::size_t)(z +
meta[2]) *
NX *
NY],
120 (std::size_t)
meta[3] *
sizeof(
double));
125static double maxAbsDiff(
const std::vector<double>& a,
const std::vector<double>& b) {
130 for (std::size_t i = 0; i < b.size(); ++i) {
131 const double d = std::fabs(a[i] - b[i]);
142 Kokkos::initialize(
argc, argv);
145 int rank = 0, size = 1;
148 auto dec = peclet::flow::CutcellMG::decomposition(
static_cast<std::size_t
>(size),
NX,
NY,
NZ);
149 auto blk =
dec.block(rank);
150 const int ox = (int)blk.origin[0], oy = (
int)blk.origin[1], oz = (int)blk.origin[2];
151 const int lnx = (int)blk.size[0],
lny = (
int)blk.size[1],
lnz = (int)blk.size[2];
152 const int gn[3] = {
NX,
NY,
NZ};
153 bool cut[3] = {
false,
false,
false};
154 for (
const auto& sz :
dec.sizes())
155 for (
int a = 0; a < 3; ++a)
156 if ((
int)sz[a] != gn[a])
160 "VOF WETTING MPI np=%d grid %dx%dx%d block %dx%dx%d cut axes: %s%s%s "
161 "theta = %.0f deg\n",
162 size,
NX,
NY,
NZ,
lnx,
lny,
lnz, cut[0] ?
"x" :
"", cut[1] ?
"y" :
"", cut[2] ?
"z" :
"",
164 if (size > 1 && !cut[2]) {
166 std::printf(
" FAIL — the decomposition does not cut z, so the contact line is not cut\n");
170 [](
int x,
int y,
int z) {
return sdfAt(x + 0.5, y + 0.5, z + 0.5); }, 0, 0, 0,
NX,
NY,
NZ);
193 long tot[5] = {0, 0, 0, 0, 0};
197 const auto gn0 = [&] {
206 const auto rd = ref.contactAngleDiagnostics();
207 const double d =
maxAbsDiff(g, ref.getVofFilledColour());
210 " [fill np=%d] theta band fill %.3e (bitwise required) | band census "
211 "theta/neighbour/pure/parallel/neutral %ld/%ld/%ld/%ld/%ld "
212 "(ref %ld/%ld/%ld/%ld/%ld) mean apparent %.3f deg | "
213 "max |theta-fill - neutral-fill| %.3e\n",
214 size, d, tot[0], tot[1], tot[2], tot[3], tot[4],
rd.contactCells,
rd.neighbourCells,
215 rd.pureCells,
rd.parallelCells,
rd.neutralCells,
rd.meanApparentAngle,
dn);
217 std::printf(
" [fill np=%d] FAIL — the theta band fill is not bitwise\n", size);
220 if (tot[0] !=
rd.contactCells || tot[1] !=
rd.neighbourCells || tot[2] !=
rd.pureCells ||
221 tot[3] !=
rd.parallelCells || tot[4] !=
rd.neutralCells) {
222 std::printf(
" [fill np=%d] FAIL — the band census differs from the reference\n", size);
230 const int steps = 25;
238 for (
int i = 0; i < steps; ++i) {
243 double v1 = 0.0, solid = 0.0;
247 std::vector<double>
gu[3];
248 for (
int c = 0; c < 3; ++c)
253 for (
int i = 0; i < steps; ++i)
256 for (
int c = 0; c < 3; ++c)
257 du = std::fmax(du,
maxAbsDiff(
gu[c], ref.getVelocity(c)));
259 const double drift = (
v1 -
v0) /
v0;
260 const double tol = size == 1 ? 0.0 : 1e-9;
262 " [coupled np=%d] colour %.3e velocity %.3e drift %.3e solid sum C %.3e "
263 "pressure iters max %ld\n",
264 size,
dc, du, drift, solid,
maxIt);
266 std::printf(
" [coupled np=%d] FAIL — colour %.3e velocity %.3e above tol %.1e\n", size,
270 if (!(solid == 0.0) || !(std::fabs(drift) <= 1e-9)) {
271 std::printf(
" [coupled np=%d] FAIL — solid sum %.3e drift %.3e\n", size, solid, drift);
281 std::printf(
fail ?
"VOF WETTING MPI: FAILED\n" :
"VOF WETTING MPI: all checks passed\n");
void setSolid(const std::vector< double > &sdfInner, bool cutcellPressure)
Host entry point: upload the inner SDF once and delegate.
std::vector< double > getVofFilledColour()
std::vector< double > getVof()
void setSurfaceTension(double sigma)
double capillaryDt()
The Brackbill capillary limit in the CALLER's time unit.
void setVof(const std::vector< double > &c)
ContactAngleDiagnostics contactAngleDiagnostics()
std::vector< double > getVelocity(int c)
long lastPressureIterations() const
void setMu(double m)
Dynamic viscosity, in the caller's units.
void setRho(double r)
Fluid density, in the caller's units.
vof::WyAdvector::Diagnostics vofDiagnostics()
void setContactAngle(double thetaDeg)
flow — host-facing Kokkos IBM Navier-Stokes solver (drop-in flow-style API).
double solidSumC
filled by the SOLVER from the canonical G=2 colour field
double volume
sum of eps_eff*C over inner FLUID cells: the EXACTLY conserved functional of the cut-cell scheme (cut...
static constexpr double XW
static constexpr double RD
static constexpr double THETA
static std::vector< double > blockOf(Fn f, int ox, int oy, int oz, int lnx, int lny, int lnz)
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 std::vector< double > sliceOf(const std::vector< double > &g, int ox, int oy, int oz, int lnx, int lny, int lnz)
static double colourAt(int ix, int iy, int iz)
static double maxAbsDiff(const std::vector< double > &a, const std::vector< double > &b)
static constexpr std::size_t GCELLS
static double sdfAt(double x, double, double)