Skip to content

Unify as_dataarray coords semantics with _as_dataarray_in_coords #723

@FBumann

Description

@FBumann

Follow-up to #722 (which closes #706 and #709).

#722 introduces linopy.model._as_dataarray_in_coords as a localized helper for add_variables: when coords is provided, the result is guaranteed to live in coords (dims, order, and values). Internally it converts the input to a DataArray, validates dims/coords against coords, expands missing dims, and transposes.

The underlying inconsistency it works around lives in linopy.common.as_dataarray, whose coords argument means four different things depending on the input type:

input what coords does today
scalar / list / int / float broadcasts to full coords
numpy.ndarray labels positional axes
pandas.Series / DataFrame ignored — dims come only from axis names
xarray.DataArray ignored — input returned unchanged

The new rule from #722 is uniform: the result lives in coords, regardless of input type. This issue tracks unifying as_dataarray around that rule and deleting _as_dataarray_in_coords.

Why this wasn't part of #722

as_dataarray is called from ~12 sites across expressions.py, variables.py, and model.py (mask, sign, rhs). Tightening its semantics globally risks regressions and benefits from an audit pass rather than being bundled into a bug-fix PR.

Call sites to audit

  • linopy/model.pymask in add_variables / add_constraints (currently relies on broadcast_mask after the conversion), sign / rhs in add_constraints.
  • linopy/expressions.py (lines 341, 584, 613, 1105, 1668, 2002, 2030, 2154, 2289) — arithmetic ops pass coords=self.coords, dims=self.coord_dims to align an input against the expression's coords. The new rule would raise on extra dims; could surface latent bugs or break working code.
  • linopy/variables.py:330, 1369.

Open questions

  1. Strict by default vs opt-in. Make the new rule the default and add a strict=False escape, or add strict=True and migrate call sites one by one?
  2. Performance. as_dataarray is hot. The validate/expand/transpose path is O(ndim) in the metadata-only case, but the validation loop still runs. Worth benchmarking model.solve() end-to-end on a representative workload before deciding.
  3. Error surface. _as_dataarray_in_coords raises ValueError for extra dims and coord-value mismatches. Should as_dataarray raise the same way, or should the error type be configurable per call site?

Scope when picked up

  • Move the body of _as_dataarray_in_coords into common.py (or merge into as_dataarray).
  • Audit each call site listed above, decide strict vs lax per site, and add tests pinning the chosen behavior.
  • Delete _as_dataarray_in_coords from model.py.
  • Benchmark before/after on a model where add_variables / arithmetic dominates.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    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