Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions doc/migrating-to-v1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ Every row is a legacy guess that becomes an explicit rule under v1. The
- Raises (``join="exact"`` — no silent reindex).
- ``.sortby(dim)`` / ``.reindex`` one side to match, or a reindexing
``join=`` (``"outer"`` / ``"inner"`` / ``"left"`` / ``"right"``).
* - An **unlabeled** operand (numpy array, list, polars ``Series``)
- Pairs with the linopy operand's dimensions by *size*; an ambiguous
match (a square array, or two dimensions of equal length) or no size
match raises rather than guessing.
- Wrap it in a ``DataArray`` / ``Series`` / ``DataFrame`` with named
dimensions so it aligns by label.
* - A **masked / absent** variable in arithmetic
- Absence propagates (the slot stays absent) instead of counting as ``0``.
- Decide the intent: ``.fillna(0)`` to keep the old "treat as zero", or
Expand All @@ -107,14 +113,24 @@ Every row is a legacy guess that becomes an explicit rule under v1. The
- Raises instead of silently dropping one.
- ``.drop_vars(name)`` to remove the coord, or ``.assign_coords(name=...)``
to relabel one side.
* - A first-class ``pd.MultiIndex`` **dimension**
- Rejected; v1 uses a flat dimension with the levels as aux coords.
- ``.reset_index(dim)`` to flatten before building the model.
* - A first-class ``pd.MultiIndex`` **dimension** — and a per-*level* input
onto it (e.g. per-``period`` bounds onto a ``(period, timestep)``
``snapshot``)
- Rejected; v1 uses a flat dimension with the levels as aux coords, and a
per-level input must be mapped onto the flat dimension explicitly (no
implicit projection). Affects PyPSA multi-investment models.
- ``.reset_index(dim)`` to flatten, then project the per-level input by
its level aux coord.
* - A multi-key ``groupby(...).sum()`` result
- A flat ``group`` dimension with the keys as aux coords (not a stacked
``group`` MultiIndex).
- Select on the key aux coords; convert an existing result with
``.reset_index("group")``.
* - A ``groupby`` grouper (``Series`` / ``DataArray`` / ``DataFrame`` /
coord name) with a differing label set or order
- Raises — the grouper aligns to the grouped dimension by label, never
by position.
- ``.sortby`` / ``.reindex`` the grouper to the dimension's labels.

The full, normative rule list lives in the
`arithmetic convention <https://github.com/PyPSA/linopy/blob/master/arithmetics-design/convention.md>`_.
Expand Down
2 changes: 2 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ Upcoming Version
* A new, stricter convention for how linopy arithmetic aligns coordinates and treats missing data is available behind ``linopy.options["semantics"] = "v1"``. Legacy behaviour remains the **default** in this release; v1 is opt-in. In short, under v1:

* shared dimensions align by label with ``join="exact"`` — a differing label set *or* a pure reorder (same labels, different order) raises instead of silently filling, dropping, or pairing by position. Resolve explicitly with ``.sel`` / ``.reindex`` / ``.assign_coords``, or pass an explicit ``join=`` to the named ``.add`` / ``.sub`` / ``.mul`` / ``.div`` / ``.le`` / ``.ge`` / ``.eq`` methods.
* an *unlabeled* operand (a numpy array, list, or polars ``Series``) pairs with the linopy operand's dimensions by size; an ambiguous match (a square array, or two equal-length dimensions) or no size match raises instead of guessing. Wrap it in a ``DataArray`` to name the dimensions. (https://github.com/PyPSA/linopy/issues/736)
* a ``NaN`` in a user-supplied constant raises, rather than being silently filled (with a value that used to differ per operator).
* *absence* — masked, reindexed, or shifted-in slots — is a first-class state that propagates through every operator, instead of collapsing to zero.
* conflicting auxiliary coordinates raise, instead of being silently dropped.
* a first-class ``pd.MultiIndex`` dimension is rejected in favour of a flat dimension with the levels as auxiliary coordinates.
* a ``groupby`` grouper aligns to the grouped dimension by label — a grouper whose labels differ in set or order from the dimension raises instead of being matched positionally, and a multi-key grouper yields a flat ``group`` dimension (keys as aux coords) rather than a stacked ``group`` MultiIndex. (https://github.com/PyPSA/linopy/issues/827)

* Every operation whose result changes under v1 emits a ``LinopySemanticsWarning`` under legacy, naming the fix — so a model can be migrated incrementally before opting in. The full rules are specified in `the arithmetic convention <https://github.com/PyPSA/linopy/blob/master/arithmetics-design/convention.md>`_.

Expand Down