← Explainer · Markdown · Source on GitHub
# Embedded boundaries before patch interfaces
**Source review, 2026-09-27, at
[`f6ea0e03aa1dd02e000cd64b07d6742583504221`](https://github.com/hankbeasley/polycfd/tree/f6ea0e03aa1dd02e000cd64b07d6742583504221).**
This is a review and recommendation, not a new numerical implementation or validation
run. AMR-02 and BC-01 are separate implementation efforts. Preserve their scope and the
current supported single-grid cases. Status belongs on the [work board](/docs/WORKBOARD).
The [illustrated explainer](/algorithms.html#geometry) introduces this review.
## Recommendation
**Keep the existing embedded-boundary foundation. Add a bounded geometry/operator
qualification before accepting solids that cross patch interfaces.** A wholesale EB
rewrite is not required before starting regular-grid S2 work. AMR-02 can continue its
behavior-preserving representation migration, and BC-01 can continue its domain-boundary
setup checks. Neither establishes that a cut surface can cross a storage join correctly.
The main near-term issue is preserving the *same discrete geometry and operators*
when the domain is partitioned. Conservative cut-cell momentum, improved wall accuracy,
moving-volume conservation and coarse/fine geometry have additional mathematical
requirements. Keep those extensions separate from this equivalence gate.
Implemented contracts remain in the [physics guide](/docs/PHYSICS_GUIDE#boundary-patches-and-resolved-bodies),
[projection guide](/src/PolyCfd.Gpu/Projection/README),
[diffusion guide](/src/PolyCfd.Gpu/Diffusion/README) and
[multigrid guide](/src/PolyCfd.Gpu/Multigrid/README).
The observations below explain their implications for S2/S3 at the reviewed revision.
## What the solver has today
The Cartesian mesh stays fixed around a solid. A signed-distance function describes
the body; it does not create a body-fitted mesh. PolyCFD's sign is **positive in fluid**.
Cell and face samples produce volume fractions $\kappa$, open-face fractions $\alpha$,
classifications and face-sampled normals pointing toward fluid. Fractions are stored
as `Half`; velocity and pressure fields are float, with double weighted reductions.
| Part | Current implementation and its limit |
| --- | --- |
| Geometry source | Analytic SDFs or STL-derived distance data; moving geometry can transform a cached distance field and rebuild device metrics. The cache has finite spatial resolution and coverage. |
| Fractions | Shared `CutCellFractions` finds face edge crossings/polygon areas and fits a plane to the eight cell corners for cell volume. Center-based fallback and solid thickening handle some unresolved features; they do not resolve a missing thin gap or wall. The class header's Simpson description is stale; the implemented cell routine uses a fitted plane. |
| Geometry storage | One fluid fraction and one pressure unknown per cell; three families of apertures, face classes and sampled normals, plus agglomeration indices. No general fluid/open-face/cut-surface centroid or cut-surface-area fields, and no independent multiple fluid subvolumes inside one cell. |
| Small cells | CPU sliver agglomeration transfers volume to a neighbor, caps it and solidifies the sliver. GPU construction instead solidifies small cells and prunes certain isolated cuts. Shared fraction formulas do not make those policies equivalent or make either a conservative momentum redistribution. |
| Pressure | Aperture-weighted Cartesian-face divergence and matching masked pressure correction, using the solver's cell-volume weights and connected pressure regions. Production GPU divergence divides by the stored positive fraction times cell volume; do not describe it as universally replacing every fraction with `max(kappa,0.05)`. |
| Viscosity and wall velocity | Component-wise Cartesian diffusion with optional static SDF-intercept wall coefficients. This is a separate operator from the pressure cut-cell flux balance. `BlockedOnly` preserves partial-face fluid flow; `NoSlip` closes cut faces at its constraint stage. Final velocity still needs checking after projection and all later constraints. |
| Advection | Semi-Lagrangian/MacCormack sampling. Optional static geometry-aware sampling pushes departure points out of solids and excludes blocked samples; the moving path uses geometry-aware sampling. This is not a conservative cut-volume momentum update. |
The resolved cylinder, channel-obstacle and cavity-sphere configurations combine
`BlockedOnly`, immersed-wall shear and geometry-aware advection. They are a useful
starting point, not universal defaults or proof for every geometry. Keeping a partial
Cartesian face open is compatible with a no-slip *physical wall*: diffusion supplies
wall shear at an SDF intercept, while fluid uses the open part of the Cartesian face.
Zeroing the entire cut face is a different geometric/numerical approximation.
Pinned implementation: [shared fractions](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Core/Geometry/CutCellFractions.cs),
[CPU builder](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Core/Geometry/CutCellBuilder.cs),
[GPU builder/cache](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/Geometry/CutCellBuilderGpu.cs),
[geometry storage](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Core/Geometry/CellGeometry.cs),
[integrator](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/Integration/TimeIntegratorGpu.cs),
[cut-face constraints](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/Geometry/CutFaceProjectorGpu.cs).
### Three different checks at a solid
1. **Operator continuity:** does the final velocity satisfy the intended aperture-weighted
cell balance, with compatibility corrections reported separately?
2. **Imposed face values:** do blocked or held MAC samples have the required wall velocity?
3. **Physical surface behavior:** does reconstructed velocity at the actual curved wall
satisfy impermeability/no slip to the required accuracy under refinement?
Passing either of the first two does not establish the third. The
[physics guide](/docs/PHYSICS_GUIDE#boundary-patches-and-resolved-bodies) explicitly
does not establish convergence of reconstructed surface-normal velocity to zero.
The cylinder's current surface-normal bound is $0.35U_\infty$, independent of its
force-reference gate; retain that limit rather than presenting it as a general
wall-accuracy certificate. [Cylinder forces](https://github.com/hankbeasley/polycfd/blob/b7f5b9ba6f52355d9b196b586e4a6c8719d8feea/docs/CYLINDER_FORCES.md) use specialized
analytic-surface reconstruction, not a generic cut-surface traction API.
For active pressure cells in the current static geometry, the conceptual balance is
$$
V_i=\kappa_i\,\Delta x\Delta y\Delta z,\qquad
(D_\alpha u)_i=\frac{1}{V_i}\sum_f s_{if}\alpha_f A_f u_f.
$$
Fractions are dimensionless; area and volume are applied once. This is the represented,
possibly threshold-modified geometry. Solid-cell masks and correction eligibility
also belong to the actual stencil. It is not a derivation of momentum control volumes
around staggered U/V/W unknowns.
## Why independently building each patch is insufficient
**Coordinates and neighborhoods.** Current builders sample a zero-origin, single
domain using local indices. Gradients have local-edge treatments, and face blocking
checks only the adjacent cells available in the local array. A patch join must instead
use global physical coordinates and valid neighboring samples/classes. The same applies
to static immersed-wall coefficient construction, which currently skips neighbors
outside its arrays. Reusing these routines unchanged on separate patches would give
an internal storage edge the wrong numerical meaning.
**One shared face.** For a same-level face connecting active cells L and R, use one
represented open area $\alpha_f A_f$ and one normal volume flow $Q_f=\alpha_f A_f u_f$,
oriented positively from L to R. The contributions are $+Q_f/V_L$ and $-Q_f/V_R$
to divergence. Thus
$$
V_L(D_\alpha u)_{L,f}+V_R(D_\alpha u)_{R,f}=0.
$$
With the same eligible pressure gradient on that face, the corresponding off-diagonal
coefficients also satisfy $V_L A_{LR}=V_R A_{RL}$ for $A=-D_\alpha G$.
These are local cancellation/symmetry checks, not a proof of accuracy or of the whole
multigrid preconditioner. Two independently thresholded face copies, or different
solid-neighbor masks, can break them even when each patch looks plausible by itself.
**Topology and final metadata.** Pressure regions must be connected across open joins;
a fluid pocket spanning three patches still gets one gauge, not three. Build masks,
face classifications and normals from the *final* repaired geometry, then keep their
ghosts consistent. In `BuildFromSdfBuffersFusedPooled`, face metadata is generated
before `FixIsolatedCutCells` changes cell classes and shared apertures, without updating
face-class/normal arrays. Some consumers use face class alone; others use aperture
and class. This is a **source-identified consistency risk needing a focused reproduction**,
not a reproduced user-visible failure or a reason to invalidate every existing run.
Test the final class/aperture invariants and consumer behavior, and repair demonstrated
mismatches before making those values authoritative across patches.
**Periodic seams.** Existing pressure/multigrid guides document symmetry limits when
geometry crosses a periodic seam. Pressure-region joining and the operator can use
different stored endpoint apertures; diffusion's wrapped solid-centered case has its
own limitation. BC-01's domain-coordinate correspondence is useful but does not qualify
these EB operators. Give periodic geometry the same canonical shared-face and neighbor
rules, then verify it independently.
Pinned seams: [pressure operator](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/PressureOperatorGpu.cs),
[divergence/gradient](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/DivGradGpu.cs),
[pressure regions](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Gpu/Projection/PressureComponentsGpu.cs),
[static wall coefficients](https://github.com/hankbeasley/polycfd/blob/f6ea0e03aa1dd02e000cd64b07d6742583504221/src/PolyCfd.Core/Geometry/ImmersedWallCoefficients.cs).
## A bounded sequence and its evidence
These are recommended experiments, **not run in this review**. Reuse the
[S2/S3 evidence record](/docs/amrex-alignment/S2_S3_PLAN#evidence-matrix): pinned revision,
exact inputs/command, reference, metrics, tolerance rationale, result artifact and
not-run/failed/passed-for-scope status. Freeze tolerances before candidate evaluation.
| When | Required experiment and bounded claim |
| --- | --- |
| Before qualifying cuts across joins | On one grid, translate planar/curved walls, a sliver and a narrow passage through sub-cell offsets. Check final `kappa`/`alpha`/class consistency, represented volume, connectivity and zero/open-face rules after every repair path. Compare CPU/GPU only for explicitly equivalent options. Investigate the pruning metadata risk. |
| Alongside that geometry audit | Check weighted pressure symmetry, true residual versus final continuity, wall-link diffusion and physical surface-normal behavior for the declared static mode. Refine grid and wall offset separately. A converged linear solve is not the wall-accuracy result. Reuse PRJ-01 and existing tests rather than creating a competing solver effort. |
| First S2 implementation | Start all-fluid. Establish canonical face ownership, exchange, coupled pressure/diffusion and partition-independent diagnostics. This can proceed without new centroids, conservative cut-cell stabilization or moving-body support. |
| Before S2 accepts stationary EB crossings | Split the same discrete grid at several locations through the same solid; include unequal patches, each orientation/corner and a periodic join. Match final geometry/volume/connectivity first, then compare operator action, trajectories, pressure regions, wall and momentum/flow diagnostics with the monolithic reference. Use one face metric/flux and stage-valid geometry ghosts. |
| Before conservative transport supports cuts | Derive MAC dual cut volumes, open areas, wall transfers, transporting continuity, required centroids and a conservative small-cell treatment. The current regular-grid carrier identity and CFL proof do not extend automatically. This is TRN-01's cut extension. |
| Before moving or coarse/fine EB support | Qualify old/new geometry, exposed/covered cells, swept-volume budgets, wall work and final continuity for motion; establish coarse/fine metric/flux consistency for refinement. The first EB-free S3 pressure example need not wait for these extensions. |
Distinguish partition equivalence from physical accuracy: two layouts agreeing can
reproduce the same approximation error. A failed single-grid wall-accuracy target
requires a correction or an explicit narrower support claim before accepting that
target on multiple patches; do not relax the target or refresh references to pass.
### GPU and cost boundary
Keep repeated geometry sampling/repair, halos, connectivity and complete diagnostic
reductions on device. A host-built static BVH and bounded layout/status coordination
remain allowed by [GPU-01](/docs/plans/gpu-resident-processing). Existing bulk paths
remain tracked: for example, `CellTransitionHandler.HandleTransitions` downloads
classification arrays to count transitions, and some setup/conversion/diagnostic
paths still copy fields. Do not replicate these paths once per patch or add a CPU
geometry reconciliation pass. Full GPU-01 closure is not a prerequisite to unrelated
AMR-02 or regular S2 work.
Measure geometry build/exchange launches, bytes, synchronization, peak live geometry
and solver storage, and time to the same accepted result. Add metric fields only when
an operator consumes them; a complete AMReX-shaped allocation is not itself a benefit.
## What changes later, and what AMReX contributes
The current moving path rebuilds at the new time, initializes changed samples, uses
geometry-aware advection and a geometric continuity target, then reapplies moving-wall
constraints after pressure projection. Rigid rotation uses a wall-flux target; other
paths use volume change. Per-region compatibility can adjust that target. This does
not establish a conservative swept-volume momentum remap or wall-work balance.
See [moving geometry](/docs/PHYSICS_GUIDE#5-moving-geometry-and-pressure-components)
and [the future moving-volume equations](/docs/amrex-alignment/ALGORITHMS#mac-momentum-and-cut-cell-derivation).
Multigrid currently rediscretizes the SDF at solver-coarse levels with a controlled
physical-thickening policy. That is a pressure preconditioner choice. It does not
establish that physical AMR coarse volumes/apertures equal sums of their fine children.
S3 needs its own geometry consistency and operator derivation.
[AMReX's EB documentation](https://amrex-codes.github.io/amrex/docs_html/EB.html)
provides useful distinctions: geometry source/database, per-layout EB data, cell/face
centroids, boundary area/centroid/normal, and conservative small-cell redistribution.
Allocate richer metrics when our chosen MAC operators require them. Its cell-centered
methods are not a drop-in staggered momentum method.
| Convention | PolyCFD at reviewed revision | AMReX documented convention |
| --- | --- | --- |
| Implicit-function sign | Positive in fluid | Negative in fluid |
| Stored normal | At Cartesian faces, points into fluid | EB boundary normal points into covered solid |
| Multiple fluid pieces in one cell | No independent subvolume unknowns | Documented EB2 path also does not support multivalued cells |
Normal location differs as well as direction; a sign flip alone is not a data-model
conversion. Document these practical differences and any future adapter explicitly;
do not change the current sign/normal contracts during behavior-preserving AMR-02.
No wholesale EB2 replacement or multivalued-cell implementation is required by this review.
Existing plane/cylinder/sphere, geometry ownership, cut projection and multigrid tests
are useful starting evidence. They were inspected, **not rerun** here. Their tested
options and tolerances do not establish universal geometry order, STL fidelity,
moving-wall conservation or patch-interface support.