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.py — mask 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
- 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?
- 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.
- 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.
Follow-up to #722 (which closes #706 and #709).
#722 introduces
linopy.model._as_dataarray_in_coordsas a localized helper foradd_variables: whencoordsis provided, the result is guaranteed to live incoords(dims, order, and values). Internally it converts the input to aDataArray, validates dims/coords againstcoords, expands missing dims, and transposes.The underlying inconsistency it works around lives in
linopy.common.as_dataarray, whosecoordsargument means four different things depending on the input type:coordsdoes todaycoordsnumpy.ndarraypandas.Series/DataFramexarray.DataArrayThe new rule from #722 is uniform: the result lives in
coords, regardless of input type. This issue tracks unifyingas_dataarrayaround that rule and deleting_as_dataarray_in_coords.Why this wasn't part of #722
as_dataarrayis called from ~12 sites acrossexpressions.py,variables.py, andmodel.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.py—maskinadd_variables/add_constraints(currently relies onbroadcast_maskafter the conversion),sign/rhsinadd_constraints.linopy/expressions.py(lines 341, 584, 613, 1105, 1668, 2002, 2030, 2154, 2289) — arithmetic ops passcoords=self.coords, dims=self.coord_dimsto 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
strict=Falseescape, or addstrict=Trueand migrate call sites one by one?as_dataarrayis hot. The validate/expand/transpose path is O(ndim) in the metadata-only case, but the validation loop still runs. Worth benchmarkingmodel.solve()end-to-end on a representative workload before deciding._as_dataarray_in_coordsraisesValueErrorfor extra dims and coord-value mismatches. Shouldas_dataarrayraise the same way, or should the error type be configurable per call site?Scope when picked up
_as_dataarray_in_coordsintocommon.py(or merge intoas_dataarray)._as_dataarray_in_coordsfrommodel.py.add_variables/ arithmetic dominates.