Link maintenance#
This file states the maintenance rows of PyPSA's Link. It is one of the 25 whole specs of one topic each (fragments) that merge composes into the spec of examples/pypsa.yaml. Link_maint_window states that a unit is in maintenance exactly where an event it started covers the snapshot, through a sum by a relation.
given:
parameters:
Link_p_nom_extendable: { dims: [link], dtype: bool }
Link_committable: { dims: [link], dtype: bool }
Link_p_nom_mod: { dims: [link] }
Link_modules_installed: { dims: [scenario, link] }
Link_active: { dims: [snapshot, link], dtype: bool }
snapshot_weightings_generators: { dims: [snapshot] }
Link_p_nom_min: { dims: [scenario, link] }
Link_p_nom_max: { dims: [scenario, link] }
variables:
Link_status: { dims: [scenario, snapshot, link], domain: integer }
Link_p_nom_ext: { dims: [link] }
conditions:
Link_committed: { dims: [link, snapshot] }
dimensions:
scenario:
description: the futures dispatch is chosen in, each with a weight
snapshot:
description: dispatch periods
dtype: datetime
ordered: true
link:
description: controllable connections, each from one bus to the buses it delivers to
relations:
Link_maintenance_cover:
description: >-
the snapshots a maintenance event covers, by the snapshot it starts in,
data prep. In a scenario, they are the start and the snapshots after it,
until their generator weightings reach that scenario's
`maintenance_duration`. A link that is not maintainable has no rows
dims: { scenario: scenario, link: link, start: snapshot, covered: snapshot }
missing: absent
parameters:
Link_maintainable:
description: >-
whether a link must be taken off for maintenance within the horizon: in
any scenario, as PyPSA takes the union over them
(`components.py:1000-1003`)
dims: [link]
dtype: bool
Link_maintenance_pu:
description: the share of the build a maintenance event takes off
dims: [scenario, link]
Link_maintenance_events:
description: how many maintenance events occur within the horizon
dims: [scenario, link]
dtype: int
Link_maintenance_duration:
description: >-
the hours of generator weightings one maintenance event covers, PyPSA's
`maintenance_duration`. It has no value where the link is not
maintainable. No row contains it. In data prep you turn it into
`Link_maintenance_cover` and `Link_maintenance_start_blocked`. The
assumptions state that it fits the horizon
dims: [scenario, link]
missing: absent
Link_maintenance_start_blocked:
description: >-
true where no maintenance event may start, data prep. The snapshots it
would cover there run past the end of the horizon or into one the link
is not active in. It is PyPSA's `active & ~valid`, from
`maintenance_duration` and the generator weightings
dims: [scenario, snapshot, link]
dtype: bool
variables:
Link_maintenance:
description: >-
`Link-maintenance` — whether a maintainable link is in maintenance:
continuous, and one exactly where an event covers the snapshot
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_active
missing: 0
bounds:
lower: 0
upper: 1
Link_maintenance_start:
description: "`Link-maintenance_start` — whether a maintenance event starts in this snapshot"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_active
missing: 0
domain: binary
Link_maintenance_capacity:
description: >-
`Link-maintenance_capacity` — the chosen build while in maintenance,
zero otherwise: the product the `maintcap` rows linearise
dims: [scenario, snapshot, link]
where: Link_maint_ext
missing: 0
bounds:
lower: 0
Link_maintenance_status:
description: >-
`Link-maintenance_status` — the status while in maintenance, zero
otherwise: the product the `maint-status` rows linearise, so a unit in
maintenance may also be off
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND NOT (Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0))
missing: 0
bounds:
lower: 0
expressions:
Link_maintenance_modules:
description: >-
how many modules of a modular committable link can be on in
maintenance: its build cap in modules where the build is extendable,
and the modules installed where it is fixed (`constraints.py:588-594`)
dims: [scenario, link]
cases:
extendable: { when: Link_p_nom_extendable, expression: Link_p_nom_max / Link_p_nom_mod }
otherwise: Link_modules_installed
conditions:
Link_maint_ext:
description: >-
a maintainable link with an extendable build that is active in the
snapshot's period, unless it is committable and modular. These are the
maintenance rows against the chosen build
condition: >-
Link_maintainable
AND Link_p_nom_extendable
AND NOT (Link_committable AND Link_p_nom_mod > 0)
AND Link_active
constraints:
Link_maint_event_count:
description: "`Link-maint-event-count` — a maintainable link holds its number of maintenance events over the horizon"
dims: [scenario, link]
where: Link_maintainable
expression: sum(Link_maintenance_start, over=snapshot) == Link_maintenance_events
Link_maint_window:
description: >-
`Link-maint-window` — a link is in maintenance exactly where an event it
started covers the snapshot. Two events do not overlap, since the
maintenance status is at most one
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_active
expression: Link_maintenance == sum(Link_maintenance_start, over=start, by=Link_maintenance_cover[covered])
Link_maint_start_horizon:
description: "`Link-maint-start-horizon` — no event starts where it could not run its whole duration"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_active AND Link_maintenance_start_blocked
expression: Link_maintenance_start == 0
Link_maintcap_upper:
description: >-
`Link-maintcap_upper` — the build taken off is at most the chosen build in
maintenance, and at most the build less its floor out of it
dims: [scenario, snapshot, link]
where: Link_maint_ext
expression: Link_maintenance_capacity <= Link_p_nom_ext - Link_p_nom_min * (1 - Link_maintenance)
Link_maintcap_upper_nommax:
description: "`Link-maintcap_upper_nommax` — out of maintenance, no build is taken off"
dims: [scenario, snapshot, link]
where: Link_maint_ext
expression: Link_maintenance_capacity <= Link_p_nom_max * Link_maintenance
Link_maintcap_lower_nommax:
description: "`Link-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off"
dims: [scenario, snapshot, link]
where: Link_maint_ext
expression: Link_maintenance_capacity >= Link_p_nom_ext - Link_p_nom_max * (1 - Link_maintenance)
Link_maintcap_lower_nommin:
description: "`Link-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off"
dims: [scenario, snapshot, link]
where: Link_maint_ext AND Link_p_nom_min > 0
expression: Link_maintenance_capacity >= Link_p_nom_min * Link_maintenance
Link_maint_status_le_status:
description: "`Link-maint-status-le-status` — the status in maintenance is at most the status"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)
expression: Link_maintenance_status <= Link_status
Link_maint_status_le_maint:
description: "`Link-maint-status-le-maint` — out of maintenance, the status in maintenance is zero"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)
expression: Link_maintenance_status <= Link_maintenance
Link_maint_status_lb:
description: "`Link-maint-status-lb` — on and in maintenance, the status in maintenance is one"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)
expression: Link_maintenance_status >= Link_status + Link_maintenance - 1
Link_maint_modstatus_le_status:
description: "`Link-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0
expression: Link_maintenance_status <= Link_status
Link_maint_modstatus_le_maint:
description: >-
`Link-maint-modstatus-le-maint` — out of maintenance, no module is on in
maintenance. In it, at most its modules in maintenance
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0
expression: Link_maintenance_status <= Link_maintenance_modules * Link_maintenance
Link_maint_modstatus_lb:
description: "`Link-maint-modstatus-lb` — in maintenance, every module on is on in maintenance"
dims: [scenario, snapshot, link]
where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0
expression: Link_maintenance_status >= Link_status - Link_maintenance_modules * (1 - Link_maintenance)
assumptions:
Link_maintenance_events_positive:
holds: "Link_maintenance_events > 0"
where: "Link_maintainable"
description: >-
a maintainable link with no event schedules no maintenance. PyPSA
refuses it (`consistency.py:1541`)
Link_maintenance_duration_positive:
holds: "Link_maintenance_duration > 0"
where: "Link_maintainable"
description: >-
an event that covers no hours is no maintenance window. PyPSA refuses it
(`consistency.py:1531`)
Link_maintenance_duration_fits_the_horizon:
holds: "Link_maintenance_duration <= sum(snapshot_weightings_generators, over=snapshot)"
where: "Link_maintainable"
description: >-
one event longer than the horizon, in generator weightings, blocks every
start and makes the event count infeasible. PyPSA refuses it
(`consistency.py:1552`)
Link_maintenance_events_fit_the_horizon:
holds: "Link_maintenance_duration * Link_maintenance_events <= sum(snapshot_weightings_generators, over=snapshot)"
where: "Link_maintainable"
description: >-
the events together longer than the horizon, in generator weightings,
cannot all be scheduled. PyPSA refuses it (`consistency.py:1564`)
Link_maintenance_build_cap_is_finite:
holds: "Link_p_nom_max < inf"
where: "Link_maintainable AND Link_p_nom_extendable"
description: >-
the `maintcap` rows bound the chosen build in maintenance by
`p_nom_max`, so an infinite cap is an infinite coefficient. PyPSA
refuses it (`consistency.py:1576`)
Given#
| Symbol | Meaning |
|---|---|
| \(\mathrm{on}^{f}\) | Link_active over \(\mathcal{L} \times \mathcal{T}\), data another file declares |
| \(\mathrm{com}^{f}\) | Link_committable over \(\mathcal{L}\), data another file declares |
| \(\mathrm{N}^{f,\mathrm{fix}}\) | Link_modules_installed over \(\mathcal{L} \times \Xi\), data another file declares |
| \(\mathrm{ext}^{f}\) | Link_p_nom_extendable over \(\mathcal{L}\), data another file declares |
| \(\overline{\mathrm{f}}^{\mathrm{nom}}\) | Link_p_nom_max over \(\mathcal{L} \times \Xi\), data another file declares |
| \(\underline{\mathrm{f}}^{\mathrm{nom}}\) | Link_p_nom_min over \(\mathcal{L} \times \Xi\), data another file declares |
| \(\mathrm{f}^{\mathrm{mod}}\) | Link_p_nom_mod over \(\mathcal{L}\), data another file declares |
| \(\mathrm{w}^{\mathrm{gen}}\) | snapshot_weightings_generators over \(\mathcal{T}\), data another file declares |
| \(F\) | Link_p_nom_ext over \(\mathcal{L}\) |
| \(u^{f}\) | Link_status over \(\mathcal{L} \times \Xi \times \mathcal{T}\) |
| \(\mathrm{on}^{f,\mathrm{com}}\) | Link_committed over \(\mathcal{L} \times \mathcal{T}\), a condition another file defines |
Sets#
| Symbol | Meaning |
|---|---|
| \(\mathcal{L}\) | index \(l\) — link with \(\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}\), Link_maintenance_cover is absent where the data has no row — controllable connections, each from one bus to the buses it delivers to |
| \(\Xi\) | index \(\xi\) — scenario with \(\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}\), Link_maintenance_cover is absent where the data has no row — the futures dispatch is chosen in, each with a weight |
| \(\mathcal{T}\) | index \(t\) — snapshot with \(\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}\), Link_maintenance_cover is absent where the data has no row — dispatch periods |
Parameters#
| Symbol | Meaning |
|---|---|
| \(\mathrm{mnt}^{f}\) | Link_maintainable over \(\mathcal{L}\) — whether a link must be taken off for maintenance within the horizon: in any scenario, as PyPSA takes the union over them (components.py:1000-1003) |
| \(\tau^{f,\mathrm{mnt}}\) | Link_maintenance_duration over \(\mathcal{L} \times \Xi\), absent where the data has no row — the hours of generator weightings one maintenance event covers, PyPSA's maintenance_duration. It has no value where the link is not maintainable. No row contains it. In data prep you turn it into Link_maintenance_cover and Link_maintenance_start_blocked. The assumptions state that it fits the horizon |
| \(\mathrm{n}^{f,\mathrm{mnt}}\) | Link_maintenance_events over \(\mathcal{L} \times \Xi\) — how many maintenance events occur within the horizon |
| \(\gamma^{f}\) | Link_maintenance_pu over \(\mathcal{L} \times \Xi\) — the share of the build a maintenance event takes off |
| \(\mathrm{blk}^{f}\) | Link_maintenance_start_blocked over \(\mathcal{L} \times \Xi \times \mathcal{T}\) — true where no maintenance event may start, data prep. The snapshots it would cover there run past the end of the horizon or into one the link is not active in. It is PyPSA's active & ~valid, from maintenance_duration and the generator weightings |
Conditions#
| Symbol | Meaning |
|---|---|
| \(\mathrm{on}^{f,\mathrm{mnt,ext}}\) | Link_maint_ext over \(\mathcal{L} \times \mathcal{T}\) — a maintainable link with an extendable build that is active in the snapshot's period, unless it is committable and modular. These are the maintenance rows against the chosen build |
Variables#
| Symbol | Meaning |
|---|---|
| \(\mu^{f}\) | Link_maintenance over \(\mathcal{L} \times \Xi \times \mathcal{T}\), \(0\) where the mask leaves it out — Link-maintenance — whether a maintainable link is in maintenance: continuous, and one exactly where an event covers the snapshot |
| \(\mu^{f,\mathrm{nom}}\) | Link_maintenance_capacity over \(\mathcal{L} \times \Xi \times \mathcal{T}\), \(0\) where the mask leaves it out — Link-maintenance_capacity — the chosen build while in maintenance, zero otherwise: the product the maintcap rows linearise |
| \(\mu^{f,\mathrm{up}}\) | Link_maintenance_start over \(\mathcal{L} \times \Xi \times \mathcal{T}\), \(0\) where the mask leaves it out — Link-maintenance_start — whether a maintenance event starts in this snapshot |
| \(\mu^{f,u}\) | Link_maintenance_status over \(\mathcal{L} \times \Xi \times \mathcal{T}\), \(0\) where the mask leaves it out — Link-maintenance_status — the status while in maintenance, zero otherwise: the product the maint-status rows linearise, so a unit in maintenance may also be off |
Definitions#
| Symbol | Meaning |
|---|---|
| \(\mathrm{Link\_maintenance\_modules}\) | Link_maintenance_modules over \(\mathcal{L} \times \Xi\) — how many modules of a modular committable link can be on in maintenance: its build cap in modules where the build is extendable, and the modules installed where it is fixed (constraints.py:588-594) |
Conditions#
Link_maint_ext
Variable domains#
Link_maintenance
Link_maintenance_capacity
Link_maintenance_start
Link_maintenance_status
Definitions#
Link_maintenance_modules
Subject to#
Link_maint_event_count
Link_maint_modstatus_lb
Link_maint_modstatus_le_maint
Link_maint_modstatus_le_status
Link_maint_start_horizon
Link_maint_status_lb
Link_maint_status_le_maint
Link_maint_status_le_status
Link_maint_window
Link_maintcap_lower_nommax
Link_maintcap_lower_nommin
Link_maintcap_upper
Link_maintcap_upper_nommax
Assumptions#
Link_maintenance_build_cap_is_finite
Link_maintenance_duration_fits_the_horizon
Link_maintenance_duration_positive
Link_maintenance_events_fit_the_horizon
Link_maintenance_events_positive
See also
- PyPSA in 25 files, for how the fragments compose
- PyPSA in one file, for the same spec as one file, rung by rung