zoomy_core.systemmodel.system_model

zoomy_core.systemmodel.system_model#

Symbolic operator-form PDE system (SystemModel) extracted from a Model: flux, nonconservative matrix, source, diffusion, eigenvalues and boundary conditions in operator slots. Sits between Model and NumericalSystemModel; also holds the system-level operations that repack operators in place.

Module Contents#

Classes#

SpectralRadius

How a Riemann solver bounds the wave speed rho(A_n) when no closed-form eigenvalues exist.

SystemModel

Operator-form PDE system M dQ/dt + div(F + P) + sum_d B[:,:,d] d_d Q - S = 0 with operators indexed (equation_row, state_col[, dim]). It may be rectangular (equation_to_state_index maps equations to state entries); derived operators are cached or refreshed by refresh_derived_operators.

SystemModelRow

Row view of a SystemModel: row i of every stored matrix.

SystemModelDescription

Markdown (Jupyter _repr_markdown_) and plain-text description of a SystemModel.

RemoveNonDiagonalH

System-level op: substitute the mass equation into every row with a nonzero h entry in the mass matrix, moving the M[i,h] d_t h term into the NCP matrix and source. The mass row must satisfy M[m,h] = 1 and zero elsewhere; other mass-matrix entries are left alone.

HydrostaticReconstruction

System-level op: repack the gravity term g h d_x eta from the chain’s (P, B) form to the standard SWE P = g h^2/2 form that hydrostatic-reconstruction Riemann solvers expect. The bathymetry term is then supplied at runtime by the Audusse fluctuation.

InvertMassMatrix

System-level op: divide each evolution row by its diagonal mass entry M_ii and set M_ii = 1. Requires a diagonal mass matrix on evolution rows and zero on algebraic rows (check with assert_diagonal_mass_matrix); state-dependent entries give a symbolic 1/M_ii.

Functions#

face_normal_symbols

Canonical outward face-normal symbols n0 ... n_{n_dim-1}, the one naming convention shared by SystemModel.normal and the derivations.

register_function_slot

Route the derivation function group group_name to the SystemModel attribute sm_attr (e.g. a derived wall BC to a boundary-condition slot).

allow_unclosed

Context manager permitting a build to return a SystemModel that still has unclosed terms, an explicit and greppable opt-in for inspecting open full-stress models.

Data#

API#

zoomy_core.systemmodel.system_model.face_normal_symbols(n_dim)#

Canonical outward face-normal symbols n0 ... n_{n_dim-1}, the one naming convention shared by SystemModel.normal and the derivations.

zoomy_core.systemmodel.system_model.OPERATOR_ARG_SLOTS#

None

zoomy_core.systemmodel.system_model.register_function_slot(group_name: str, sm_attr: str) → None#

Route the derivation function group group_name to the SystemModel attribute sm_attr (e.g. a derived wall BC to a boundary-condition slot).

class zoomy_core.systemmodel.system_model.SpectralRadius#

Bases: zoomy_core.misc.options.Option

How a Riemann solver bounds the wave speed rho(A_n) when no closed-form eigenvalues exist.

Initialization

Initialize self. See help(type(self)) for accurate signature.

eig#

‘eig’

power#

‘power’

bound#

‘bound’

class zoomy_core.systemmodel.system_model.SystemModel#

Operator-form PDE system M dQ/dt + div(F + P) + sum_d B[:,:,d] d_d Q - S = 0 with operators indexed (equation_row, state_col[, dim]). It may be rectangular (equation_to_state_index maps equations to state entries); derived operators are cached or refreshed by refresh_derived_operators.

time: sympy.Symbol#

None

space: List[sympy.Symbol]#

None

state: List[Any]#

None

aux_state: List[Any]#

None

parameters: zoomy_core.misc.misc.Zstruct#

None

flux: zoomy_core.misc.misc.ZArray#

None

hydrostatic_pressure: zoomy_core.misc.misc.ZArray#

None

nonconservative_matrix: zoomy_core.misc.misc.ZArray#

None

source: zoomy_core.misc.misc.ZArray#

None

mass_matrix: zoomy_core.misc.misc.ZArray#

None

eigenvalues: Optional[zoomy_core.misc.misc.ZArray]#

None

eigenvalues_cfl: Optional[zoomy_core.misc.misc.ZArray]#

None

source_jacobian_wrt_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

source_jacobian_wrt_aux_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

flux_jacobian_wrt_aux_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

derive_jacobians: bool#

False

derive_source_jacobians: bool#

‘field(…)’

normal: Optional[zoomy_core.misc.misc.Zstruct]#

None

parameter_values: Optional[zoomy_core.misc.misc.Zstruct]#

None

equation_to_state_index: Optional[List[int]]#

None

boundary_conditions: Optional[Any]#

None

aux_boundary_conditions: Optional[Any]#

None

boundary_gradients: Optional[Any]#

None

initial_conditions: Optional[Any]#

None

aux_initial_conditions: Optional[Any]#

None

update_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

update_aux_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

diffusion_matrix: Optional[zoomy_core.misc.misc.ZArray]#

None

diffusion_matrix_explicit: Optional[zoomy_core.misc.misc.ZArray]#

None

source_explicit: Optional[zoomy_core.misc.misc.ZArray]#

None

reconstruction_variables: Optional[zoomy_core.misc.misc.ZArray]#

None

state_from_reconstruction: Optional[zoomy_core.misc.misc.ZArray]#

None

interpolate_to_3d: Optional[zoomy_core.misc.misc.ZArray]#

None

project_from_3d: Optional[zoomy_core.misc.misc.ZArray]#

None

position: Optional[Any]#

None

equilibrium_reconstruction: str#

‘none’

state_function_map: Optional[Dict]#

None

vertical: Optional[Any]#

None

unclassified_terms: List#

‘field(…)’

history: List[Dict[str, str]]#

‘field(…)’

admissible: Optional[zoomy_core.misc.misc.ZArray]#

None

property n_equations: int#

Number of equations (rows of the operators).

property n_state: int#

Number of state entries.

property n_dim: int#

Number of space dimensions.

property depth_scaled_state_indices: list#

State rows carrying one factor of the depth, i.e. every row except depth and bed, which a hydrostatic reconstruction must rescale by h*/h.

References

  • Audusse et al. 2004, https://doi.org/10.1137/S1064827503431090

property discharge_state_indices: list#

Per horizontal direction, the state row that is the depth-integrated mass flux (hu, q_x_0), read off the mass balance; -1 where no unique row exists.

property n_variables: int#

Number of state variables (equal to n_equations).

property n_aux_variables: int#

Number of aux variables.

property n_parameters: int#

Number of parameters.

property dimension: int#

Number of space dimensions (Model API alias of n_dim).

property variables: zoomy_core.misc.misc.Zstruct#

Zstruct view name -> state Symbol (mirrors Model.variables).

update_variables_or_identity() → zoomy_core.misc.misc.ZArray#

update_variables as an explicit (n_eq, 1) expression, the identity state[equation_to_state_index[i]] when the model has none; the C-family printers emit from this.

property aux_variables: zoomy_core.misc.misc.Zstruct#

Zstruct view name -> aux Symbol (mirrors Model.aux_variables).

position_struct() → zoomy_core.misc.misc.Zstruct#

The length-3 position group (x, y, z) that printers and analysis read; a bare system resolves the canonical symbols.

operator_signature(name: str) → zoomy_core.misc.misc.Zstruct#

The declared args Zstruct of operator name, built from this system’s symbols in OPERATOR_ARG_SLOTS order; the single source every backend reads.

operator(name: str) → Any#

Operator name as a basefunction.Function whose args is the declared signature and whose definition is the live array; backends only translate syntax.

property eigenvalue_mode: str#

"symbolic" when a symbolic spectrum is carried, "numerical" when it was skipped (eigenvalues is None).

attach_boundary_conditions(bcs, aux_bcs=None)#

Build the indexed symbolic BC kernels (boundary_conditions, boundary_gradients, aux_boundary_conditions) from existing BoundaryConditions objects.

Args

  • bcs: a BoundaryConditions container (or list).

  • aux_bcs: aux BCs; defaults to per-tag Extrapolation.

property roles#

The declared state roles resolved against the current state (systemmodel.roles.Roles).

property tags#

The declared model tags (see systemmodel/tags.py).

declare_tags(*tags)#

Record model tags; returns self.

declare_roles(**roles)#

Record a role declaration (see systemmodel.roles.declare_roles); returns self.

declare_admissible(constraints)#

Declare the admissibility list, expressions in (Q, Qaux, p) that must stay >= 0 (empty: every state admissible); returns self.

boundary_ghost_kernel()#

The ghost-state boundary kernel (function, branches), built on demand (see build_boundary_ghost_kernel).

admissible_constraints() → list#

The admissibility list as sympy expressions: the declared one, else [depth] for a free-surface system, else [].

property is_square: bool#

True when n_equations == n_state and equations map identity-style.

property stationary_indices: frozenset#

State indices whose row vanishes in every transport, source and diffusion slot, i.e. fields stationary by construction (e.g. the bed).

field_index(field) → int#

Integer state index of a field handle (Symbol or name matched by name, or an int bounds-checked); raises ValueError otherwise.

property quasilinear_matrix#

Flux Jacobian dF/dQ + dP/dQ + B, computed lazily from the primaries on first access and cached; assigning re-seeds the cache.

ensure_jacobians()#

Derive the source and flux jacobians now if absent (off by default, see derive_jacobians); call before the runtime is lowered, since printers emit what is present.

property eigensystem: zoomy_core.misc.misc.ZArray#

Opaque eigendecomposition of the normal-projected quasilinear matrix A_n = sum_d n_d quasilinear_matrix[:, :, d].

Returns

Flat row-major array [lambda (n), R (n*n), L = R^-1 (n*n)].

property numerical_eigenvalues: zoomy_core.misc.misc.ZArray#

Eigenvalues of A_n as n calls to the opaque eigenvalue kernel, used for the wave speed when the model has no closed-form eigenvalues (SME, VAM).

spectral_bound_iterations#

2

use_spectral_radius_bound#

False

spectral_radius_method#

None

spectral_power_steps#

10

spectral_power_safety#

1.06

property spectral_radius_bound#

Closed-form scalar upper bound on rho(A_n), the Min over k <= iterations of (max_i (|A_n|^k 1)_i)^(1/k), so the CFL needs no eigen-decomposition. Every candidate is an upper bound on its own, so iterations buys tightness only and the CFL cannot become unsafe.

References

  • Golub, Van Loan 2013, https://doi.org/10.56021/9781421407944

refresh_derived_operators(*, eigenvalues: bool = False)#

Recompute quasilinear_matrix and the source jacobians from the current (possibly mutated) primaries; eigenvalues=True also re-derives the spectrum.

assert_diagonal_mass_matrix()#

Check that mass_matrix is diagonal and nonzero on every evolution row and zero on every algebraic row; raises otherwise.

apply(operation, *, name: Optional[str] = None, description: Optional[str] = None)#

Apply a system-level operation in place; returns self.

has_active_source() → bool#

True if any source row is nonzero at the configured parameter values (matched by symbol name).

has_higher_moments() → bool#

True if the system carries moment rows beyond the depth-averaged one.

resolve_equilibrium_kernel(*, force_steady_ode: bool = False) → str#

Which concrete well-balanced kernel a backend must run: none / audusse pass through, the Bernoulli family resolves to steady_ode (friction, higher moments or force_steady_ode) or bernoulli_closed_form.

References

  • Pimentel-Garcia et al. 2022, https://doi.org/10.1016/j.jcp.2022.111152

is_vertical_dependent(symbol) → bool#

True if state symbol is a vertical-dependent field such as u(t,x,zeta), False for depth-collapsed fields or when no vertical is known.

classmethod from_model(model, Q=None, Qaux=None, canonical_source=None, dae=False, derive_source_jacobians=None) → zoomy_core.systemmodel.system_model.SystemModel#

Build a SystemModel from a Model; the single entry point. Production models with a _system_model_kind dispatch to their builder in model_builders, others go through _from_model_impl.

Args

  • Q: state fields of a declarative model (required there).

  • Qaux: aux fields; auto-populated when None.

  • canonical_source: user-facing model that owns the source and explicit-diffusion overrides.

  • dae: retain a non-diagonal or singular mass matrix (index-1 DAE) instead of requiring unit diagonal.

  • derive_source_jacobians: override of the field of the same name.

reconstruct_residuals()#

Re-assemble the row-wise residuals M d_t Q + d_x F + d_x P + B d_x Q - S as sympy expressions, with aux symbols back-substituted to their original atoms.

