Skip to content

A uw.function.expression whose value is zero is folded out of expressions by sympy at construction, so a runtime constant that starts at zero never updates #696

Description

@lmoresi

What happens

UWexpression reports is_zero, is_positive and is_negative from its current value (expressions.py, the assumption properties delegate to self._sym). Sympy uses those assumptions in automatic evaluation, so an expression whose value is zero when a formula is built is evaluated away before any JIT sees it, and changing the value later has no effect:

t = uw.function.expression(r"t", 0.0, "time")
F = sympy.exp(-0.02 * t)                                   # exp(-0.02*t): survives on its own
U = sympy.Matrix([[-sympy.sin(x) * sympy.cos(y) * F, 0]])   # -> -sin(x)*cos(y): F is gone
(-0.02 * t).is_zero                                         # True, from the value

A solver boundary condition built this way is frozen at the value it had at construction. With c = expression("c", 0.0) and a lid velocity exp(-c) * x * (1 - x), the Stokes and Navier-Stokes solvers keep the lid at exp(0) after c.sym = 2.0; with c created at 1.0 the same code follows the value exactly. We found it on the Taylor-Green vortex benchmark, where a time-dependent exact Dirichlet velocity built from a time expression created at t = 0 gave the same 4.7e-3 error on 1/16, 1/32 and 1/64 meshes at every time step, with the decay 10% too slow; freezing the time deliberately gave the identical answer to four digits.

The same folding will hit any formula in which a runtime constant multiplies or feeds a function that sympy evaluates on a zero argument (Mul, exp, Pow, Piecewise conditions): a body force, a source, a ramped boundary value, all of which naturally start at zero.

Where

src/underworld3/function/expressions.py, the is_zero / is_positive / is_negative / is_finite properties (added in 9b738ea for the units work). is_comparable was already made unconditionally False for a related reason (#415: Max/Min tried to compare the contents).

Not patched here

Reported rather than changed: the assumption properties may be relied on elsewhere (the rotated free-slip path tests sympify(conds).is_zero, and possibly the units and non-dimensionalisation code), so the choice of what a runtime constant should advertise to sympy is a design decision. The Taylor-Green driver works around it by creating the time expression at a non-zero value.

🤖 Generated with Claude Code

https://claude.ai/code/session_018T2VHUGaZiQVJ95qQ4DiSL

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions