zoomy_core.model.splitter#
Predictor / pressure / corrector splitter for non-hydrostatic SystemModels.
=========================================================================
CANONICAL SPLITTER: split_for_pressure_structural
This is the ONE generic, supported pressure splitter — use it for every
non-hydrostatic model (VAM, ML-VAM, …). It is what model.chorin_split(dt)
calls (see VAM.chorin_split / MLVAM.chorin_split). It is “structural”:
it discovers the row roles purely from the OPERATORS — the divergence
constraints are exactly the rows with an identically-zero mass-matrix row, the
rest are evolution rows — so it needs NO equation_names convention and works
for any level / dimension / basis straight out of a declarative derivation.
>>> split = VAM(level=1).chorin_split(dt) # (SM_pred, SM_press, SM_corr)
>>> split = split_for_pressure_structural(sm, P_syms, dt) # explicit form
DEPRECATED — do NOT use for new work (each raises a DeprecationWarning):
split_for_pressure— old chain-DAE splitter; dispatches rows by the fragileequation_namesconvention (mass/xmom_j*/zmom_j*/cont_j*). A declarative SystemModel carries no such names.split_simple— minimal hand-rolled splitter; used only by the hand-builtescalante_vam_bump/run.pyoracle (also name-based).build_pressure_elliptic_block— internal helper for the two deprecated splitters; the structural splitter does NOT use it.
The deprecated three are kept only so the legacy hand-built reference cases keep
running; new models and agents must go through chorin_split /
split_for_pressure_structural.
Module Contents#
Classes#
Explicit coefficient fields ( |
|
One stage of a split solver’s march (REQ-173). |
|
Three sub-SystemModels produced by |
Functions#
Build the pressure-stage elliptic block for |
|
Verify each row is linear in |
|
Extract the explicit affine pressure operator from a Chorin
|
|
DEPRECATED — use |
|
Structural predictor / pressure / corrector splitter — no equation-name conventions. |
|
DEPRECATED — use |
API#
- zoomy_core.model.splitter.build_pressure_elliptic_block(sm, pressure_vars: Sequence, dt: sympy.Symbol, *, bottom=None)#
Build the pressure-stage elliptic block for
SM_press.Parameters
sm(SystemModel): Chain-DAE SystemModel (e.g.SystemModel.from_model( VAMModelGalerkin(level=1))). Must carryequation_nameswith the canonical mass / xmom_j / zmom_j / cont_j layout.pressure_vars(Sequence): Pressure mode state Symbols (e.g.[P_0, P_1]for VAM(1,2,2)). Internally converted to Function form to match the residual representation produced bySystemModel.reconstruct_residuals.dt(sp.Symbol): Symbolic time-step.bottom(optional): Bottom-topography Functionb(x). If None, located by scanning equation residuals for a Function namedb.
Returns
dict with keys
rows,U_tilde,W_tilde,T_u,T_w,U_corr,W_corr,pressure_vars,h,bottom,t,x. All entries are in Function form (coordinate-dependent).
- zoomy_core.model.splitter.verify_p_linearity(rows, pressure_vars, x)#
Verify each row is linear in
(P_l, ∂_x P_l, ∂_xx P_l).
- class zoomy_core.model.splitter.PressureLinearOperator#
Explicit coefficient fields (
A0,first_derivative,second_derivative,RHS) of the affine pressure operatorSM_press.source, as printable sympy expressions.Produced lazily by
SystemModel.pressure_operatorby differentiating the already-splitsource(no re-derivation);Ax/Ay/AzandAxx/Ayy/Azz/Axy/Axz/Ayzare accessors (Nonewhen the axis is absent).- P_modes: list#
None
- A0: list#
None
- first_derivative: dict#
None
- second_derivative: dict#
None
- RHS: list#
None
- property Ax#
- property Ay#
- property Az#
- property Axx#
- property Ayy#
- property Azz#
- property Axy#
- property Axz#
- property Ayz#
- zoomy_core.model.splitter.build_pressure_linear_operator(sm_press)#
Extract the explicit affine pressure operator from a Chorin
SM_press(seePressureLinearOperator).Mechanical — no re-derivation.
SM_press.sourceis differentiated w.r.t. the bare pressure symbols (→A0) and w.r.t. the pressure-derivative aux symbols, which the existing aux metadata (aux_registry/aux_input_registryentries whosestate_indexis a pressure slot) sorts into first / second-derivative coefficient matrices by theirmulti_index. Assertssourceis affine inPand its pressure derivatives (raises clearly otherwise).General over any chorin-split model (VAM any level, ML_VAM), any number of pressure modes
NP, and any dimension (2-D / 3-D).
- class zoomy_core.model.splitter.Stage#
Bases:
typing.NamedTupleOne stage of a split solver’s march (REQ-173).
A split solver is supplied a list of stages and marches over it; a backend supplies one executor per stage
kind.label— a STABLE, deterministic per-stage identifier ("predictor"/"pressure"/"corrector"for the Chorin split). Code-generating backends key generated names off it (amrex emitsModel_<label>.H); it MUST NOT be derived from the list position, or any reordering silently renames every header and invalidates every build cache.kind— the executor kind:"hyperbolic" | "elliptic" | "pointwise"(extensible). It selects which per-kind executor the backend runs for this stage.sm— theSystemModelfor the stage.
- label: str#
None
- kind: str#
None
- sm: object#
None
- class zoomy_core.model.splitter.SplitForPressureResult#
Three sub-SystemModels produced by
split_for_pressure.For VAM(1, 2, 2) on
Q = [h, U_0, U_1, W_0, W_1, P_0, P_1]:SM_pred— predictor: 5 evolution rows (mass+ 2xmom+ 2zmom) updatingQ[0..4] = h, U_k, W_kwithP_kfrozen atP_k^n.SM_press— pressure stage: 2 algebraic rows (the elliptic block in(P_0, P_1)) updatingQ[5..6]. Mass matrix all-zero.SM_corr— corrector: 4 algebraic update rows.
- SM_pred: object#
None
- SM_press: object#
None
- SM_corr: object#
None
- property stages#
The split as a canonical stage list (REQ-173).
A split solver marches over this list; a backend supplies one executor per
Stagekind. The Chorin split is exactly this data — predictor (hyperbolic) → pressure (elliptic) → corrector (pointwise)..SM_pred/.SM_press/.SM_corrremain the primary attributes; this is a view of the same three objects with their stable labels and kinds attached.
- zoomy_core.model.splitter.split_for_pressure(sm, pressure_vars, dt, *, bottom=None)#
DEPRECATED — use
split_for_pressure_structural(viamodel.chorin_split(dt)).Old chain-DAE splitter that dispatches rows by the
equation_namesconvention (mass/xmom_j*/zmom_j*/cont_j*); a declarative SystemModel carries no such names. The structural splitter discovers the same roles from the operators (zero mass-matrix rows ⇒ constraints) and is the only supported path for new models.
- zoomy_core.model.splitter.split_for_pressure_structural(sm, pressure_vars, dt)#
Structural predictor / pressure / corrector splitter — no equation-name conventions.
The chain-DAE
split_for_pressuredispatches rows by the legacy naming scheme (xmom_j*,cont_j*,U_k/q_Uk). SystemModels extracted from a DECLARATIVE derivation carry no such names, but the row roles are fully visible in the operators:constraint rows — identically-zero mass-matrix row (no
∂_t): these are the divergence/incompressibility projections → the elliptic block determining the pressure modes;evolution rows — everything else; rows whose residual carries a pressure variable get the corrector update
Q[s] ← Q[s] − dt·(pressure part)/M[row, s];equation_to_state_indexsupplies the row→slot map (identity for a squarefrom_modelextraction).
The predictor is the PRESSURE-FREE hydrostatic system (the evolution residuals with every pressure mode set to zero) — Escalante et al. 2024 eq (12a): the hyperbolic step carries no non-hydrostatic terms; the FULL pressure impulse
−dt·T(P^{n+1})is applied by the corrector. (Keeping the pressure force atP^nin the predictor double-applies it and turns the pressure into an undamped alternating iterationP^{n+1} + P^n ≈ P_physthat diverges at shocks — the historic VAM dam-break NaN.) The elliptic rows are the constraint residuals with every corrected velocity substituted; the corrector applies the closed-form update viaupdate_variables.Parameters
sm(SystemModel): Square (or rectangular) extraction withequation_to_state_index.pressure_vars(Sequence): Pressure-mode state Symbols (must be entries ofsm.state).dt(sp.Symbol): Symbolic time-step.
- zoomy_core.model.splitter.split_simple(sm, pressure_vars, dt, *, bottom=None)#
DEPRECATED — use
split_for_pressure_structural(viamodel.chorin_split(dt)).Minimal hand-rolled splitter retained ONLY for the hand-built
escalante_vam_bump/run.pyreference oracle; it dispatches rows by theequation_namesconvention (cont_j*⇒ constraint). New models / agents must use the structural splitter, which discovers the same roles from the operators (zero mass-matrix rows ⇒ constraints).Copies the SystemModel, then deletes rows and terms.
Algorithm:
Copy the parent SystemModel three times →
(SM_pred, SM_press, SM_corr).SM_pred: keep only the rows whose
equation_namedoes NOT start withcont_j(evolution rows including any trivial ones likeb_eqfor bathymetry-as-state). Then ZERO out every pressure-state-dependent term:F.xreplace({P_k: 0}), same forP,B,S. The predictor thus advances with kinetic + gravity + NCP and ANY non-pressure source — exactly like the OLDPredictorCorrectorSolverdid with its flux-only step.SM_press: keep only the
cont_j*rows, with thedt-bakedU_corrsubstitution applied (reusesbuild_pressure_elliptic_blockfor the substitution machinery). This is the elliptic block in(P_0, P_1)that the implicit Newton-Krylov solver targets.SM_corr: the closed-form
update_variablesformulaQ[k] ← Q[k] − (dt/h)·T_u_k(P)(also frombuild_pressure_elliptic_block). This is the projection-corrector that applies the freshly-solved pressure to the momentum modes.
Parameters
sm(SystemModel): Parent system. Must carryequation_nameswhose values flag algebraic rows by thecont_jprefix.pressure_vars(Sequence[sp.Symbol]): Pressure state symbols (e.g.[P_0, P_1]).dt(sp.Symbol): Symbolic time-step (gets baked intoSM_press/SM_corroperators).bottom(optional): Forwarded tobuild_pressure_elliptic_block.
Returns
SplitForPressureResult