expose_aux_atoms()#

Route every non-state symbolic input (bare Functions such as the bed, and Derivative atoms) of the operators into aux_state and record each in aux_registry.

expose_functions_as_aux(function_names=None)#

Replace bare Function atoms (those named in function_names, else all) by aux Symbols of the same name appended to aux_state.

expose_derivatives_as_aux()#

Replace every Derivative(target, axes...) atom in the operators by an aux Symbol {target}_{axes} and record it in aux_derivative_map for the solver to fill.

change_state_variables(new_state, transform)#

Change the state variables in place, updating every state-dependent field (operators, derived operators, reconstruction pair, BC kernels, aux registry by the chain rule).

Args

  • new_state: new state vector of the same length.

  • transform: maps each replaced OLD state entry to its expression in the new variables.

remove_non_diagonal_h(**kwargs)#

Apply RemoveNonDiagonalH to this system.

assert_all_classified()#

Raise if any equation row carries an operator term the structural extractor could not classify into a slot; the strict counterpart of the build-time warning.

describe_unclosed() → str#

List the aux rows nothing computes (the model’s open terms), classifying each aux slot as computed, external or open.

describe(full: bool = False) → zoomy_core.systemmodel.system_model.SystemModelDescription#

A SystemModelDescription rendering the core operators; full=True adds the derived slots.

class zoomy_core.systemmodel.system_model.SystemModelRow(parent: zoomy_core.systemmodel.system_model.SystemModel, i: int)#

Row view of a SystemModel: row i of every stored matrix.

Initialization

View row i of parent.

property flux#

Row i of the flux.

property hydrostatic_pressure#

Row i of the hydrostatic pressure.

property source#

Entry i of the source.

property mass_matrix_row#

Row i of the mass matrix.

property nonconservative_matrix_row#

Row i of the nonconservative matrix as an (n_eq, n_dim) array.

class zoomy_core.systemmodel.system_model.SystemModelDescription(sm: zoomy_core.systemmodel.system_model.SystemModel, *, full: bool = False)#

Markdown (Jupyter _repr_markdown_) and plain-text description of a SystemModel.

Initialization

Describe sm; full adds the derived slots.

class zoomy_core.systemmodel.system_model.RemoveNonDiagonalH#

System-level op: substitute the mass equation into every row with a nonzero h entry in the mass matrix, moving the M[i,h] d_t h term into the NCP matrix and source. The mass row must satisfy M[m,h] = 1 and zero elsewhere; other mass-matrix entries are left alone.

name#

‘remove_non_diagonal_h’

description#

‘Substitute mass equation into rows with non-zero ∂_t h coupling; clear M[i, h] for those rows.’

class zoomy_core.systemmodel.system_model.HydrostaticReconstruction#

System-level op: repack the gravity term g h d_x eta from the chain’s (P, B) form to the standard SWE P = g h^2/2 form that hydrostatic-reconstruction Riemann solvers expect. The bathymetry term is then supplied at runtime by the Audusse fluctuation.

References

  • Audusse et al. 2004, https://doi.org/10.1137/S1064827503431090

name#

‘hydrostatic_reconstruction’

description#

“Convert chain’s g·h·η in (P, B) to standard SWE P = g·h²/2 for Audusse HR compatibility (drops -g·h·…”

class zoomy_core.systemmodel.system_model.InvertMassMatrix#

System-level op: divide each evolution row by its diagonal mass entry M_ii and set M_ii = 1. Requires a diagonal mass matrix on evolution rows and zero on algebraic rows (check with assert_diagonal_mass_matrix); state-dependent entries give a symbolic 1/M_ii.

name#

‘invert_mass_matrix’

description#

‘Divide each evolution row by its diagonal mass entry to reach canonical ∂_t Q form.’

zoomy_core.systemmodel.system_model.allow_unclosed()#

Context manager permitting a build to return a SystemModel that still has unclosed terms, an explicit and greppable opt-in for inspecting open full-stress models.

exception zoomy_core.systemmodel.system_model.UnclosedClosureError(unclosed, model_name='', system_model=None)#

Bases: RuntimeError

A declared closure reached the SystemModel with nothing closing it; carries the built system_model.

Initialization

Store the unclosed terms, the model name and the built system.

describe() → str#

The open-term listing (see SystemModel.describe_unclosed).