zoomy_core.model.basemodel module

zoomy_core.model.basemodel module#

Symbolic PDE model base: variables, parameters, registered flux/source callbacks, and BC wiring.

zoomy_core.model.basemodel.register_sympy_attribute(definition, prefix='q')#

Turn int or list field specs into a Zstruct of real sympy Symbols.

zoomy_core.model.basemodel.eigenvalue_dict_to_matrix(eigenvals_dict)#

Flatten a sympy eigenvals() dict {eigenvalue: multiplicity} into a ZArray.

zoomy_core.model.basemodel.default_simplify(expr)#
zoomy_core.model.basemodel.parse_definition_to_zstruct(definition, prefix='q_')#

Turn int/list/dict/Zstruct specs into symbolic Zstruct fields.

zoomy_core.model.basemodel.extract_parameter_defaults(definition)#

Numeric defaults for parameters (feeds model.parameters Zstruct values).

class zoomy_core.model.basemodel.Model(init_functions=True, **params)#

Bases: Parameterized, SymbolicRegistrar

Model. (class).

name = 'Model'#
dimension = 1#
disable_differentiation = False#
eigenvalue_mode = 'symbolic'#
variables = 1#
aux_variables = 0#
parameters = {}#
boundary_conditions = None#
aux_boundary_conditions = None#
initial_conditions = None#
aux_initial_conditions = None#
derive_model()#

Subclass hook — populate equations via self.add_equation(name, expr) and self.apply(Op(…)). No-op on the base class.

add_equation(name, expression=None, shape=None)#

Insert an equation into the model under name. Accessible afterwards as self.<name>.

With shape=None: scalar equation; self.<name> is the single Equation.

With shape=(s1, s2, ...) or a list of component labels: creates one sub-equation per index combo, named "{name}_{i}_{j}_...".

remove_equation(name)#

Remove an equation by name. After this, self.<name> raises AttributeError.

apply(op, *, level='major', description=None)#

Broadcast an Operation across every equation in the model.

op may be:

  • an Operation whose whole_model_op == True — in which case op.apply_to_model(self) is called once;

  • an Operation whose whole_model_op == False — applied per-equation via Equation.apply(op);

  • a substitution dict — broadcast as xreplace;

  • a Relation — broadcast via its substitution map;

  • a callable — broadcast via Equation.apply.

describe(*, show_history=False, include_minor=False)#

Return a ModelDescription rendering the equation set.

In a Jupyter cell, returning the description as the last expression triggers _repr_markdown_ and the equations render as LaTeX. In a plain Python REPL or via print(...) / str(...), the plain-text form is shown.

print_boundary_conditions()#

Print boundary conditions.

flux()#

Flux F(Q, Qaux, p) — rank-2 ZArray (n_eq, n_dim).

Default: walks self.equations via tag extraction, pulls every flux-tagged term, substitutes derivation Symbols for Model Symbols, returns as ZArray. Falls back to zeros when the derivation tree is empty.

diffusion_matrix()#

Diffusion matrix A(Q, Qaux, p) — implicit treatment.

Shape (n_variables, n_variables, dimension, dimension).

Defines the diffusive flux structurally via F_diff[i, d] = Σ_{j, e} A[i, j, d, e] · ∂_e Q[j]; the PDE residual contributes -∇·(A:∇Q). A is a pure (Q, Qaux, p) expression — derivatives enter only via Qaux, exposed automatically by SystemModel.expose_aux_atoms().

IMEX-capable backends evaluate this slot at Qnp1 inside the source step (no parabolic CFL). Override diffusion_matrix_explicit() instead for explicit treatment. Default: zero tensor (no diffusion).

diffusion_matrix_explicit()#

Diffusion matrix A(Q, Qaux, p) — explicit treatment.

Same shape and contraction contract as diffusion_matrix(). IMEX-capable backends evaluate this slot at Qn inside the convective step (Forward-Euler-equivalent; subject to the parabolic CFL dt h²/(2ν)). Default: zero tensor.

A SystemModel may declare both implicit and explicit diffusion contributions; the solver adds each at the appropriate stage. Explicit-only backends compound: A_total = A_implicit + A_explicit.

dflux()#

Dflux (legacy).

hydrostatic_pressure()#

Hydrostatic pressure P(Q, Qaux, p) — rank-2 ZArray (n_eq, n_dim).

Default: tag-extracted from self.equations (canonical tag hydrostatic_pressure). Falls back to zeros.

nonconservative_matrix()#

Nonconservative matrix B(Q, Qaux, p) — rank-3 ZArray (n_eq, n_state, n_dim).

Default: tag-extracted from self.equations (canonical tag nonconservative_flux). Falls back to zeros.

source()#

Source — implicit treatment (Manning friction, reactions, stiff body forces). Rank-1 ZArray of length n_variables.

Default: tag-extracted from self.equations (canonical tag implicit_source). Falls back to zeros.

source_explicit()#

Source — explicit treatment (non-stiff body forces, gravity, prescribed momentum sources). Rank-1 ZArray of length n_variables.

Default: tag-extracted from self.equations (canonical tag explicit_source). Falls back to zeros.

mass_matrix()#

Mass matrix M(Q, Qaux, p) — rank-2 ZArray (n_eq, n_state).

Extracted from time_derivative-tagged terms. Each equation row i contributes M[i, j] = coefficient of ∂_t Q[j] for j = 0..n_state-1. Rows with no time_derivative term (e.g. elliptic constraint equations for pressure modes in VAM, or trivial conservation that lost its ∂_t coefficient) come out as all-zero rows — a singular M flags the constraint to the solver, which must use a DAE-aware time-stepper or a split formulation.

The mass matrix arises naturally from the symbolic derivation; every ∂_t Q[j] atom on the LHS of an equation contributes to its row. There is NO fallback — if the derivation didn’t produce time-derivative terms, the model genuinely has no time-evolution slot, and the solver gets a singular M as the honest answer.

residual()#

Residual.

interpolate()#

Interpolate.

project_2d_to_3d()#

Project 2d to 3d.

project_3d_to_2d()#

Project 3d to 2d.

initial_condition()#

Initial condition.

initial_aux_condition()#

Initial aux condition.

update_variables()#

Update variables.

update_aux_variables()#

Update aux variables.

reconstruction_variables()#

Symbolic map state primitive well-balanced variables used by MUSCL-style reconstruction.

Override in subclasses to limit primitive quantities (η = h+b, u = q_U/h, …) instead of conservative ones (h, q_U), which bounds the limited values by physical scales and removes momentum overshoot at wet/dry fronts (Audusse-Bouchut-Bristeau et al.). Default: identity — the reconstruction layer then limits the conservative state directly.

Returns a ZArray of length n_variables; entry k is the symbolic expression for the reconstruction-side variable in the same slot. The inverse is auto-derived from this expression (see state_from_reconstruction()); subclasses with a non-invertible or hand-tuned inverse may override state_from_reconstruction directly.

See thesis/chapters/30_numerics.md “Primitive-variable MUSCL reconstruction”.

state_from_reconstruction()#

Symbolic inverse of reconstruction_variables(): primitive reconstruction variables → conservative state.

Default: auto-derived from reconstruction_variables() via zoomy_core.model.reconstruction_inverse.invert_reconstruction(). The result is expressed in terms of fresh WB_<state_name> symbols (one per state slot) which the runtime feeds with the reconstructed primitive face values; the callable then returns the conservative face state.

Override only if sympy’s solver cannot close the inverse symbolically (rare — the SWE / SME / VAM cases all close in closed form).

update_variables_jacobian_wrt_variables()#

Update variables jacobian wrt variables.

update_aux_variables_jacobian_wrt_variables()#

Update aux variables jacobian wrt variables.

quasilinear_matrix()#

Quasilinear matrix.

source_jacobian_wrt_variables()#

Source jacobian wrt variables.

source_jacobian_wrt_aux_variables()#

Source jacobian wrt aux variables.

eigenvalues()#

Eigenvalues of the normal-projected quasilinear matrix.

In ‘symbolic’ mode: solves the characteristic polynomial in SymPy. In ‘numerical’ mode: returns an empty ZArray (eigenvalues computed at runtime by the Numerics class via np.linalg.eigvals).

left_eigenvectors()#

Left eigenvectors.

right_eigenvectors()#

Right eigenvectors.

print_model_functions(function_names=None)#

Print model functions.

summarize_model(tex=False)#

Complete model description as a dict (for display) or LaTeX string.

Returns a dict with keys:
  • ‘pde_form’: the general PDE structure

  • ‘Q’: state vector

  • ‘Qaux’: auxiliary variables

  • ‘F’: flux matrix

  • ‘P’: hydrostatic pressure

  • ‘B’: nonconservative matrix (per dimension)

  • ‘S’: source vector

  • ‘eigenvalues’: list of eigenvalue expressions (or ‘numerical’)

  • ‘parameters’: {name: default_value}

  • ‘config’: model configuration summary

If tex=True, all SymPy objects are returned as LaTeX strings.

class zoomy_core.model.basemodel.ModelDescription(model, *, show_history=False, include_minor=False)#

Bases: object

Markdown / plain-text description of a Model.

Returned by Model.describe(). Renders LaTeX equations via _repr_markdown_ in Jupyter; str(...) / print(...) give the plain-text fallback.