zoomy_core.model.derivation.basisfunctions

zoomy_core.model.derivation.basisfunctions#

Concrete polynomial bases in z (Legendre, Chebyshev, splines, layered, BC-aware) for the moment/Galerkin derivation. They resolve the opaque Galerkin brackets of a Model into numbers on the way to a SystemModel.

Module Contents#

Classes#

Basisfunction

Base class of a concrete basis: polynomials basis plus opaque heads phi_fn(k, zeta) and c_fn(zeta) that point back to the instance. ResolveBasis routes Galerkin brackets built from these heads to resolve.

Monomials

Monomial basis z**k (the base-class default).

LayeredBasis

Multi-layer basis: an inner basis rescaled onto each of N sub-intervals and zero outside, giving N * (inner_level + 1) functions with flat index i*m + k. inner_level=0 gives piecewise constants (multi-layer SWE), Legendre_shifted multi-layer moments.

Legendre_shifted

Shifted Legendre basis phi_k(z) = P_k(2z - 1) on [0, 1], orthogonal under unit weight; the standard SME moment basis.

WeightedBasis

Wrap an orthogonal basis with an explicit test weight (e.g. a curvilinear metric), so projections resolve concretely. It has no delta closed forms because the wrapped family is orthogonal only under unit weight.

Chebyshevu

Chebyshev-U basis on [-1, 1] with weight sqrt(1 - z**2) and normalisation sqrt(2/pi).

Chebyshevu_shifted

Chebyshev-U basis U_k(2z - 1) on [0, 1] with weight sqrt(z(1 - z)) and phi_0 = 1, orthogonal with norm pi/8.

Legendre_DN

Legendre-based basis on [-1, 1] satisfying no-slip at the bottom z = -1 and no-stress at the top z = 1 by construction; not an SWE-limit basis.

GalerkinBasis

Boundary-condition-aware basis: phi_0 = 1 and phi_k recombined from parent polynomials (Legendre or Chebyshev-U) to satisfy ‘free’, ‘noslip’, ‘nostress’ or ‘slip’ conditions at bottom and top.

SplineBasis

Raw B-spline hat-function basis on [0, 1] with nodal coefficients and partition of unity (sum B_k = 1). Provides get_knot_spans for piecewise integration.

Spline

Legacy B-spline basis with fixed knots; use SplineBasis instead.

OrthogonalSplineWithConstant

B-spline basis plus a constant, orthonormalised on [0, 1] by Gram-Schmidt.

API#

class zoomy_core.model.derivation.basisfunctions.Basisfunction(level=0, symbol='phi', **kwargs)#

Base class of a concrete basis: polynomials basis plus opaque heads phi_fn(k, zeta) and c_fn(zeta) that point back to the instance. ResolveBasis routes Galerkin brackets built from these heads to resolve.

Args

  • level: highest basis index (level + 1 functions).

  • symbol: name of the opaque phi_fn Function class.

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Basisfunction’

bounds()#

Return the integration interval [0, 1].

basis_definition()#

Return the monomials z**k for k = 0..level.

weight(z)#

Return the weight omega(z) = 1.

mean_coefficients()#

Return coefficients c_k with sum(c_k phi_k) = 1, so the depth mean is sum(c_k alpha_k)`. Default `[1, 0, ...] assumes phi_0 = 1; override when the constant is a combination (e.g. B-splines).

weight_eval(z)#

Evaluate weight numerically via lambdify.

weight_name#

‘c’

closed_form_bracket(name, args)#

Return the closed form of a named bracket ("Gram" / "Weight") in symbolic indices, or None. The base class has none; orthogonal bases override it, e.g. Legendre_shifted.

Args

  • name: bracket family name.

  • args: its index tuple.

resolve_atoms(expr)#

Replace each phi_fn(k, arg) with integer k by the polynomial eval(k, arg); symbolic k stays opaque. Atoms of other bases are untouched.

evaluate_bracket(body, var, lower=0, upper=1)#

Evaluate one Galerkin bracket int_lower^upper body d(var) to a number by concretising and using the antiderivative; memoised per instance.

Args

  • body: product of opaque phi / c heads, their derivatives and nested running integrals.

  • var: integration variable.

analytical_weighted_integral_bounds(poly_expr, var, lower, upper)#

Return int_lower^upper poly_expr d(var) by antiderivative.

resolve(expr, var)#

Resolve every Galerkin bracket in expr to a number against this basis (closed forms for Gram / Weight, evaluate_bracket otherwise). Only inserts values: outer derivatives are not evaluated and deferred integrals stay compact.

Args

  • expr: sympy expression containing brackets.

  • var: bracket integration variable.

get(k)#

Return the polynomial of basis function k.

gram(i, j)#

Return the Galerkin mass-matrix entry <phi_i, phi_j> = int omega phi_i phi_j dz, from the closed form if the basis has one.

Args

  • i: row index.

  • j: column index.

eval(k, _z)#

Evaluate basis function k at _z.

at0(k)#

Return basis function k at the bottom of the layer, eval(k, bounds[0]).

at1(k)#

Return basis function k at the free surface, eval(k, bounds[1]).

eval_psi(k, _z)#

Evaluate the running integral of basis function k from the lower bound to _z.

get_lambda(k)#

Return a numeric callable of basis function k accepting scalars, lists or arrays.

plot(ax)#

Plot every basis function on bounds into the matplotlib axes ax.

reconstruct_velocity_profile(alpha, N=100)#

Return sum(alpha_i phi_i) on N equispaced points of bounds.

reconstruct_velocity_profile_at(alpha, z)#

Return sum(alpha_i phi_i) at the point z.

reconstruct_alpha(velocities, z)#

Return per-mode coefficients of sampled velocities at points z by trapezoid quadrature (assumes an orthogonal basis).

project_onto_basis(Y)#

Return the unnormalised projections int Y phi_k omega dz of the samples Y (equispaced on bounds) by trapezoid quadrature.

projection_rows(nodes, weights, samples, norm=None)#

Return one symbolic row per basis function that projects a profile sampled at fixed nodes onto the basis (discrete least squares, full inverse Gram matrix). Each row is plain arithmetic in samples, so every code printer can lower it.

Args

  • nodes: sample points zeta_j.

  • weights: quadrature weights w_j (same length).

  • samples: input symbols field(zeta_j) (same length).

  • norm: optional per-row scale, a callable of k or a sequence.

Returns

List of len(basis) sympy rows.

get_diff_basis()#

Return the z-derivatives of all basis polynomials.

class zoomy_core.model.derivation.basisfunctions.Monomials(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Monomial basis z**k (the base-class default).

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Monomials’

class zoomy_core.model.derivation.basisfunctions.LayeredBasis(inner_cls=None, inner_level=0, interfaces=None, n_layers=None, **inner_kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Multi-layer basis: an inner basis rescaled onto each of N sub-intervals and zero outside, giving N * (inner_level + 1) functions with flat index i*m + k. inner_level=0 gives piecewise constants (multi-layer SWE), Legendre_shifted multi-layer moments.

Args

  • inner_cls: per-layer Basisfunction subclass.

  • inner_level: level of the inner basis.

  • interfaces: explicit breakpoints (N + 1), in zeta or physical z.

  • n_layers: number of equal layers on [0, 1] when interfaces is not given.

References

  • Audusse et al. 2011, https://doi.org/10.1051/m2an/2010036

Initialization

Build the inner basis and the layered piecewise polynomials.

name#

‘LayeredBasis’

basis_definition()#

Return the inner functions rescaled to each layer as Piecewise, zero outside the layer.

bounds()#

Return the outer interfaces [first, last].

weight(z)#

Return the inner-basis weight.

mean_coefficients()#

Return the inner mean coefficients repeated for every layer.

flat_index(layer_idx, moment_idx)#

Map (layer_idx, moment_idx) to the flat basis index.

layer_zeta(layer_idx, z_value)#

Return the local coordinate (z_value - lower_i) / h_i in layer layer_idx.

class zoomy_core.model.derivation.basisfunctions.Legendre_shifted(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Shifted Legendre basis phi_k(z) = P_k(2z - 1) on [0, 1], orthogonal under unit weight; the standard SME moment basis.

References

  • Kowalski, Torrilhon 2019, https://doi.org/10.4208/cicp.OA-2017-0263

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Legendre_shifted’

basis_definition()#

Return legendre(k, 2z - 1), so phi_k(0) = (-1)^k at the bed and phi_k(1) = 1 at the free surface.

analytical_weighted_integral(poly_expr, var)#

Return int_0^1 poly_expr d(var) (unit weight) by antiderivative.

closed_form_bracket(name, args)#

Return Gram(i, l) = delta_il / (2l + 1) and Weight(l) = delta_l0, or None for any other bracket.

class zoomy_core.model.derivation.basisfunctions.WeightedBasis(inner, weight, level=None)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Wrap an orthogonal basis with an explicit test weight (e.g. a curvilinear metric), so projections resolve concretely. It has no delta closed forms because the wrapped family is orthogonal only under unit weight.

Args

  • inner: wrapped Basisfunction.

  • weight: weight expression in the integration variable.

  • level: basis level (default: that of inner).

Initialization

Store the wrapped basis and the weight.

name#

‘WeightedBasis’

basis_definition()#

Return the wrapped basis polynomials unchanged.

bounds()#

Return the bounds of the wrapped basis.

property weight#

Return the geometric weight.

analytical_weighted_integral(poly_expr, var)#

Return int_0^1 poly_expr * weight d(var) by antiderivative.

closed_form_bracket(name, args)#

Return None: no delta closed form under a non-unit weight.

class zoomy_core.model.derivation.basisfunctions.Chebyshevu(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Chebyshev-U basis on [-1, 1] with weight sqrt(1 - z**2) and normalisation sqrt(2/pi).

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Chebyshevu’

bounds()#

Return [-1, 1].

weight(z)#

Return sqrt(1 - z**2).

basis_definition()#

Return sqrt(2/pi) * U_k(z).

class zoomy_core.model.derivation.basisfunctions.Chebyshevu_shifted(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Chebyshev-U basis U_k(2z - 1) on [0, 1] with weight sqrt(z(1 - z)) and phi_0 = 1, orthogonal with norm pi/8.

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Chebyshevu_shifted’

bounds()#

Return [0, 1].

weight(z)#

Return sqrt(z (1 - z)).

basis_definition()#

Return U_k(2z - 1).

analytical_weighted_integral(poly_expr, var)#

Return int_0^1 poly_expr * sqrt(z(1 - z)) d(var) via U-orthogonality, or None if poly_expr is not a polynomial.

quadrature_nodes(n=None)#

Return Gauss-Chebyshev-U nodes and weights on [0, 1] for the weight sqrt(z(1 - z)).

Args

  • n: node count minus one; default 2 * (level + 1).

Returns

Tuple (nodes, weights) of arrays.

class zoomy_core.model.derivation.basisfunctions.Legendre_DN(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Legendre-based basis on [-1, 1] satisfying no-slip at the bottom z = -1 and no-stress at the top z = 1 by construction; not an SWE-limit basis.

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Legendre_DN - satifying no-slip and no-stress. This is a non-SWE basis’

bounds()#

Return [-1, 1].

basis_definition()#

Return P_k + alpha_k P_{k+1} + beta_k P_{k+2} with fixed rational alpha_k, beta_k.

class zoomy_core.model.derivation.basisfunctions.GalerkinBasis(level=0, parent='legendre', bc_bottom='slip', bc_top='nostress', slip_length=None, **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Boundary-condition-aware basis: phi_0 = 1 and phi_k recombined from parent polynomials (Legendre or Chebyshev-U) to satisfy ‘free’, ‘noslip’, ‘nostress’ or ‘slip’ conditions at bottom and top.

Args

  • level: highest basis index.

  • parent: parent family, 'legendre' or 'chebyshev'.

  • bc_bottom: condition at z = 0.

  • bc_top: condition at z = 1.

  • slip_length: slip length for 'slip' (symbolic slip_length if None).

References

  • Shen 1994, https://doi.org/10.1137/0915089

Initialization

Store the parent family and boundary conditions, then build the basis.

name#

‘GalerkinBasis’

bounds()#

Return [0, 1].

weight(z)#

Return the unit weight.

basis_definition()#

Return [1, phi_1, ...] with each phi_k solved from the linear boundary conditions (one condition: two parents, two conditions: three).

class zoomy_core.model.derivation.basisfunctions.SplineBasis(level=0, degree=1, **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Raw B-spline hat-function basis on [0, 1] with nodal coefficients and partition of unity (sum B_k = 1). Provides get_knot_spans for piecewise integration.

Args

  • level: highest basis index.

  • degree: spline degree.

Initialization

Store the spline degree, then build the basis.

name#

‘SplineBasis’

bounds()#

Return [0, 1].

weight(z)#

Return the unit weight.

basis_definition()#

Return the first level + 1 B-splines, padded with zeros.

get_knot_spans()#

Return the (a, b) intervals between consecutive distinct knots.

mean_coefficients()#

Return all ones, since B-splines are a partition of unity.

class zoomy_core.model.derivation.basisfunctions.Spline(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

Legacy B-spline basis with fixed knots; use SplineBasis instead.

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘Spline’

basis_definition(degree=1, knots=[0, 0, 0.001, 1, 1])#

Return the B-spline set of the given degree and knots.

class zoomy_core.model.derivation.basisfunctions.OrthogonalSplineWithConstant(level=0, symbol='phi', **kwargs)#

Bases: zoomy_core.model.derivation.basisfunctions.Basisfunction

B-spline basis plus a constant, orthonormalised on [0, 1] by Gram-Schmidt.

Initialization

Build the concrete basis, the opaque heads phi_fn / c_fn and the bracket cache.

name#

‘OrthogonalSplineWithConstant’

basis_definition(degree=1, knots=[0, 0, 0.5, 1, 1])#

Return the Gram-Schmidt orthonormalised basis [1] + B-splines[:-1].