Models¶
A model describes the local physics of a block: state variables, physical flux, source terms, field coupling, wave speeds, projections, and capabilities. It does not describe mesh layout, AMR, MPI, Kokkos, output, or time stepping.
The documented route is to attach models to a Case.
Native bricks¶
import pops
model = pops.Model(
state=pops.Scalar(),
transport=pops.ExB(B0=1.0),
source=pops.NoSource(),
elliptic=pops.BackgroundDensity(alpha=1.0, n0=0.0),
)
Physics DSL¶
from pops.physics import Model
from pops.math import ddt, div
m = Model("plasma")
U = m.state("U", components=["rho", "mx", "my"], roles={"rho": "density"})
rho, mx, my = U
flux = m.flux("F", on=U, x=[...], y=[...], waves={"x": [...], "y": [...]})
m.rate("explicit_rate", ddt(U) == -div(flux))
The model is attached to a case:
case = pops.Case(layout=layout, name="run").block("plasma", physics=m)
Moment models¶
Generic moment construction belongs in pops.moments. Ready moment models
belong in pops.lib.models.moments.
Moment models must declare more than positivity of density. They need explicit contracts for realizability, closure, projection, wave speeds, moment ordering, and compatibility with Riemann solvers.
What a model must not do¶
A model must not compile itself, allocate runtime storage, run a simulation,
choose MPI/Kokkos backends, or own AMR. Those concerns belong to Case,
pops.compile, pops.bind, and the C++ runtime.