Skip to content

Enforce the ND<->units boundary: evaluate/global_evaluate should reject or nondimensionalise UnitAwareArray input #279

Description

@lmoresi

Background

Per the ND<->units boundary contract (added with #267/#278): the DM/PETSc/solver layer is non-dimensional-only; units live above it in the MeshVariable API.

Today that boundary is convention, not enforced, and there is a silent trap: uw.function.evaluate / global_evaluate strip the UnitAwareArray subclass with np.array() but keep the numeric value. So a dimensional coordinate array (.coords ≈ 1e9 m) passed in is kept as 1e9 and located against a 0..1000 ND DM — no exception, wrong location, wrong answer.

This is exactly how #267 slipped in (the SL trace-back fed dimensional .coords into the ND DM). #277 fixed that one call site, but the same class of mistake can recur anywhere a developer reaches for .coords/.array instead of .coords_nd/.data.

Proposal

Make the ND entry points guard the boundary instead of silently stripping:

  • uw.function.evaluate / global_evaluate: if handed a UnitAwareArray for the query coordinates (or a unit-bearing expression where ND is expected), either
    • reject it with a clear error ('pass non-dimensional coordinates — use mesh.X.coords_nd / var.coords_nd, or uw.non_dimensionalise(...)'), or
    • correctly non-dimensionalise it (not just strip the label) before locating.
  • Consider the same guard on the DM coordinate setters / any other ND entry point.

Rejecting is the safer default (forces the caller to be explicit); auto-nondimensionalising is more convenient but hides the boundary. Prefer reject-with-actionable-message unless there's a strong ergonomic case.

Acceptance

A regression test that passing a dimensional UnitAwareArray of coordinates to evaluate/global_evaluate no longer silently mislocates (errors clearly, or returns the correctly-located result).

Tracked from the #267 boundary-contract discussion.

Underworld development team with AI support from Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions