linopy.model.Model.add_variables

linopy.model.Model.add_variables#

Model.add_variables(lower=-inf, upper=inf, coords=None, name=None, mask=None, binary=False, integer=False, semi_continuous=False, **kwargs)#

Assign a new, possibly multi-dimensional array of variables to the model.

Variables may be added with lower and/or upper bounds. Unless a coords argument is provided, the shape of the lower and upper bounds define the number of variables which will be added to the model under the name name.

Parameters:
  • lower (float/array_like, optional) – Lower bound of the variable(s). Ignored if binary is True. The default is -inf.

  • upper (TYPE, optional) – Upper bound of the variable(s). Ignored if binary is True. The default is inf.

  • coords (list/dict/xarray.Coordinates, optional) – The coords of the variable array. When provided with named dimensions (a Mapping, xarray.Coordinates, a sequence of named pd.Index objects, or an unnamed sequence paired with dims= in **kwargs), coords is the source of truth for the variable’s dimensions, order, and values. lower, upper and mask are aligned to this contract:

    • dims of every bound must be a subset of coords.dims; extra dims raise ValueError;

    • dim order in the variable always follows coords;

    • shared-dim coordinate values must equal coords; same values in a different order are auto-reindexed, different value sets raise ValueError;

    • dims listed in coords but missing from a bound are broadcast to coords shape.

    One optimization variable is added per combination of coordinates. The default is None, in which case the shape is inferred from the bounds.

  • name (str, optional) – Reference name of the added variables. The default None results in a name like “var1”, “var2” etc.

  • mask (array_like, optional) – Boolean mask with False values for variables which are skipped. The shape of the mask has to match the shape the added variables. Default is None.

  • binary (bool) – Whether the new variable is a binary variable which are used for Mixed-Integer problems.

  • integer (bool) – Whether the new variable is a integer variable which are used for Mixed-Integer problems.

  • semi_continuous (bool) – Whether the new variable is a semi-continuous variable. A semi-continuous variable can take the value 0 or any value between its lower and upper bounds. Requires a positive lower bound.

  • **kwargs – Additional keyword arguments are passed to the DataArray creation.

Raises:

ValueError – If neither lower bound and upper bound have coordinates, nor coords are directly given.

Returns:

linopy.Variable – Variable which was added to the model.

Examples

>>> from linopy import Model
>>> import pandas as pd
>>> m = Model()
>>> time = pd.RangeIndex(10, name="Time")
>>> m.add_variables(lower=0, coords=[time], name="x")
Variable (Time: 10)
-------------------
[0]: x[0] ∈ [0, inf]
[1]: x[1] ∈ [0, inf]
[2]: x[2] ∈ [0, inf]
[3]: x[3] ∈ [0, inf]
[4]: x[4] ∈ [0, inf]
[5]: x[5] ∈ [0, inf]
[6]: x[6] ∈ [0, inf]
[7]: x[7] ∈ [0, inf]
[8]: x[8] ∈ [0, inf]
[9]: x[9] ∈ [0, inf]

Strict coords-as-truth: a bound with an extra dim raises.

>>> import xarray as xr
>>> m = Model()
>>> bad = xr.DataArray(
...     [[1.0, 2.0, 3.0]] * 2,
...     dims=["extra", "x"],
...     coords={"x": [0, 1, 2]},
... )
>>> m.add_variables(lower=bad, coords=[pd.Index([0, 1, 2], name="x")], name="v")
Traceback (most recent call last):
...
ValueError: lower bound has dimension(s) ['extra'] not declared in coords ...

Strict coords-as-truth: a bound whose shared-dim values don’t match raises.

>>> m = Model()
>>> wrong = xr.DataArray(
...     [1.0, 2.0, 3.0], dims=["x"], coords={"x": [10, 20, 30]}
... )
>>> m.add_variables(
...     lower=wrong, coords=[pd.Index([0, 1, 2], name="x")], name="v"
... )
Traceback (most recent call last):
...
ValueError: lower bound: coordinate values for dimension 'x' do not match coords ...

Strict coords-as-truth, helpful side: a bound whose coord values match coords only in a different order is auto-reindexed.

>>> m = Model()
>>> reordered = xr.DataArray(
...     [3.0, 1.0, 2.0], dims=["x"], coords={"x": ["c", "a", "b"]}
... )
>>> v = m.add_variables(
...     lower=reordered,
...     coords=[pd.Index(["a", "b", "c"], name="x")],
...     name="r",
... )
>>> v.lower.values.tolist()
[1.0, 2.0, 3.0]

Unnamed-coords sequence + dims= opts into the same strict enforcement as a named index — extra dims still raise.

>>> m = Model()
>>> m.add_variables(lower=bad, coords=[[0, 1, 2]], dims=["x"], name="w")
Traceback (most recent call last):
...
ValueError: lower bound has dimension(s) ['extra'] not declared in coords ...

The same strict contract applies to mask (including with coords=[[...]], dims=[...]).

>>> m = Model()
>>> m.add_variables(mask=bad, coords=[[0, 1, 2]], dims=["x"], name="wm")
Traceback (most recent call last):
...
ValueError: mask has dimension(s) ['extra'] not declared in coords ...