(theory_scalar_voxelization)= # Voxelization of Solid-Body Scalar Boundaries A scalar boundary on a solid body, such as a heated obstacle or a surface releasing a pollutant, is ultimately a condition on the lattice nodes that sit against the body surface: fix the wall value, fix the wall flux, or seal the wall to scalar transport. In nassu the production route to impose those conditions on an arbitrary geometry is **voxelization**: the body surface is rasterized onto the Cartesian lattice, a thin band of nodes wrapping the surface is classified, and the existing scalar boundary-condition machinery is attached to those band nodes. This page motivates that choice, describes what the band is and why it is intentionally surface-only, and shows how the imposed wall conditions and the shared scalar code path connect. ## Why not the immersed boundary method The Immersed Boundary Method (IBM) represents a body by Lagrangian markers and a diffuse Dirac kernel that interpolates fluid quantities to the markers and spreads a correction force back to the Eulerian grid. For momentum this is the right tool: the no-slip condition is a target velocity at the marker, and the spread correction is a body force with a clear physical meaning that enters the Guo source term. A scalar Dirichlet or Neumann condition is a poorer fit for that machinery. The natural statement of a fixed-value or fixed-flux surface condition lives on the lattice nodes adjacent to the surface, where the wall-normal gradient is reconstructed from the off-wall interior values. Forcing it through a diffuse-interface spread means smearing the surface value over a kernel-width halo and iterating a scalar source to converge to the target, which blurs the very surface the condition is meant to pin and couples poorly to the level of the scalar boundary layer that may be much thinner than the velocity layer. The scalar boundary-condition page derives the sharp, node-local Dirichlet and Neumann reconstructions that nassu uses; voxelization exists to select the nodes those reconstructions act on, without introducing a separate forcing model. ```{admonition} Solid-body scalar walls use voxelization --- class: important --- Solid-body scalar walls are imposed by voxelizing the geometry and attaching the regularised scalar wall conditions of {doc}`boundary_conditions` to the classified band nodes. The diffuse-interface immersed-boundary scalar formulation in {doc}`coupling` is the alternative that reuses the velocity-IBM kernels. ``` ## What voxelization does For each runnable block the body surface is rasterized onto the lattice. Every triangle of the geometry mesh is tested against the lattice cells it overlaps, and the nodes that fall within the band of the surface are marked with a `SurfaceBand` voxel state. The rasterizer returns one record per band node carrying its lattice index, its triangle-overlap count, and a signed cardinal wall normal $(n_x, n_y, n_z)$ obtained by accumulating the local surface orientation and snapping it to the nearest of the six axis directions (or, where two faces meet, the diagonal combinations). That snapped normal points out of the wall into the fluid and tells the boundary condition which way the interior reference nodes lie. Band nodes are then grouped by their snapped normal. The policy that decides which boundary condition to attach is evaluated **once per distinct normal**, not per node, so the per-node work stays in the compiled rasterizer and the assignment loop, keeping setup tractable for very large node counts. Each group of nodes sharing a normal is handed to the lattice handler, which writes the boundary-condition function index and the snapped normal index into that node's bitmap entry. ### The band is a surface shell, not a filled solid The band is a thin shell of nodes at and just inside the surface. The interior of the body is **not** flood-filled or masked: it is left as dead fluid sealed behind the band. This is intentional. A surface boundary condition is, by definition, a statement about the surface; once the band seals every lattice link that crosses the wall, the interior is causally disconnected from the exterior flow and its state is irrelevant to the exterior solution. Filling the interior would add nodes that carry no boundary information and do no useful work. Interior masking belongs to the separate internal-flow track and is deliberately out of scope here. The band thickness is set by a band radius in lattice nodes. The default radius of one node gives a band half-extent of $1.5\,\Delta x$, which is the principled minimum for the momentum lattice: $$ \text{band half-extent} = \left(r_{\text{band}} + \tfrac{1}{2}\right)\Delta x $$ (band_extent) with $r_{\text{band}} = 1$. The reason is the link geometry of D3Q27: its diagonal links have length $\sqrt{3}\,\Delta x$, so a single node-thick wall does not intercept every population that would otherwise stream across the surface. One extra layer (half-extent $1.5\,\Delta x$) seals all 26 D3Q27 links crossing the wall. The scalar lattice is cardinal-only, so a band sized to seal D3Q27 over-seals the scalar lattice for free. ```{note} The band width also sets the geometric healing tolerance. A gap in the surface mesh narrower than the band is bridged by the band itself, and two surfaces closer together than the band merge into one. This is expected behaviour of band-only voxelization, and it is the reason the band radius is exposed as a configuration parameter: it trades surface fidelity against robustness to imperfect meshes. ``` ## Imposing the scalar condition on band nodes Once a band node is classified and tagged with a scalar boundary-condition function, the scalar wall condition is imposed by exactly the reconstructions documented in {doc}`boundary_conditions`. Voxelization does not introduce a new way to enforce a scalar wall; it only chooses the nodes and supplies each node's wall normal. - **Dirichlet (fixed value).** A band node tagged with `ScalarRegularizedDirichlet` carries a prescribed wall value $\phi_w$. The reconstruction builds the equilibrium populations from $(\phi_w, u_w)$, estimates the inward gradient from the off-wall interior nodes along the snapped normal, and rebuilds the non-equilibrium flux from that gradient. This is the route for a fixed-temperature or fixed-concentration surface. - **Neumann (prescribed flux).** A band node tagged with `ScalarRegularizedNeumann` carries a prescribed wall-normal flux $J_w$. The wall value is extrapolated from the known-flux gradient and the off-wall interior nodes, and the non-equilibrium flux is set to match $J_w$. A positive $J_w$ injects scalar into the fluid as a node-local source on the band; $J_w = 0$ recovers the adiabatic, zero-gradient wall. - **Robin (convective).** A band node tagged with `ScalarRegularizedRobin` loses scalar to a far-field ambient through $J_w = h\,(\phi_\infty - \phi_w)$. The unknown wall value is resolved from the convective balance and the off-wall interior nodes, and the resolved flux is imposed through the same prescribed-flux reconstruction as the Neumann band. This is the route for a wall exchanging heat with the surroundings, such as a room shell in a compartment-fire case. The velocity boundary condition on the same band (for example a halfway or regularised halfway bounce-back wall) and the scalar boundary condition are **independent axes**. The surface is rasterized once, and the same band nodes can receive a velocity wall on the fluid field and a distinct scalar wall on each scalar field. One body can therefore drive several scalar fields at once, for instance a no-slip momentum wall that is simultaneously a fixed-temperature surface for one scalar and an adiabatic surface for another. ```{warning} The per-node boundary-condition function index is a four-bit field, so at most fifteen distinct boundary-condition functions can coexist on a single field's lattice map. A voxelized curved surface specialises one function per snapped cardinal normal, so a body that produces more than fifteen distinct (type, normal) combinations exceeds the encoding and fails at setup with a clear message. Planar and cylindrical surfaces fit comfortably; a body that snaps to all 26 normals at once exceeds the encoding. This budget is independent per field, since the fluid and each scalar field keep their own lattice-type registry. ``` ## How voxelization fits the shared scalar path Voxelization respects the "same code, same path" principle that governs scalar transport in nassu. It is a **classifier**, not a second solver. Its only job is to mark lattice nodes and stamp each with a boundary-condition function and a wall normal; from that point on, the band nodes are ordinary boundary nodes processed by the existing scalar boundary-condition kernel for that field. There is no voxelization-specific collision, streaming, or communication. Each scalar field keeps its own lattice-type registry and bitmap, and the per-node assignment writes the snapped normal and boundary-condition function into that field's own bitmap. The scalar boundary kernel for a field dispatches on that field's function index exactly as a domain-edge scalar wall would, so a voxelized surface wall and a domain-boundary scalar wall travel through identical code. This also makes the band transparent to multiblock refinement. Band nodes stay live: their used and wet flags are untouched, so the F2C and C2F exchange treats them as ordinary nodes with no special case. The scalar exchange communicates only the scalar macroscopics $\phi$ and $q^{neq}_\alpha$, with no momentum or force content, so it is intrinsically force-free; the reconstructed band values cross refinement interfaces unchanged, governed by the rescaling rules in {doc}`coupling`. A fix to the shared scalar boundary or communication logic reaches voxelized walls and domain walls together, because they are the same path. ## Caveats and limits - **Resolution-dependent surface.** The surface is represented by the lattice nodes nearest to it with cardinal-snapped normals. Curvature and surface orientation are therefore resolved only to the grid scale, and a curved body is staircased at the lattice resolution. Refine the level around the body to sharpen the surface representation. - **Band thickness couples fidelity and robustness.** A thicker band heals larger mesh gaps and seals wider links but pushes the effective wall further from the true surface; the default radius is the minimum that seals D3Q27 and is the recommended starting point. - **No interior fill.** The interior is dead fluid sealed behind the band, which is correct for a surface condition but is not an internal-flow or solid-conduction model. Problems that need the body interior, such as conjugate heat transfer through the solid, are outside the scope of band-only voxelization. - **Concave corners.** A band node where the accumulated normal cancels (a concave corner or two surfaces meeting) has no single acceptable cardinal normal. By default this raises at setup; it can be configured to skip such nodes instead.