Issue Description
Follow-up to #450 (partially fixed by #614).
After #614, add_variables correctly applies the full dimensionality from coords even when the lower/upper bounds are DataArrays missing some of those dimensions. However, the dimension order of the resulting variable depends on the type of the bounds rather than on coords:
- If at least one bound is a scalar (
int/float), the variable follows the coords order.
- If both bounds are
DataArrays missing the same dimension, that dimension gets prepended instead of placed in coords order.
This is inconsistent and surprising — the variable's dimension order should always match coords.
Reproducible Example
import xarray as xr
import numpy as np
import linopy
m = linopy.Model()
test = xr.DataArray(np.random.rand(3, 2), [("x", ["a", "b", "c"]), ("y", ["X", "Y"])])
# Scalar lower bound -> dims follow coords order: ('x', 'y')
foo = m.add_variables(lower=0, upper=test.sum("y"), coords=test.coords, name="foo")
print("foo:", foo.dims) # ('x', 'y')
# Both bounds are DataArrays missing 'y' -> 'y' is prepended: ('y', 'x')
bar = m.add_variables(lower=-test.sum("y"), upper=test.sum("y"), coords=test.coords, name="bar")
print("bar:", bar.dims) # ('y', 'x') <-- wrong
Output:
foo: ('x', 'y')
bar: ('y', 'x')
Expected Behavior
Both foo and bar should have dimensions in the order given by coords, i.e. ('x', 'y').
Root Cause
In linopy/model.py, _validate_dataarray_bounds expands missing dimensions with arr.expand_dims(expand). DataArray.expand_dims prepends new dimensions by default, so a bound with dims ('x',) becomes ('y', 'x') instead of ('x', 'y'). When only one bound is a scalar, as_dataarray/xr.broadcast happens to recover the coords order, which masks the bug — hence the type-dependent inconsistency.
A fix would transpose the expanded array back to the coords dimension order after expand_dims.
Installed Versions
linopy 0.7.0.post1.dev18+ged594d7fb (current master, commit ed594d7).
Issue Description
Follow-up to #450 (partially fixed by #614).
After #614,
add_variablescorrectly applies the full dimensionality fromcoordseven when thelower/upperbounds areDataArrays missing some of those dimensions. However, the dimension order of the resulting variable depends on the type of the bounds rather than oncoords:int/float), the variable follows thecoordsorder.DataArrays missing the same dimension, that dimension gets prepended instead of placed incoordsorder.This is inconsistent and surprising — the variable's dimension order should always match
coords.Reproducible Example
Output:
Expected Behavior
Both
fooandbarshould have dimensions in the order given bycoords, i.e.('x', 'y').Root Cause
In
linopy/model.py,_validate_dataarray_boundsexpands missing dimensions witharr.expand_dims(expand).DataArray.expand_dimsprepends new dimensions by default, so a bound with dims('x',)becomes('y', 'x')instead of('x', 'y'). When only one bound is a scalar,as_dataarray/xr.broadcasthappens to recover thecoordsorder, which masks the bug — hence the type-dependent inconsistency.A fix would transpose the expanded array back to the
coordsdimension order afterexpand_dims.Installed Versions
linopy
0.7.0.post1.dev18+ged594d7fb(currentmaster, commit ed594d7).