zoomy_core.model.equation

zoomy_core.model.equation#

Equation primitives — Term, _TermGroup, Equation.

Direct port of the framework developed in the transparent-derivation notebooks (thesis/notebooks/legacy/modeling/transparent_derivations/ sme_clean.py etc.). Same classes, same auto-history mechanics, same simplify pipeline (sp.expand → pull var-independent factors out of Derivative atoms → recover fluxes by pulling var-independent coeffs back inside Derivative arguments).

Lives in its own module so the Model class (in basemodel.py) and the derivation subclasses (sigmaref.py, sme.py, vam.py) can import Equation without dragging in the full operations / state surface.

Module Contents#

Classes#

Term

One additive term of an Equation.

Equation

Linear list of Term carrying the residual of one PDE/algebraic equation. apply delegates to Expression.apply (the library operation-dispatch layer) and auto-records a history entry on the parent Model if one is set.

API#

class zoomy_core.model.equation.Term(expr, tag=None, parent=None)#

One additive term of an Equation.

Initialization

apply(*args, **kwargs)#
class zoomy_core.model.equation.Equation(expression, name='eq', model=None)#

Bases: zoomy_core.model.operations.RelationMixin

Linear list of Term carrying the residual of one PDE/algebraic equation. apply delegates to Expression.apply (the library operation-dispatch layer) and auto-records a history entry on the parent Model if one is set.

Via RelationMixin an Equation can be ORIENTED — built from sp.Eq(lhs, rhs) or produced by solve_for — in which case it carries _as_relation = {lhs: rhs} and acts as a substitution under .apply (with .lhs / .rhs / .subs_map). That is what replaces the former Substitution / Relation classes.

Initialization

property solver_tags#

Dict of solver tags (canonical names) → sub-expression, or empty dict if none set.

get_solver_tag(name)#

Return the sp.Expr for a solver tag, or None if not set. name is normalised through canonical_solver_tag.

untagged_remainder()#

Return self.expr - sum(solver_tags.values()), simplified. Zero ⇒ every term has been routed to a solver tag; non-zero drives collect_solver_tag’s untagged_policy.

static to_terms(expression)#
static to_expression(terms)#
property expr#
property terms#
property term#

ADDITIVE-TERM accessor — eq.term[i] (one term), eq.term[i, j] / eq.term[[i, j]] (a term group). Each view’s .apply(op) rewrites ONLY those terms back into this equation.

Disambiguated from [l] MOMENT access (MomentFamily / VectorEquation): a scalar Equation is no longer term-indexable via bare eq[i] — use eq.term[i].

apply(*args, **kwargs)#
simplify()#

Canonical form (three sub-steps):

  1. sp.expand — flatten Mul/Add nesting and combine like terms.

  2. Pull var-independent factors out of every Derivative argument: Derivative(g·h, x) → g·Derivative(h, x), Derivative(0, x) → 0.

  3. Recover fluxes — for each term c · Derivative(_, x) where c is var-independent, pull c back inside so the tagger sees the conservative atom.

solve_for(symbol)#

Algebraically isolate symbol from this equation’s residual (self.expr == 0); returns a NEW oriented Equation symbol = solved-expr (carrying _as_relation = {symbol: sol}).

The result stays an Equation — pass it straight to .apply and it acts as the substitution symbol -> sol (.lhs / .rhs / .subs_map expose the rule). This is what the old Substitution return value did, with no separate class.

Pure algebra — solve_for does not integrate. If symbol appears under a Derivative the residual is differential in it; integrate the balance first (e.g. eq.apply(Integrate(var, lo, hi)) followed by a boundary-condition substitution) and then solve_for the resulting algebraic relation.

remove()#

Delete this equation from its parent model (triggers Q refresh).

describe(strip_args=False, header=True, show_tags=False)#

Render this equation as a Description.

Terms print in their current order (so a SortByTag shows). An oriented equation (from solve_for / sp.Eq) renders lhs = rhs rather than residual = 0. show_tags=True underbraces each physics-tag group.

describe_line(strip_args=False, bullet=False, show_tags=False)#

One-line markdown render (used by Model.describe). An oriented equation renders as lhs = rhs; a plain residual as … = 0 with terms in their current order. show_tags underbraces each tag group (same render as describe).