zoomy_core.analysis package#
Generic linear-analysis tools for shallow-water-family PDE systems.
The unified analysis entry point is SystemModel (in
zoomy_core.model.models.system_model). Every analysis routine
in this package consumes a SystemModel and never inspects
model-specific attributes.
Package contents:
Linearisation around a base state (
linearise()) — operates on a SystemModel, returns a SystemModel of perturbation fields.Plane-wave dispersion analysis (ω(k) solutions).
Generalised-eigenvalue (“pencil”) form for systems with constraints.
Numerical eigenvalue sampling for hyperbolicity over a parameter cube.
The library knows nothing about VAM, SME, ML-SWE, etc. — every model-specific bit is in tutorials/.
- zoomy_core.analysis.linearise(sm, base_state, *, eps=None, simplify=True)#
Insert
Q = Q_0 + ε δQ, expand, return O(ε) SystemModel.- Parameters:
sm (SystemModel) – Input operator-form system.
base_state (dict) – Maps each entry in
sm.stateto its base value (a scalar or an expression in coordinates).eps (sympy Symbol, optional) – Small parameter; created internally if None.
simplify (bool) – Apply
sp.expandto each linearised operator entry.
- Returns:
New SystemModel whose state is
[δq_0, …, δq_{n-1}]and whose operator matrices are linearised aroundbase_state.- Return type:
SystemModel
- zoomy_core.analysis.plane_wave_dispersion(linear_sm, *, k=None, omega=None, axis=0, solve_for='omega', simplify=True, factor_in_target=True)#
Full dispersion solve.
Returns a dict with:
matrix — sp.Matrix M(ω, k) amplitudes — list of q̂ symbols determinant — det M(ω, k) solutions — list of ω(k) (or k(ω)) solutions phase_velocity_solutions — [ω/k for ω in solutions] (omega-mode only)
- Parameters:
k (Optional[Symbol]) –
omega (Optional[Symbol]) –
axis (int) –
solve_for (str) –
simplify (bool) –
factor_in_target (bool) –
- zoomy_core.analysis.plane_wave_matrix(linear_sm, *, k=None, omega=None, axis=0)#
Insert
δq → q̂ exp(i(k x_axis − ω t))and reduce to a matrix.linear_smmust be a SystemModel returned bylinearise()(state entries are the perturbation symbolsδq).- Returns:
M (sp.Matrix) – Coefficient matrix such that
M · q̂_vector = 0.amplitudes (list[sp.Symbol]) – Amplitude symbols, in the same order as
linear_sm.state.
- Parameters:
k (Optional[Symbol]) –
omega (Optional[Symbol]) –
axis (int) –
- zoomy_core.analysis.extract_quasilinear_pencil(linear_sm)#
Extract
(M_t, [M_xa], M_0)from a linearised SystemModel.Each entry of the linearised SystemModel’s operator slots is expected to be linear in the perturbation state.
- Returns:
M_t ((n_eq × n_state) sp.Matrix — coefficient of ∂_t δq_j.)
M_xa (list of (n_eq × n_state) sp.Matrix — one per spatial axis.)
M_0 ((n_eq × n_state) sp.Matrix — coefficient of δq_j (no derivative).)
- Return type:
Tuple[MutableDenseMatrix, List[MutableDenseMatrix], MutableDenseMatrix]
- zoomy_core.analysis.generalised_eigenvalues(M_x, M_t, *, lam=None, simplify=True)#
Symbolic generalised eigenvalues of the pencil
(M_x, M_t).Solves
det(M_x − λ M_t) = 0for λ. Returns a list of solutions.Caveat — symbolic charpoly degree blows up fast. For larger systems use
sample_generalised_eigenvalues(numerical).- Parameters:
M_x (MutableDenseMatrix) –
M_t (MutableDenseMatrix) –
lam (Optional[Symbol]) –
simplify (bool) –
- Return type:
List[Expr]
- zoomy_core.analysis.sample_generalised_eigenvalues(M_x, M_t, parameter_samples, *, dtype=<class 'complex'>, drop_infinite=False)#
For each sample (a dict of symbolic-value → numeric-value), return the numerical generalised eigenvalues of
(M_x, M_t)at that sample.Uses
scipy.linalg.eig(A, B)which solvesA v = λ B veven whenBis singular (in which case some λ are returned asinf).drop_infinite=Truefilters those out.- Parameters:
M_x (MutableDenseMatrix) –
M_t (MutableDenseMatrix) –
parameter_samples (List[Dict]) –
drop_infinite (bool) –
- Return type:
List[ndarray]
- zoomy_core.analysis.symbolic_eigenvalues_at(sm, base_state, *, axis=0, simplify=True)#
One-shot helper: linearise
sm(a SystemModel) atbase_state, extract the principal-symbol pencil(M_x_axis, M_t), and return the symbolic generalised eigenvalues.- Parameters:
sm – a
SystemModel.base_state (Dict) – dict
{state_sym: value}for every state entry.axis (int) – which spatial direction’s pencil to use (default 0).
simplify (bool) – apply
sp.expandto the characteristic poly.
- Returns:
list of symbolic eigenvalues.
- Return type:
List[Expr]
- zoomy_core.analysis.reduce_singular_pencil(M_x, M_t, fields, M_0=None, *, verbose=False)#
Eliminate algebraic-constraint rows + the corresponding fields.
Three classes of “algebraic” rows are handled:
M_t row = 0andM_x row != 0— principal-symbol algebraic constraint at high k. Use the M_x row to solve for one field and substitute into all remaining rows (M_x, M_t and M_0 if provided).M_t row = 0andM_x row = 0andM_0 row != 0— zeroth-order algebraic constraint (k-independent). Use the M_0 row to solve. REQUIRESM_0argument.All three rows zero — redundant; drop the row.
Returns
(M_x_reduced, M_t_reduced, fields_reduced)with no all-zeroM_trows. IfM_0was provided it is also reduced; access via the returned tuple’s caller side-effect (the matrix is mutated in place — pass a copy if you need the original).- Parameters:
M_x (MutableDenseMatrix) –
M_t (MutableDenseMatrix) –
fields (List) –
M_0 (Optional[MutableDenseMatrix]) –
verbose (bool) –
- Return type:
Tuple[MutableDenseMatrix, MutableDenseMatrix, List]
- zoomy_core.analysis.is_hyperbolic_at(M_x, M_t, sample, *, tol=1e-09, drop_infinite=True)#
Evaluate
(M_x, M_t)atsampleand check eigenvalues.Returns
(hyperbolic, eigenvalues).hyperbolicisTrueiff every finite eigenvalue has|imag| < tol.- Parameters:
M_x (MutableDenseMatrix) –
M_t (MutableDenseMatrix) –
sample (Dict) –
tol (float) –
drop_infinite (bool) –
- Return type:
Tuple[bool, ndarray]
- zoomy_core.analysis.sample_hyperbolicity(M_x, M_t, parameter_ranges, *, n_samples=1000, rng=None, tol=1e-09, drop_infinite=True, constraint_filter=None, max_attempts=10)#
Random-uniform sample over a hyper-rectangle of parameters.
- Parameters:
M_x (MutableDenseMatrix) – the pencil matrices (sympy).
M_t (MutableDenseMatrix) – the pencil matrices (sympy).
parameter_ranges (Dict[Any, Sequence]) – dict
{sympy_symbol: (lo, hi)}for the variables you want to sample. Symbols not in this dict must already be substituted-out in the pencil (e.g. fixed at chosen values).n_samples (int) – number of accepted samples to draw.
rng (Optional[Generator]) – optional
np.random.Generator.tol (float) – imaginary-part threshold for “real”.
drop_infinite (bool) – drop infinite generalised eigenvalues (typical for systems with constraints).
constraint_filter (Optional[Callable[[Dict], bool]]) – optional callable
sample_dict → bool. A sample is rejected (and another drawn) if this returns False — useful for excluding e.g. h ≤ 0.max_attempts (int) – per accepted sample, how many draws before giving up.
- Return type:
Returns
HyperbolicityReport.
- zoomy_core.analysis.plot_dispersion(result, k_range, *, k_var=None, ax=None, n_points=200, mode='phase_velocity', fixed_subs=None, references=None, nondimensionalise_by=None, squared=False, title=None, mode_labels=None, drop_zero_modes=True, **plot_kwargs)#
Plot dispersion curves from a
plane_wave_dispersionresult.- Parameters:
result (Dict) – dict from
plane_wave_dispersion().k_range (Tuple[float, float]) –
(k_lo, k_hi)numeric range over which to evaluate.k_var (Optional[Symbol]) – wavenumber symbol; auto-detected as
Symbol('k')if absent.ax – matplotlib axis to draw on; new figure created if None.
n_points (int) – grid resolution along k.
mode (str) –
'phase_velocity'(C = ω/k) or'omega'.fixed_subs (Optional[Dict]) – dict
{Symbol: number}for the non-k free symbols.references (Optional[Dict[str, Callable]]) – dict
{label: callable(k_arr)}for overlay curves (e.g.{'Airy': lambda k: np.sqrt(np.tanh(k*H)/(k*H))}).nondimensionalise_by (Optional[Tuple[str, Any]]) – tuple
(label, expr); if given, the y-axis becomesy / exprand the label includeslabel(e.g.('gH', g*H)).squared (bool) – if True, plot
y**2instead ofy(forC²/(gH)).title (Optional[str]) – optional plot title.
mode_labels (Optional[List[str]]) – if given, list of length
len(solutions)for the legend; otherwisemode 0, mode 1, ….drop_zero_modes (bool) – if True (default), skip ω-solutions that are identically zero (trivial constraint modes).
- Returns:
{'k', 'curves', 'figure', 'axis'}.
- zoomy_core.analysis.plot_hyperbolic_region_2d(M_x, M_t, axis_a, axis_b, fixed_subs, *, ax=None, n_a=100, n_b=100, tol=1e-09, drop_infinite=True, show='binary', title=None, cmap=None)#
2D color map of hyperbolicity over a chosen parameter pair.
Each
(a_val, b_val)grid point is evaluated by:Substituting all of
fixed_subsplus{axis_a[0]: a_val, axis_b[0]: b_val}intoM_xandM_t.Computing the generalised eigenvalues of the pencil
(M_x_num, M_t_num)viascipy.linalg.eig.Filtering infinite eigenvalues (constraint modes); the state is hyperbolic iff every remaining eigenvalue has
|imag| < tol.
- Parameters:
M_x – pencil matrices (sympy).
M_t – pencil matrices (sympy).
axis_a (Tuple[Symbol, float, float]) –
(symbol_a, lo, hi)for the x-axis parameter.axis_b (Tuple[Symbol, float, float]) –
(symbol_b, lo, hi)for the y-axis parameter.fixed_subs (Dict) – dict of values for every other free symbol in
M_xandM_t.n_a (int) – grid resolution.
n_b (int) – grid resolution.
show (str) –
'binary'(default — green=hyperbolic, red=non) or'imag_max'(color bymax |Im λ|).cmap (Optional[str]) – optional matplotlib colormap name.
tol (float) –
drop_infinite (bool) –
title (Optional[str]) –
- Returns:
dict with
a_grid,b_grid,is_hyperbolic(bool 2D array),imag_max(float 2D array),figure,axis.