|
core 1.5.0
Shared MPI block decomposition, asynchronous ghost-layer exchange, SDF geometry, load balancing (header-only C++20)
|
core — VoF rung V5a (WO-Q): the cut-cell rules of the Weymouth–Yue colour transport. More...
#include <Kokkos_Core.hpp>Go to the source code of this file.
Namespaces | |
| namespace | peclet |
| namespace | peclet::core |
| namespace | peclet::core::vof |
Enumerations | |
| enum | peclet::core::vof::VofCellKind : unsigned char { peclet::core::vof::kVofFluid = 0 , peclet::core::vof::kVofSolid = 1 } |
| Cell classification on the colour block. More... | |
| enum | peclet::core::vof::VofFillState : unsigned char { peclet::core::vof::kVofFillNone = 0 , peclet::core::vof::kVofFillFluid = 1 , peclet::core::vof::kVofFillPass0 = 1 } |
| Band-fill state, stored per cell on the colour block. More... | |
Functions | |
| double | peclet::core::vof::vofEpsEff (double eps, bool solid) |
| The effective fluid volume of a cell (rule 1). | |
| bool | peclet::core::vof::vofIsSolidCell (double eps, const double oLo[3], const double oHi[3]) |
Is this cell SOLID? eps == 0 and every one of the six faces closed. | |
| double | peclet::core::vof::vofCutFlux (double openness, double rawFlux) |
The openness-weighted geometric flux (1): one number per face, used with opposite signs by the two neighbours, so the sum telescopes bit-exactly whatever o is. | |
| double | peclet::core::vof::vofCutFluxClamp (double fluxMag, double sweep, double epsDon, double cDon) |
Weymouth's admissible flux interval, generalized to a cut donor cell — the cut-cell twin of momentum_advect.hpp point 3, and for the same reason. | |
| double | peclet::core::vof::vofCutCourant (double openness, double a, double eps) |
| The boundedness-relevant Courant number of a face against a cell (rule 2). | |
| double | peclet::core::vof::vofClipCut (double c, double epsEff, double &moved) |
The clip of rule 3, returned as the CLIPPED value; moved receives the liquid VOLUME the clip created (positive) or destroyed (negative) in this cell, i.e. | |
| bool | peclet::core::vof::vofFillReadable (unsigned char state, int k) |
Is state readable by pass k (1-based)? Fluid always; a solid cell only if an EARLIER pass filled it. | |
| int | peclet::core::vof::vofGhostDepth1 (int i, int g, int n) |
| Ghost depth of an index on one axis of an extended block: 0 for an inner cell, growing outward. | |
| int | peclet::core::vof::vofGhostDepth (int x, int y, int z, int g, int nx, int ny, int nz) |
| Ghost depth of a cell = the max over the three axes. | |
Variables | |
| constexpr double | peclet::core::vof::kVofEpsFloor = 1.0 / 64.0 |
The smallest fluid volume buildCellFraction's 4³ subsampling can resolve (one subcell of 64). | |
| constexpr double | peclet::core::vof::kVofCourantEpsFloor = 0.1 |
| Below this the interface-local Courant number stops being amplified by 1/eps (rule 2): a cut cell at eps = 0.1 already reports 10x its face Courant number, and chasing thinner slivers with dt buys boundedness the clip provides for free. | |
core — VoF rung V5a (WO-Q): the cut-cell rules of the Weymouth–Yue colour transport.
Container-free (the plic.hpp rule: scalars and small arrays only, no View, no indexing), so every rule below is a pure function that the device kernels in advect_wy.hpp and the solver plumbing in flow_ibm.hpp call, and that a host oracle can call verbatim.
VOF_PLAN.md §3 design rule 2: **C is the liquid fraction of the FLUID volume of a cell**, so C ∈ [0,1] whatever the solid fraction is. The transported quantity is therefore eps_i C_i (fluid volume × liquid fraction = liquid volume), and the split sweep becomes
eps_i C_i <- eps_i C_i + (F_{i-} - F_{i+}) + c_i ( o_{i+} a_{i+} - o_{i-} a_{i-} )
F_f = o_f * wyFaceFlux(a_f, ...) (1)
with o_f the face OPENNESS (fluid area fraction of the face, the same field scalarBuildRhs and divergOpen weight with), a_f = uf_f dt/h the face Courant number and c_i = H(C^n - ½) the frozen dilation indicator. Both the flux and the dilation term use the SAME o_f a_f per face, and the projection zeroes sum_f o_f u_f per cell — so
d/dt sum_i eps_i C_i = (telescoping flux sum) + sum_i c_i (openness-weighted divergence) = 0
exactly, to the accuracy with which the projection's own max|div(open u)| vanishes. That identity, not an accuracy statement, is what gate G2 measures.
The flux (1) uses the PLIC polyhedron reconstructed on the WHOLE unit cell (as if the cell were not cut) and multiplies its slab volume by the open area. This is an approximation — the accurate construction clips the PLIC polyhedron against the SOLID polygon as well (Huang, JCP 2025/2026 solid-clipped flux polygons) and would put the liquid where the fluid actually is inside the cell. It is conservative either way (one number per face, used with opposite signs by the two neighbours), it is exact wherever the interface and the wall are parallel or the cell is whole, and it is O(1) wrong in the distribution inside a cell whose interface and wall cross. Recorded as the known gap; see the WO-Q findings.
buildCellFraction subsamples 4³, so its output is a multiple of 1/64 and a cell can read eps == 0 while still owning an OPEN face (the face openness comes from a different quadrature, buildOpenness). Dividing the update by such an eps would be a division by zero on a cell that legitimately receives flux, so the scheme uses eps_eff = max(eps, kVofEpsFloor) with kVofEpsFloor = 1/64 — the subsampling resolution, i.e. the smallest fluid volume the quadrature can resolve at all. A cell that is eps == 0 AND has six closed faces is SOLID: it is excluded from the update entirely and its colour is supplied by the band fill below. Consequence for the conservation gate: the exactly conserved functional is sum_i eps_eff_i C_i, not sum_i eps_i C_i — they differ only on eps == 0 cells with an open face, where the raw sum silently drops whatever flux enters. Both are reported.eps_i and the area is o_f, so the effective Courant number is o_f |a_f| / eps_i. vofCutCourant is that number with a 0.1 floor on eps: the limiter throttles for genuinely cut cells and does NOT chase slivers to dt = 0 (a sliver's own boundedness is handled by the clip, which is measured).eps < 1), and the liquid volume that the clip moved is accumulated. If that number is not negligible the scheme is wrong and the fix is the solid-clipped flux polygon, not a bigger clip.The MYC 3³ stencil and the V3 height-function columns of a cell next to a wall reach INTO the solid. Leaving those cells at 0 makes every wall look perfectly non-wetting; the neutral rule is a zero-slope continuation of the colour into the wall, which is exactly the 90° contact angle boundary condition of Afkhami & Bussmann (IJNMF 57:453, 2008) written as fractions. Three passes with a SHRINKING depth budget (pass k writes solid cells at ghost depth ≤ 3−k and reads only fluid cells or cells filled in an EARLIER pass) walk the value up to three cells into the solid while keeping every read inside the halo the exchange has already made decomposition-independent. WO-S replaces the pass-1 rule with the θ-consistent one and keeps passes 2–3 and the depth budget unchanged.
**Layer L1 (VOF_PLAN.md §11): promoted from flow/src/vof/ to core (WO-W0, 2026-09-02).** These are the container-free VoF math kernels — one copy shared by every container: flow's structured colour field, the per-bubble block container (Part III) and the future AMR path. flow/src/vof/cutcell.hpp is now a thin include + a using-directive, so every existing peclet::flow::vof:: spelling keeps working unchanged.
Definition in file cutcell.hpp.