Native numerics: Riemann solvers and reconstruction¶
The hot-path finite-volume bricks are C++ native in include/pops/numerics/fv. Python never
computes a Riemann flux or a WENO reconstruction; it selects a native brick (a descriptor,
see Typed bricks (pops.lib)) and supplies the model-dependent quantities the brick needs.
Native Riemann solvers (include/pops/numerics/fv/numerical_flux.hpp)¶
Brick |
C++ type |
Needs from the model |
|---|---|---|
Rusanov (local Lax-Friedrichs) |
|
|
HLL |
|
|
HLLC |
|
|
Roe |
|
|
HLLC and Roe are generic over the model via capability traits (HasHLLCStructure,
HasRoeDissipation); 2D Euler is only the fallback when no hooks are provided. A model that
lacks a required capability is rejected with a clear message, e.g.
riemann HLLC requires model capability 'hllc_star_state' for state U.
Native reconstruction / limiters (include/pops/numerics/fv/reconstruction.hpp)¶
Brick |
C++ type |
|---|---|
First order (no slope) |
|
MUSCL minmod |
|
MUSCL van Leer |
|
WENO5-Z |
|
Selecting them from Python¶
A pops.physics.facade.Model selects the solver/reconstruction with TYPED pops.numerics
descriptors (pops.FiniteVolume(riemann=HLLC(), reconstruction=WENO5Z()); Spec 5 sec.7 rejects a
bare string) and generates the model hooks from physical roles via m.enable_hllc() /
m.enable_roe() (the hooks become POPS_HD C++ functions the native solver calls statically; no
Python callback, no per-cell string lookup).
The Spec 3 descriptors name these native bricks without computing anything:
import pops.lib as lib
lib.riemann.HLLC().native_id # 'pops::HLLCFlux'
lib.reconstruction.WENO5Z().native_id # 'pops::Weno5'
lib.riemann.HLLC().requirements # {'capabilities': ['physical_flux', 'pressure', ...]}
Capability validation (board)¶
m.riemann("hllc"/"roe"/"hll"/"rusanov") and m.finite_volume_rate(riemann=...) validate the
model’s capabilities for the chosen solver before anything is generated, and canonicalize the
board roles (density -> Density, momentum_x -> MomentumX, …) so the role lookup finds
them. HLLC/Roe require a pressure (a primitive p or a pressure= formula) and the fluid roles
Density/MomentumX/MomentumY; HLL requires wave speeds; Rusanov requires only a max wave speed.
Missing capabilities are rejected with a clear message, e.g.
riemann HLLC requires model capability 'pressure' for state 'U'. When valid, m.riemann drives
the dsl enable_hllc() / enable_roe() that generate the POPS_HD contact_speed /
hllc_star_state / roe_dissipation hooks from the roles.
Passing an explicit board formula for a single-state capability quantity overrides the
role-derived hook with that formula’s codegen: m.riemann("hllc", pressure=<pops.math expr>)
emits the pressure(U) hook from the given expression instead of the primitive p. A formula
that references a quantity the model cannot provide raises the same clear capability error at
codegen.
Status¶
The native solvers, the reconstruction bricks, the descriptor catalog, the board capability
validation, the role-derived hook generation and the single-state formula override (pressure=)
are in place. The two-state hooks (contact_speed / star_state, spanning UL/UR) take only a
role-derived capability descriptor, not an arbitrary pops.math formula; that and the end-to-end
board-model compile path are the remaining part of ADC-456.