From d1da8cf889bbd235fa345088f68d8f220a2bf204 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 15:31:54 +0000 Subject: [PATCH 1/3] docs(pypsa): a PyPSA schedule, weight or limit that the data leaves out is absent rather than zero Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf --- CHANGELOG.md | 1 + docs/examples/pypsa.md | 170 ++++++++++++------- docs/examples/pypsa/carrier.md | 4 +- docs/examples/pypsa/cost.md | 4 +- docs/examples/pypsa/generator.md | 20 +-- docs/examples/pypsa/generator_commitment.md | 21 ++- docs/examples/pypsa/generator_maintenance.md | 4 +- docs/examples/pypsa/generator_ramping.md | 16 +- docs/examples/pypsa/line.md | 28 +-- docs/examples/pypsa/link.md | 20 +-- docs/examples/pypsa/link_commitment.md | 21 ++- docs/examples/pypsa/link_maintenance.md | 4 +- docs/examples/pypsa/link_ramping.md | 16 +- docs/examples/pypsa/process.md | 12 +- docs/examples/pypsa/process_commitment.md | 21 ++- docs/examples/pypsa/process_maintenance.md | 4 +- docs/examples/pypsa/process_ramping.md | 16 +- docs/examples/pypsa/security.md | 8 +- docs/examples/pypsa/storage_unit.md | 32 ++-- docs/examples/pypsa/store.md | 24 +-- docs/examples/pypsa/transformer.md | 20 +-- examples/pypsa.yaml | 143 +++++++++------- examples/pypsa/carrier.yaml | 2 +- examples/pypsa/cost.yaml | 2 +- examples/pypsa/generator.yaml | 10 +- examples/pypsa/generator_commitment.yaml | 11 +- examples/pypsa/generator_maintenance.yaml | 2 +- examples/pypsa/generator_ramping.yaml | 8 +- examples/pypsa/line.yaml | 14 +- examples/pypsa/link.yaml | 10 +- examples/pypsa/link_commitment.yaml | 11 +- examples/pypsa/link_maintenance.yaml | 2 +- examples/pypsa/link_ramping.yaml | 8 +- examples/pypsa/process.yaml | 6 +- examples/pypsa/process_commitment.yaml | 11 +- examples/pypsa/process_maintenance.yaml | 2 +- examples/pypsa/process_ramping.yaml | 8 +- examples/pypsa/security.yaml | 4 +- examples/pypsa/storage_unit.yaml | 16 +- examples/pypsa/store.yaml | 12 +- examples/pypsa/transformer.yaml | 10 +- 41 files changed, 453 insertions(+), 305 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fecf921f..1e049881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ it releases that version ([RELEASING.md](https://github.com/energy-models/mathsp ## Upcoming version +- docs(pypsa): a PyPSA schedule, weight or limit that the data leaves out is absent rather than zero, and a committable extendable unit is assumed to have its big-M ([#PR](https://github.com/energy-models/mathspec/pull/PR)) - feat(language)!: a missing row reads as the value the file names, and `missing: neutral` is gone ([#894](https://github.com/energy-models/mathspec/pull/894)) - docs: the changelog is listed under Reference rather than About ([#895](https://github.com/energy-models/mathspec/pull/895)) - docs(pypsa): an extendable unit has a capacity to choose exactly where its active flag is set, as in PyPSA ([#886](https://github.com/energy-models/mathspec/pull/886)) diff --git a/docs/examples/pypsa.md b/docs/examples/pypsa.md index 19fba0fc..3e4d9dd0 100644 --- a/docs/examples/pypsa.md +++ b/docs/examples/pypsa.md @@ -5509,10 +5509,10 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{(2)}`$ | `Generator_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — cost of the square of one unit of output | | $`\mathrm{sgn}`$ | `Generator_sign` over $`\mathcal{G}`$ — the sign output enters its bus's balance with — PyPSA's `sign`, `1` unless given, `-1` for a unit that draws power. PyPSA refuses one that differs by scenario (`constants.py:43`) | | $`\mathrm{com}`$ | `Generator_committable` over $`\mathcal{G}`$ — whether output is gated by an on/off status decision | -| $`\mathrm{ru}`$ | `Generator_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}`$ | `Generator_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{ru}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — most output in the snapshot a unit starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{\mathrm{dn}}`$ | `Generator_ramp_limit_shut_down` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}`$ | `Generator_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}`$ | `Generator_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{ru}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — most output in the snapshot a unit starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{\mathrm{dn}}`$ | `Generator_ramp_limit_shut_down` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit | | $`\mathrm{UT}`$ | `Generator_min_up_time` over $`\Xi \times \mathcal{G}`$ — least snapshots a unit stays on once started | | $`\mathrm{DT}`$ | `Generator_min_down_time` over $`\Xi \times \mathcal{G}`$ — least snapshots a unit stays off once stopped | | $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\Xi \times \mathcal{G}`$ — one where the unit was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | @@ -5524,15 +5524,15 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{\mathrm{on}}`$ | `Generator_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — cost of one snapshot spent on | | $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{N}^{\mathrm{fix}}`$ | `Generator_modules_installed` over $`\Xi \times \mathcal{G}`$ — how many whole modules a committable build has in place: `Generator_p_nom / Generator_p_nom_mod` where a fixed build is modular, one where it is not, data prep. PyPSA refuses a fixed modular build whose nominal power is not a whole number of modules | -| $`\mathrm{M}`$ | `Generator_big_m` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — the bound a committed extendable generator's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep | +| $`\mathrm{M}`$ | `Generator_big_m` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — the bound a committed extendable generator's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep | | $`\mathrm{nonneg}`$ | `Generator_p_min_pu_nonneg` over $`\mathcal{G}`$ — true where none of the generator's own minimums-per-unit is negative — PyPSA's per-unit `(p_min_pu >= 0).all()` over every snapshot and scenario, data prep | | $`\mathrm{mnt}`$ | `Generator_maintainable` over $`\mathcal{G}`$ — whether a generator must be taken off for maintenance within the horizon — in any scenario, as PyPSA takes the union over them (`components.py:1016-1019`) | | $`\gamma`$ | `Generator_maintenance_pu` over $`\Xi \times \mathcal{G}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\Xi \times \mathcal{G}`$ — how many maintenance events the horizon holds | -| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the generator is not maintainable. No row reads it: data prep turns it into `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the generator is not maintainable. No row reads it: data prep turns it into `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}`$ | `Generator_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the generator does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | -| $`\mathrm{ru}^{f}`$ | `Link_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{ru}^{f}`$ | `Link_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | | $`\mathrm{f}^{\mathrm{nom}}`$ | `Link_p_nom` over $`\Xi \times \mathcal{L}`$ — nominal power | | $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$ — whether the nominal power is a decision | | $`\underline{\mathrm{f}}`$ | `Link_p_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — least flow, per unit of nominal power — negative for a link that carries both ways | @@ -5543,8 +5543,8 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{f}`$ | `Link_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of one unit of flow | | $`\mathrm{c}^{f,(2)}`$ | `Link_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of the square of one unit of flow | | $`\mathrm{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$ — whether flow is gated by an on/off status decision | -| $`\mathrm{ru}^{f,\mathrm{up}}`$ | `Link_ramp_limit_start_up` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — most flow in the snapshot a link starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{f,\mathrm{dn}}`$ | `Link_ramp_limit_shut_down` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}^{f,\mathrm{up}}`$ | `Link_ramp_limit_start_up` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — most flow in the snapshot a link starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{f,\mathrm{dn}}`$ | `Link_ramp_limit_shut_down` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit | | $`\mathrm{UT}^{f}`$ | `Link_min_up_time` over $`\Xi \times \mathcal{L}`$ — least snapshots a link stays on once started | | $`\mathrm{DT}^{f}`$ | `Link_min_down_time` over $`\Xi \times \mathcal{L}`$ — least snapshots a link stays off once stopped | | $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\Xi \times \mathcal{L}`$ — one where the link was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | @@ -5556,12 +5556,12 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{f,\mathrm{on}}`$ | `Link_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of one snapshot spent on | | $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{N}^{f,\mathrm{fix}}`$ | `Link_modules_installed` over $`\Xi \times \mathcal{L}`$ — how many whole modules a committable build has in place: `Link_p_nom / Link_p_nom_mod` where a fixed build is modular, one where it is not, data prep. PyPSA refuses a fixed modular build whose nominal power is not a whole number of modules | -| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — the bound a committed extendable link's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep | +| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — the bound a committed extendable link's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep | | $`\mathrm{nonneg}^{f}`$ | `Link_p_min_pu_nonneg` over $`\mathcal{L}`$ — true where none of the link's own minimums-per-unit is negative — PyPSA's per-unit `(p_min_pu >= 0).all()` over every snapshot and scenario, data prep | | $`\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:1016-1019`) | | $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\Xi \times \mathcal{L}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\Xi \times \mathcal{L}`$ — how many maintenance events the horizon holds | -| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the link is not maintainable. No row reads it: data prep turns it into `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the link is not maintainable. No row reads it: data prep turns it into `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}^{f}`$ | `Link_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the link does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | | $`\mathrm{z}^{\mathrm{nom}}`$ | `Process_p_nom` over $`\Xi \times \mathcal{J}`$ — nominal internal power | | $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$ — whether the nominal internal power is a decision | @@ -5572,16 +5572,16 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{cyc}^{z}`$ | `Process_output_cyclic_delay` over $`\mathcal{R}`$ — whether a delayed port's transfer wraps from the end of its investment period — PyPSA's `cyclic_delay0`, `cyclic_delay1`, …; where it does not, the energy still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | | $`\mathrm{c}^{z}`$ | `Process_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one unit of internal power | | $`\mathrm{c}^{z,(2)}`$ | `Process_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of the square of one unit of internal power | -| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — a given internal power schedule; a process without one has no row here | +| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — a given internal power schedule; a process without one has no row here | | $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\Xi \times \mathcal{J}`$ — least nominal power an extendable process may be built at | | $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\Xi \times \mathcal{J}`$ — most nominal power an extendable process may be built at | | $`\mathrm{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\Xi \times \mathcal{J}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, $`0`$ where the data has no row — a given nominal power for an extendable process; one without a value has no row here | +| $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, `absent` where the data has no row — a given nominal power for an extendable process; one without a value has no row here | | $`\mathrm{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$ — whether internal power is gated by an on/off status decision | -| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{z,\mathrm{dn}}`$ | `Process_ramp_limit_shut_down` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{z,\mathrm{dn}}`$ | `Process_ramp_limit_shut_down` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit | | $`\mathrm{UT}^{z}`$ | `Process_min_up_time` over $`\Xi \times \mathcal{J}`$ — least snapshots a process stays on once started | | $`\mathrm{DT}^{z}`$ | `Process_min_down_time` over $`\Xi \times \mathcal{J}`$ — least snapshots a process stays off once stopped | | $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\Xi \times \mathcal{J}`$ — one where the process was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | @@ -5593,19 +5593,19 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{z,\mathrm{on}}`$ | `Process_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one snapshot spent on | | $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\Xi \times \mathcal{J}`$ — how many whole modules a committable build has in place: `Process_p_nom / Process_p_nom_mod` where a fixed build is modular, one where it is not, data prep. PyPSA refuses a fixed modular build whose nominal power is not a whole number of modules | -| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — the bound a committed extendable process's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep | +| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — the bound a committed extendable process's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep | | $`\mathrm{nonneg}^{z}`$ | `Process_p_min_pu_nonneg` over $`\mathcal{J}`$ — true where none of the process's own minimums-per-unit is negative — PyPSA's per-unit `(p_min_pu >= 0).all()` over every snapshot and scenario, data prep | | $`\mathrm{mnt}^{z}`$ | `Process_maintainable` over $`\mathcal{J}`$ — whether a process must be taken off for maintenance within the horizon — in any scenario, as PyPSA takes the union over them (`components.py:1016-1019`) | | $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\Xi \times \mathcal{J}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\Xi \times \mathcal{J}`$ — how many maintenance events the horizon holds | -| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the process is not maintainable. No row reads it: data prep turns it into `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the process is not maintainable. No row reads it: data prep turns it into `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}^{z}`$ | `Process_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the process does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | | $`\mathrm{load}`$ | `Load_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{D}`$ — demand | | $`\mathrm{sgn}^{\mathrm{load}}`$ | `Load_sign` over $`\mathcal{D}`$ — the sign a load's demand enters its bus's balance with — PyPSA's `sign`, `-1` unless given, `1` for a load that feeds its bus. PyPSA refuses one that differs by scenario (`constants.py:43`) | | $`\mathrm{on}^{\mathrm{load}}`$ | `Load_active` over $`\mathcal{D}`$ — whether a load stands in the model — PyPSA's `active`. A load has no build year and no lifetime, so the flag holds in every snapshot. PyPSA refuses one that differs by scenario (`constants.py:51`) | | $`\pi`$ | `scenario_weight` over $`\Xi`$ — PyPSA's `scenario_weightings.weight` — the probability of a future | | $`\omega`$ | `CVaR_omega` (scalar), $`0`$ where the data has no row — PyPSA's `risk_preference['omega']` — the share of operating cost priced at the tail rather than in expectation. Data prep writes a row only where a risk preference is set. Without a risk preference, the file has no CVaR variables or rows. With `omega = 0`, PyPSA builds them, and the optimum is the risk-neutral one | -| $`\alpha`$ | `CVaR_alpha` (scalar), $`0`$ where the data has no row — PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` | +| $`\alpha`$ | `CVaR_alpha` (scalar), `absent` where the data has no row — PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$ — PyPSA's `investment_period_weightings.objective` — what a period's cost weighs; PyPSA reads it only under `multi_investment_periods`, so data prep feeds one otherwise, whatever the column holds (`optimize.py:205-207`, `:264-266`) | | $`\mathrm{w}^{\mathrm{yr}}`$ | `period_weight_years` over $`\mathcal{Y}`$ — PyPSA's `investment_period_weightings.years` — what a period's energy weighs in a `primary_energy` or `operational_limit` row; PyPSA reads it only under `multi_investment_periods`, so data prep feeds one otherwise | | $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{T} \times \mathcal{G}`$ — whether a generator stands in a snapshot's period — PyPSA's `active`, from build year and lifetime, data prep | @@ -5635,30 +5635,30 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{new}^{e}`$ | `Store_first_active` over $`\mathcal{Y} \times \mathcal{V}`$ — one in the first period a store stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | | $`\mathrm{new}^{s}`$ | `Line_first_active` over $`\mathcal{Y} \times \mathcal{K}`$ — one in the first period a line stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | | $`\mathrm{new}^{z}`$ | `Process_first_active` over $`\mathcal{Y} \times \mathcal{J}`$ — one in the first period a process stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\overline{\Delta}`$ | `Carrier_max_growth` over $`\mathcal{I}`$, $`0`$ where the data has no row — most capacity of a carrier that may be added in a period; no value means no limit. The least over the scenarios, as PyPSA takes it (`global_constraints.py:227-231`), data prep. PyPSA reads it only under `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise | +| $`\overline{\Delta}`$ | `Carrier_max_growth` over $`\mathcal{I}`$, `absent` where the data has no row — most capacity of a carrier that may be added in a period; no value means no limit. The least over the scenarios, as PyPSA takes it (`global_constraints.py:227-231`), data prep. PyPSA reads it only under `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise | | $`\mathrm{r}`$ | `Carrier_max_relative_growth` over $`\mathcal{I}`$ — share of the previous period's additions that may be added on top — the least over the scenarios, as PyPSA takes it, data prep | -| $`\mathrm{p}^{\mathrm{set}}`$ | `Generator_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — a given output schedule; a generator without one has no row here | -| $`\mathrm{f}^{\mathrm{set}}`$ | `Link_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — a given flow schedule; a link without one has no row here | +| $`\mathrm{p}^{\mathrm{set}}`$ | `Generator_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — a given output schedule; a generator without one has no row here | +| $`\mathrm{f}^{\mathrm{set}}`$ | `Link_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — a given flow schedule; a link without one has no row here | | $`\mathrm{w}^{\mathrm{sto}}`$ | `snapshot_weightings_stores` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.stores` — hours a snapshot stands for in a storage balance | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.generators` — hours a snapshot stands for in an energy total | | $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\Xi \times \mathcal{G}`$ — least nominal power an extendable generator may be built at | | $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\Xi \times \mathcal{G}`$ — most nominal power an extendable generator may be built at | | $`\mathrm{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\Xi \times \mathcal{G}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, $`0`$ where the data has no row — a given nominal power for an extendable generator; one without a value has no row here | +| $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, `absent` where the data has no row — a given nominal power for an extendable generator; one without a value has no row here | | $`\underline{\mathrm{E}}`$ | `Generator_e_sum_min` over $`\Xi \times \mathcal{G}`$ — least energy over the horizon; minus infinity where no floor is meant | | $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\Xi \times \mathcal{G}`$ — most energy over the horizon — a fuel or emission budget in energy terms; infinity where no cap is meant | | $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\Xi \times \mathcal{L}`$ — least nominal power an extendable link may be built at | | $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\Xi \times \mathcal{L}`$ — most nominal power an extendable link may be built at | | $`\mathrm{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\Xi \times \mathcal{L}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, $`0`$ where the data has no row — a given nominal power for an extendable link; one without a value has no row here | +| $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, `absent` where the data has no row — a given nominal power for an extendable link; one without a value has no row here | | $`\underline{\mathrm{h}}^{\mathrm{nom}}`$ | `StorageUnit_p_nom_min` over $`\Xi \times \mathcal{S}`$ — least nominal power an extendable storage unit may be built at | | $`\overline{\mathrm{h}}^{\mathrm{nom}}`$ | `StorageUnit_p_nom_max` over $`\Xi \times \mathcal{S}`$ — most nominal power an extendable storage unit may be built at | | $`\mathrm{c}^{\mathrm{cap},h}`$ | `StorageUnit_capital_cost` over $`\Xi \times \mathcal{S}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, $`0`$ where the data has no row — a given nominal power for an extendable storage unit; one without a value has no row here | +| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, `absent` where the data has no row — a given nominal power for an extendable storage unit; one without a value has no row here | | $`\underline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_min` over $`\Xi \times \mathcal{V}`$ — least nominal capacity an extendable store may be built at | | $`\overline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_max` over $`\Xi \times \mathcal{V}`$ — most nominal capacity an extendable store may be built at | | $`\mathrm{c}^{\mathrm{cap},e}`$ | `Store_capital_cost` over $`\Xi \times \mathcal{V}`$ — cost of one unit of nominal capacity for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, $`0`$ where the data has no row — a given nominal capacity for an extendable store; one without a value has no row here | +| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, `absent` where the data has no row — a given nominal capacity for an extendable store; one without a value has no row here | | $`\mathrm{h}^{\mathrm{nom}}`$ | `StorageUnit_p_nom` over $`\Xi \times \mathcal{S}`$ — nominal power | | $`\mathrm{ext}^{h}`$ | `StorageUnit_p_nom_extendable` over $`\mathcal{S}`$ — whether the nominal power is a decision | | $`\mathrm{h}^{\mathrm{mod}}`$ | `StorageUnit_p_nom_mod` over $`\mathcal{S}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | @@ -5680,10 +5680,10 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{h,(2)}`$ | `StorageUnit_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of the square of one unit of dispatch; storing is not charged | | $`\mathrm{c}^{\mathrm{soc}}`$ | `StorageUnit_marginal_cost_storage` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of charge held over one snapshot | | $`\mathrm{c}^{\mathrm{spill}}`$ | `StorageUnit_spill_cost` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of inflow passed on unused | -| $`\mathrm{h}^{\mathrm{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given net dispatch schedule; a unit without one has no row here | -| $`\mathrm{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given dispatch schedule; a unit without one has no row here | -| $`\mathrm{h}^{-,\mathrm{set}}`$ | `StorageUnit_p_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given charging schedule; a unit without one has no row here | -| $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given charge schedule; a unit without one has no row here | +| $`\mathrm{h}^{\mathrm{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given net dispatch schedule; a unit without one has no row here | +| $`\mathrm{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given dispatch schedule; a unit without one has no row here | +| $`\mathrm{h}^{-,\mathrm{set}}`$ | `StorageUnit_p_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given charging schedule; a unit without one has no row here | +| $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given charge schedule; a unit without one has no row here | | $`\mathrm{e}^{\mathrm{nom}}`$ | `Store_e_nom` over $`\Xi \times \mathcal{V}`$ — nominal energy capacity | | $`\mathrm{ext}^{e}`$ | `Store_e_nom_extendable` over $`\mathcal{V}`$ — whether the nominal energy capacity is a decision | | $`\mathrm{e}^{\mathrm{mod}}`$ | `Store_e_nom_mod` over $`\mathcal{V}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | @@ -5700,8 +5700,8 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{c}^{q}`$ | `Store_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of one unit of power delivered | | $`\mathrm{c}^{q,(2)}`$ | `Store_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of the square of the net power delivered, so charging costs as much as delivering | | $`\mathrm{c}^{e}`$ | `Store_marginal_cost_storage` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of one unit of energy held over one snapshot | -| $`\mathrm{e}^{\mathrm{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, $`0`$ where the data has no row — a given energy schedule; a store without one has no row here | -| $`\mathrm{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, $`0`$ where the data has no row — a given schedule of power delivered; a store without one has no row here | +| $`\mathrm{e}^{\mathrm{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `absent` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\mathrm{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `absent` where the data has no row — a given schedule of power delivered; a store without one has no row here | | $`\mathrm{s}^{\mathrm{nom}}`$ | `Line_s_nom` over $`\Xi \times \mathcal{K}`$ — nominal apparent power | | $`\mathrm{ext}^{s}`$ | `Line_s_nom_extendable` over $`\mathcal{K}`$ — whether the nominal apparent power is a decision | | $`\mathrm{s}^{\mathrm{mod}}`$ | `Line_s_nom_mod` over $`\mathcal{K}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | @@ -5709,12 +5709,12 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\Xi \times \mathcal{K}`$ — least nominal apparent power an extendable line may be built at | | $`\overline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_max` over $`\Xi \times \mathcal{K}`$ — most nominal apparent power an extendable line may be built at | | $`\mathrm{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\Xi \times \mathcal{K}`$ — cost of one unit of nominal apparent power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, $`0`$ where the data has no row — a given nominal apparent power for an extendable line; one without a value has no row here | -| $`\mathrm{s}^{\mathrm{set}}`$ | `Line_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$, $`0`$ where the data has no row — a given flow schedule; a line without one has no row here | -| $`\overline{\delta}`$ | `Line_v_ang_max` over $`\Xi \times \mathcal{K}`$, $`0`$ where the data has no row — the most the voltage angle difference across a line may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. A line whose carrier is not AC has no row either. The deprecated `v_ang_min` is ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) | +| $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, `absent` where the data has no row — a given nominal apparent power for an extendable line; one without a value has no row here | +| $`\mathrm{s}^{\mathrm{set}}`$ | `Line_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$, `absent` where the data has no row — a given flow schedule; a line without one has no row here | +| $`\overline{\delta}`$ | `Line_v_ang_max` over $`\Xi \times \mathcal{K}`$, `absent` where the data has no row — the most the voltage angle difference across a line may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. A line whose carrier is not AC has no row either. The deprecated `v_ang_min` is ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) | | $`\mathrm{x}^{\mathrm{eff}}`$ | `Line_x_pu_eff` over $`\Xi \times \mathcal{K}`$ — the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over the square of its bus's nominal voltage, data prep | -| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{C}`$, $`0`$ where the data has no row — the line's series impedance, signed by its orientation in the cycle — the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) | -| $`\beta`$ | `Line_BODF` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{K}^{\mathrm{out}}`$, $`0`$ where the data has no row — the share of an outaged branch's flow a line takes on when that branch goes out — PyPSA's `BODF`, from the PTDF of the sub-network the period's active branches form, data prep; a row only where the line and the outage are active in the period and share a sub-network, -1 at the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) | +| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{C}`$, `absent` where the data has no row — the line's series impedance, signed by its orientation in the cycle — the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) | +| $`\beta`$ | `Line_BODF` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{K}^{\mathrm{out}}`$, `absent` where the data has no row — the share of an outaged branch's flow a line takes on when that branch goes out — PyPSA's `BODF`, from the PTDF of the sub-network the period's active branches form, data prep; a row only where the line and the outage are active in the period and share a sub-network, -1 at the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) | | $`\mathrm{lossy}`$ | `transmission_losses` (scalar) — whether the network dissipates transmission losses — PyPSA's `transmission_losses` read as a flag; its mode, tangents or secants, only decides how data prep fills the `segment` axis, the rows are the same; false with no segments is a lossless run. A security-constrained run over a network with passive branches builds no loss: PyPSA does not hand the keyword to `create_model` (`abstract.py:528-532`) but to the solver (`:548`), so data prep feeds false there | | $`\overline{\ell}`$ | `Line_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$ — the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep | | $`\mathrm{a}`$ | `Line_loss_slope` over $`\Xi \times \mathcal{T} \times \mathcal{K} \times \mathcal{B}`$ — the slope of a cut to the loss curve — a tangent's `2 * r_pu_eff * p_k` at its segment's flow, a secant's `r_pu_eff * (p_k + p_k+1)` between consecutive breakpoints, data prep | @@ -5726,13 +5726,13 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\underline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_min` over $`\Xi \times \mathcal{M}`$ — least nominal apparent power an extendable transformer may be built at | | $`\overline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_max` over $`\Xi \times \mathcal{M}`$ — most nominal apparent power an extendable transformer may be built at | | $`\mathrm{c}^{\mathrm{cap},\sigma}`$ | `Transformer_capital_cost` over $`\Xi \times \mathcal{M}`$ — cost of one unit of nominal apparent power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, $`0`$ where the data has no row — a given nominal apparent power for an extendable transformer; one without a value has no row here | -| $`\sigma^{\mathrm{set}}`$ | `Transformer_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, $`0`$ where the data has no row — a given flow schedule; a transformer without one has no row here | -| $`\overline{\delta}^{\sigma}`$ | `Transformer_v_ang_max` over $`\Xi \times \mathcal{M}`$, $`0`$ where the data has no row — the most the voltage angle difference across a transformer, its phase shift included, may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's | +| $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, `absent` where the data has no row — a given nominal apparent power for an extendable transformer; one without a value has no row here | +| $`\sigma^{\mathrm{set}}`$ | `Transformer_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `absent` where the data has no row — a given flow schedule; a transformer without one has no row here | +| $`\overline{\delta}^{\sigma}`$ | `Transformer_v_ang_max` over $`\Xi \times \mathcal{M}`$, `absent` where the data has no row — the most the voltage angle difference across a transformer, its phase shift included, may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's | | $`\mathrm{x}^{\mathrm{eff},\sigma}`$ | `Transformer_x_pu_eff` over $`\Xi \times \mathcal{M}`$ — the transformer's effective series reactance — PyPSA's `x_pu_eff`, `x` over its `s_nom` times its tap ratio, data prep | -| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{C}`$, $`0`$ where the data has no row — the transformer's effective series reactance, `x` times its tap ratio, signed by its orientation in the cycle — PyPSA's `x_pu_eff`, the cycle basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's | -| $`\beta^{\sigma}`$ | `Transformer_BODF` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{K}^{\mathrm{out}}`$, $`0`$ where the data has no row — the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network | -| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{T} \times \mathcal{M} \times \mathcal{C}`$, $`0`$ where the data has no row — a fixed transformer's phase shift in radians at each snapshot, signed by its orientation in the cycle — a constant added to the cycle sum, data prep; zero for a varying transformer, whose shift is a decision instead, so the constant and the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row | +| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{C}`$, `absent` where the data has no row — the transformer's effective series reactance, `x` times its tap ratio, signed by its orientation in the cycle — PyPSA's `x_pu_eff`, the cycle basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's | +| $`\beta^{\sigma}`$ | `Transformer_BODF` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{K}^{\mathrm{out}}`$, `absent` where the data has no row — the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network | +| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{T} \times \mathcal{M} \times \mathcal{C}`$, `absent` where the data has no row — a fixed transformer's phase shift in radians at each snapshot, signed by its orientation in the cycle — a constant added to the cycle sum, data prep; zero for a varying transformer, whose shift is a decision instead, so the constant and the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row | | $`\mathrm{Transformer\_phase\_shift\_varying}`$ | `Transformer_phase_shift_varying` over $`\mathcal{M}`$ — whether a transformer's phase shift is a decision — PyPSA's `phase_shift_min < phase_shift_max`, read as a flag in data prep; false is a fixed shift carried by `phase_shift`. The shift parameters carry no scenario, but PyPSA reads them per scenario (`variables.py:433-443`, `constraints.py:1652`, `:1735`), so the spec and PyPSA differ here (\#783) | | $`\mathrm{Transformer\_phase\_shift\_min}`$ | `Transformer_phase_shift_min` over $`\mathcal{M}`$ — the least a varying transformer's phase shift may take, in degrees — PyPSA's `phase_shift_min`; where it is below `phase_shift_max` the shift is a decision, otherwise the transformer keeps its fixed `phase_shift` | | $`\mathrm{Transformer\_phase\_shift\_max}`$ | `Transformer_phase_shift_max` over $`\mathcal{M}`$ — the most a varying transformer's phase shift may take, in degrees — PyPSA's `phase_shift_max`; equal to `phase_shift_min` for a fixed transformer | @@ -5745,22 +5745,22 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | $`\mathrm{sense}`$ | `GlobalConstraint_sense` over $`\Xi \times \mathcal{I}`$ — which way the row binds in each scenario — `<=`, `>=` or `==`; PyPSA reads a row's sense per scenario (`global_constraints.py:551`, `:749`, `:829`) | | $`\mathrm{K}`$ | `GlobalConstraint_constant` over $`\Xi \times \mathcal{I}`$ — the constant the total is held against; what a variable cannot carry — an initial charge, times its period's years for each counted period where the storage reopens per period, or a non-extendable build — is folded in here by data prep. PyPSA reads it per scenario (`global_constraints.py:552`, `:750`, `:829`) | | $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\Xi \times \mathcal{I} \times \mathcal{T}`$, `false` where the data has no row — whether a row counts a snapshot in a scenario — PyPSA's `investment_period`: every snapshot where the row names none, and only that period's where it names one, data prep. A row that names a period the run does not model has no label here, as PyPSA skips it (`global_constraints.py:372`); PyPSA reads the column only under `multi_investment_periods`, and fails on a row that names a period without it (`global_constraints.py:364-369`) | -| $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — the constrained attribute per unit of energy at the bus — the carrier's `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row | -| $`\mathrm{a}^{h}`$ | `StorageUnit_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{S}`$, $`0`$ where the data has no row — the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row | -| $`\mathrm{a}^{e}`$ | `Store_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{V}`$, $`0`$ where the data has no row — the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row | -| $`\mathrm{b}`$ | `Generator_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{G}`$, $`0`$ where the data has no row — one where the generator is in the row's set — data prep; one outside it has no row | -| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{S}`$, $`0`$ where the data has no row — one where the storage unit is in the row's set — data prep; one outside it has no row | -| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{V}`$, $`0`$ where the data has no row — one where the store is in the row's set — data prep; one outside it has no row | -| $`\mathrm{len}`$ | `Line_volume_weight` over $`\Xi \times \mathcal{I} \times \mathcal{K}`$, $`0`$ where the data has no row — the line's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a line outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{len}^{f}`$ | `Link_volume_weight` over $`\Xi \times \mathcal{I} \times \mathcal{L}`$, $`0`$ where the data has no row — the link's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a link outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{cc}`$ | `Line_expansion_cost_weight` over $`\Xi \times \mathcal{I} \times \mathcal{K}`$, $`0`$ where the data has no row — the line's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a line outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | -| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\Xi \times \mathcal{I} \times \mathcal{L}`$, $`0`$ where the data has no row — the link's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a link outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | -| $`\mathrm{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{G}`$, $`0`$ where the data has no row — one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{L}`$, $`0`$ where the data has no row — one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{K}`$, $`0`$ where the data has no row — one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{S}`$, $`0`$ where the data has no row — one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{V}`$, $`0`$ where the data has no row — one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{J}`$, $`0`$ where the data has no row — one where the process is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — the constrained attribute per unit of energy at the bus — the carrier's `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row | +| $`\mathrm{a}^{h}`$ | `StorageUnit_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{S}`$, `absent` where the data has no row — the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row | +| $`\mathrm{a}^{e}`$ | `Store_primary_energy_weight` over $`\Xi \times \mathcal{I} \times \mathcal{V}`$, `absent` where the data has no row — the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row | +| $`\mathrm{b}`$ | `Generator_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{G}`$, `absent` where the data has no row — one where the generator is in the row's set — data prep; one outside it has no row | +| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{S}`$, `absent` where the data has no row — one where the storage unit is in the row's set — data prep; one outside it has no row | +| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\Xi \times \mathcal{I} \times \mathcal{V}`$, `absent` where the data has no row — one where the store is in the row's set — data prep; one outside it has no row | +| $`\mathrm{len}`$ | `Line_volume_weight` over $`\Xi \times \mathcal{I} \times \mathcal{K}`$, `absent` where the data has no row — the line's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a line outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{len}^{f}`$ | `Link_volume_weight` over $`\Xi \times \mathcal{I} \times \mathcal{L}`$, `absent` where the data has no row — the link's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a link outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{cc}`$ | `Line_expansion_cost_weight` over $`\Xi \times \mathcal{I} \times \mathcal{K}`$, `absent` where the data has no row — the line's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a line outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | +| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\Xi \times \mathcal{I} \times \mathcal{L}`$, `absent` where the data has no row — the link's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a link outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | +| $`\mathrm{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{G}`$, `absent` where the data has no row — one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{L}`$, `absent` where the data has no row — one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{K}`$, `absent` where the data has no row — one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{S}`$, `absent` where the data has no row — one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{V}`$, `absent` where the data has no row — one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{I} \times \mathcal{J}`$, `absent` where the data has no row — one where the process is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks @@ -12421,6 +12421,54 @@ CVaR_def: \theta + \frac{1}{1 - \alpha} \cdot \left( \sum_{\xi \in \Xi} \pi_{\xi} \cdot a_{\xi} \right) \le CVaR \qquad \text{where } \omega \text{ is defined} ``` +### `Generator_big_m_where_committed_and_extendable` + +```yaml +Generator_big_m_where_committed_and_extendable: + holds: "Generator_big_m" + where: "Generator_com_ext" + description: >- + a committable generator with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) +``` + +```math +\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{t,g} +``` + +### `Link_big_m_where_committed_and_extendable` + +```yaml +Link_big_m_where_committed_and_extendable: + holds: "Link_big_m" + where: "Link_com_ext" + description: >- + a committable link with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) +``` + +```math +\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{t,l} +``` + +### `Process_big_m_where_committed_and_extendable` + +```yaml +Process_big_m_where_committed_and_extendable: + holds: "Process_big_m" + where: "Process_com_ext" + description: >- + a committable process with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) +``` + +```math +\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{t,j} +``` + ### `Generator_maintenance_events_positive` ```yaml diff --git a/docs/examples/pypsa/carrier.md b/docs/examples/pypsa/carrier.md index 385073e3..9b6ccf74 100644 --- a/docs/examples/pypsa/carrier.md +++ b/docs/examples/pypsa/carrier.md @@ -30,7 +30,7 @@ parameters: `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise dims: [carrier] - missing: 0 + missing: absent Carrier_max_relative_growth: description: >- share of the previous period's additions that may be added on top — the @@ -80,7 +80,7 @@ constraints: | Symbol | Meaning | |---|---| -| $`\overline{\Delta}`$ | `Carrier_max_growth` over $`\mathcal{I}`$, $`0`$ where the data has no row — most capacity of a carrier that may be added in a period; no value means no limit. The least over the scenarios, as PyPSA takes it (`global_constraints.py:227-231`), data prep. PyPSA reads it only under `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise | +| $`\overline{\Delta}`$ | `Carrier_max_growth` over $`\mathcal{I}`$, `absent` where the data has no row — most capacity of a carrier that may be added in a period; no value means no limit. The least over the scenarios, as PyPSA takes it (`global_constraints.py:227-231`), data prep. PyPSA reads it only under `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise | | $`\mathrm{r}`$ | `Carrier_max_relative_growth` over $`\mathcal{I}`$ — share of the previous period's additions that may be added on top — the least over the scenarios, as PyPSA takes it, data prep | #### Definitions diff --git a/docs/examples/pypsa/cost.md b/docs/examples/pypsa/cost.md index 12c0625b..95274c70 100644 --- a/docs/examples/pypsa/cost.md +++ b/docs/examples/pypsa/cost.md @@ -25,7 +25,7 @@ parameters: CVaR_alpha: description: PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` dims: [] - missing: 0 + missing: absent variables: CVaR_a: @@ -83,7 +83,7 @@ constraints: | Symbol | Meaning | |---|---| -| $`\alpha`$ | `CVaR_alpha` (scalar), $`0`$ where the data has no row — PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` | +| $`\alpha`$ | `CVaR_alpha` (scalar), `absent` where the data has no row — PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` | #### Variables diff --git a/docs/examples/pypsa/generator.md b/docs/examples/pypsa/generator.md index 4c7e7883..cce525a1 100644 --- a/docs/examples/pypsa/generator.md +++ b/docs/examples/pypsa/generator.md @@ -131,7 +131,7 @@ parameters: Generator_p_set: description: a given output schedule; a generator without one has no row here dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_p_nom_min: description: least nominal power an extendable generator may be built at dims: [scenario, generator] @@ -149,7 +149,7 @@ parameters: Generator_p_nom_set: description: a given nominal power for an extendable generator; one without a value has no row here dims: [generator] - missing: 0 + missing: absent Generator_e_sum_min: description: least energy over the horizon; minus infinity where no floor is meant dims: [scenario, generator] @@ -162,18 +162,18 @@ parameters: `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row dims: [scenario, global_constraint, snapshot, generator] - missing: 0 + missing: absent Generator_operational_limit_weight: description: one where the generator is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, generator] - missing: 0 + missing: absent Generator_tech_capacity_weight: description: >- one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, generator] - missing: 0 + missing: absent variables: Generator_p: @@ -364,16 +364,16 @@ assumptions: | $`\mathrm{act}`$ | `Generator_active_asset` over $`\mathcal{G}`$ — whether a generator is one of PyPSA's `active_assets` — its `active` flag alone, without build year and lifetime, so a unit that stands in no snapshot of the horizon still counts. PyPSA refuses one that differs by scenario (`constants.py:51`) | | $`\mathrm{W}`$ | `Generator_capital_weight` over $`\mathcal{G}`$ — the sum of period weights a generator stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{new}`$ | `Generator_first_active` over $`\mathcal{Y} \times \mathcal{G}`$ — one in the first period a generator stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\mathrm{p}^{\mathrm{set}}`$ | `Generator_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — a given output schedule; a generator without one has no row here | +| $`\mathrm{p}^{\mathrm{set}}`$ | `Generator_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — a given output schedule; a generator without one has no row here | | $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\Xi \times \mathcal{G}`$ — least nominal power an extendable generator may be built at | | $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\Xi \times \mathcal{G}`$ — most nominal power an extendable generator may be built at | | $`\mathrm{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\Xi \times \mathcal{G}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, $`0`$ where the data has no row — a given nominal power for an extendable generator; one without a value has no row here | +| $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, `absent` where the data has no row — a given nominal power for an extendable generator; one without a value has no row here | | $`\underline{\mathrm{E}}`$ | `Generator_e_sum_min` over $`\Xi \times \mathcal{G}`$ — least energy over the horizon; minus infinity where no floor is meant | | $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\Xi \times \mathcal{G}`$ — most energy over the horizon — a fuel or emission budget in energy terms; infinity where no cap is meant | -| $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\Xi \times \mathcal{L} \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — the constrained attribute per unit of energy at the bus — the carrier's `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row | -| $`\mathrm{b}`$ | `Generator_operational_limit_weight` over $`\Xi \times \mathcal{L} \times \mathcal{G}`$, $`0`$ where the data has no row — one where the generator is in the row's set — data prep; one outside it has no row | -| $`\mathrm{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{G}`$, $`0`$ where the data has no row — one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\Xi \times \mathcal{L} \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — the constrained attribute per unit of energy at the bus — the carrier's `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row | +| $`\mathrm{b}`$ | `Generator_operational_limit_weight` over $`\Xi \times \mathcal{L} \times \mathcal{G}`$, `absent` where the data has no row — one where the generator is in the row's set — data prep; one outside it has no row | +| $`\mathrm{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{G}`$, `absent` where the data has no row — one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks diff --git a/docs/examples/pypsa/generator_commitment.md b/docs/examples/pypsa/generator_commitment.md index 4d735f8a..d2a7f10b 100644 --- a/docs/examples/pypsa/generator_commitment.md +++ b/docs/examples/pypsa/generator_commitment.md @@ -104,7 +104,7 @@ parameters: (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep dims: [scenario, generator] - missing: 0 + missing: absent variables: Generator_status: @@ -302,6 +302,15 @@ constraints: dims: [scenario, snapshot, generator] where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 expression: Generator_shut_down <= Generator_n_mod + +assumptions: + Generator_big_m_where_committed_and_extendable: + holds: "Generator_big_m" + where: "Generator_com_ext" + description: >- + a committable generator with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) ``` #### Given @@ -349,7 +358,7 @@ constraints: | $`\mathrm{c}^{\mathrm{up}}`$ | `Generator_start_up_cost` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — cost of one start in this snapshot | | $`\mathrm{c}^{\mathrm{dn}}`$ | `Generator_shut_down_cost` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{\mathrm{on}}`$ | `Generator_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — cost of one snapshot spent on | -| $`\mathrm{M}`$ | `Generator_big_m` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — the bound a committed extendable generator's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep | +| $`\mathrm{M}`$ | `Generator_big_m` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — the bound a committed extendable generator's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep | #### Masks @@ -548,4 +557,12 @@ u_{\xi,t,g} \le N_{g} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \ ```math \mathit{dn}_{\xi,t,g} \le N_{g} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com}}_{t,g} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` + +#### Assumptions + +**`Generator_big_m_where_committed_and_extendable`** + +```math +\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{t,g} +``` diff --git a/docs/examples/pypsa/generator_maintenance.md b/docs/examples/pypsa/generator_maintenance.md index dd05f835..a17022ca 100644 --- a/docs/examples/pypsa/generator_maintenance.md +++ b/docs/examples/pypsa/generator_maintenance.md @@ -67,7 +67,7 @@ parameters: `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, generator] - missing: 0 + missing: absent Generator_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -277,7 +277,7 @@ assumptions: | $`\mathrm{mnt}`$ | `Generator_maintainable` over $`\mathcal{G}`$ — whether a generator must be taken off for maintenance within the horizon — in any scenario, as PyPSA takes the union over them (`components.py:1016-1019`) | | $`\gamma`$ | `Generator_maintenance_pu` over $`\Xi \times \mathcal{G}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\Xi \times \mathcal{G}`$ — how many maintenance events the horizon holds | -| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the generator is not maintainable. No row reads it: data prep turns it into `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the generator is not maintainable. No row reads it: data prep turns it into `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}`$ | `Generator_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the generator does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | #### Masks diff --git a/docs/examples/pypsa/generator_ramping.md b/docs/examples/pypsa/generator_ramping.md index 393904eb..b8ea8a0e 100644 --- a/docs/examples/pypsa/generator_ramping.md +++ b/docs/examples/pypsa/generator_ramping.md @@ -54,19 +54,19 @@ parameters: Generator_ramp_limit_up: description: most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_down: description: most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_start_up: description: most output in the snapshot a unit starts, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_ramp_limit_shut_down: description: most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_p_init: description: >- the output a unit brought into the horizon — PyPSA's `p_init`, read @@ -294,10 +294,10 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ru}`$ | `Generator_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}`$ | `Generator_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, $`0`$ where the data has no row — most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{ru}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — most output in the snapshot a unit starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{\mathrm{dn}}`$ | `Generator_ramp_limit_shut_down` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}`$ | `Generator_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}`$ | `Generator_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{G}`$, `absent` where the data has no row — most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{ru}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — most output in the snapshot a unit starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{\mathrm{dn}}`$ | `Generator_ramp_limit_shut_down` over $`\Xi \times \mathcal{G}`$, `absent` where the data has no row — most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit | | $`\mathrm{p}^{0}`$ | `Generator_p_init` over $`\Xi \times \mathcal{G}`$, $`0`$ where the data has no row — the output a unit brought into the horizon — PyPSA's `p_init`, read only where the unit came in running; no value means it is unknown, so the unit carries no ramp row at the first snapshot | #### Masks diff --git a/docs/examples/pypsa/line.md b/docs/examples/pypsa/line.md index 29dba4f3..5be306c4 100644 --- a/docs/examples/pypsa/line.md +++ b/docs/examples/pypsa/line.md @@ -124,11 +124,11 @@ parameters: Line_s_nom_set: description: a given nominal apparent power for an extendable line; one without a value has no row here dims: [line] - missing: 0 + missing: absent Line_s_set: description: a given flow schedule; a line without one has no row here dims: [scenario, snapshot, line] - missing: 0 + missing: absent Line_v_ang_max: description: >- the most the voltage angle difference across a line may be either way, @@ -137,7 +137,7 @@ parameters: ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) dims: [scenario, line] - missing: 0 + missing: absent Line_x_pu_eff: description: >- the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over @@ -149,7 +149,7 @@ parameters: the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) dims: [period, line, cycle] - missing: 0 + missing: absent Line_loss_max: description: the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep dims: [scenario, snapshot, line] @@ -171,7 +171,7 @@ parameters: line outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Line_expansion_cost_weight: description: >- the line's capital cost where its carrier is in the row's set, times @@ -182,14 +182,14 @@ parameters: `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Line_tech_capacity_weight: description: >- one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, line] - missing: 0 + missing: absent variables: Line_s: @@ -394,17 +394,17 @@ constraints: | $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\Xi \times \mathcal{K}`$ — least nominal apparent power an extendable line may be built at | | $`\overline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_max` over $`\Xi \times \mathcal{K}`$ — most nominal apparent power an extendable line may be built at | | $`\mathrm{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\Xi \times \mathcal{K}`$ — cost of one unit of nominal apparent power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, $`0`$ where the data has no row — a given nominal apparent power for an extendable line; one without a value has no row here | -| $`\mathrm{s}^{\mathrm{set}}`$ | `Line_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$, $`0`$ where the data has no row — a given flow schedule; a line without one has no row here | -| $`\overline{\delta}`$ | `Line_v_ang_max` over $`\Xi \times \mathcal{K}`$, $`0`$ where the data has no row — the most the voltage angle difference across a line may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. A line whose carrier is not AC has no row either. The deprecated `v_ang_min` is ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) | +| $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, `absent` where the data has no row — a given nominal apparent power for an extendable line; one without a value has no row here | +| $`\mathrm{s}^{\mathrm{set}}`$ | `Line_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$, `absent` where the data has no row — a given flow schedule; a line without one has no row here | +| $`\overline{\delta}`$ | `Line_v_ang_max` over $`\Xi \times \mathcal{K}`$, `absent` where the data has no row — the most the voltage angle difference across a line may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. A line whose carrier is not AC has no row either. The deprecated `v_ang_min` is ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) | | $`\mathrm{x}^{\mathrm{eff}}`$ | `Line_x_pu_eff` over $`\Xi \times \mathcal{K}`$ — the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over the square of its bus's nominal voltage, data prep | -| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{C}`$, $`0`$ where the data has no row — the line's series impedance, signed by its orientation in the cycle — the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) | +| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{C}`$, `absent` where the data has no row — the line's series impedance, signed by its orientation in the cycle — the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) | | $`\overline{\ell}`$ | `Line_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{K}`$ — the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep | | $`\mathrm{a}`$ | `Line_loss_slope` over $`\Xi \times \mathcal{T} \times \mathcal{K} \times \mathcal{E}`$ — the slope of a cut to the loss curve — a tangent's `2 * r_pu_eff * p_k` at its segment's flow, a secant's `r_pu_eff * (p_k + p_k+1)` between consecutive breakpoints, data prep | | $`\mathrm{b}`$ | `Line_loss_offset` over $`\Xi \times \mathcal{T} \times \mathcal{K} \times \mathcal{E}`$ — where that cut meets the loss axis — a tangent's `loss_k - slope_k * p_k`, a secant's `-r_pu_eff * p_k * p_k+1`, negative, data prep | -| $`\mathrm{len}`$ | `Line_volume_weight` over $`\Xi \times \mathcal{G} \times \mathcal{K}`$, $`0`$ where the data has no row — the line's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a line outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{cc}`$ | `Line_expansion_cost_weight` over $`\Xi \times \mathcal{G} \times \mathcal{K}`$, $`0`$ where the data has no row — the line's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a line outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | -| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{K}`$, $`0`$ where the data has no row — one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{len}`$ | `Line_volume_weight` over $`\Xi \times \mathcal{G} \times \mathcal{K}`$, `absent` where the data has no row — the line's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a line outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{cc}`$ | `Line_expansion_cost_weight` over $`\Xi \times \mathcal{G} \times \mathcal{K}`$, `absent` where the data has no row — the line's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a line outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | +| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{K}`$, `absent` where the data has no row — one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks diff --git a/docs/examples/pypsa/link.md b/docs/examples/pypsa/link.md index 22b7b82e..d207ac82 100644 --- a/docs/examples/pypsa/link.md +++ b/docs/examples/pypsa/link.md @@ -164,7 +164,7 @@ parameters: Link_p_set: description: a given flow schedule; a link without one has no row here dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_p_nom_min: description: least nominal power an extendable link may be built at dims: [scenario, link] @@ -182,7 +182,7 @@ parameters: Link_p_nom_set: description: a given nominal power for an extendable link; one without a value has no row here dims: [link] - missing: 0 + missing: absent Link_volume_weight: description: >- the link's length in each scenario where its carrier is in the row's @@ -190,7 +190,7 @@ parameters: link outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Link_expansion_cost_weight: description: >- the link's capital cost where its carrier is in the row's set, times @@ -201,14 +201,14 @@ parameters: `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Link_tech_capacity_weight: description: >- one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, link] - missing: 0 + missing: absent variables: Link_p: @@ -418,14 +418,14 @@ assumptions: | $`\mathrm{act}^{f}`$ | `Link_active_asset` over $`\mathcal{L}`$ — whether a link is one of PyPSA's `active_assets` — its `active` flag alone, without build year and lifetime, so a unit that stands in no snapshot of the horizon still counts. PyPSA refuses one that differs by scenario (`constants.py:51`) | | $`\mathrm{W}^{f}`$ | `Link_capital_weight` over $`\mathcal{L}`$ — the sum of period weights a link stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{new}^{f}`$ | `Link_first_active` over $`\mathcal{Y} \times \mathcal{L}`$ — one in the first period a link stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\mathrm{f}^{\mathrm{set}}`$ | `Link_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — a given flow schedule; a link without one has no row here | +| $`\mathrm{f}^{\mathrm{set}}`$ | `Link_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — a given flow schedule; a link without one has no row here | | $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\Xi \times \mathcal{L}`$ — least nominal power an extendable link may be built at | | $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\Xi \times \mathcal{L}`$ — most nominal power an extendable link may be built at | | $`\mathrm{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\Xi \times \mathcal{L}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, $`0`$ where the data has no row — a given nominal power for an extendable link; one without a value has no row here | -| $`\mathrm{len}^{f}`$ | `Link_volume_weight` over $`\Xi \times \mathcal{G} \times \mathcal{L}`$, $`0`$ where the data has no row — the link's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a link outside it, or one that does not stand in the row's `investment_period`, has no row | -| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\Xi \times \mathcal{G} \times \mathcal{L}`$, $`0`$ where the data has no row — the link's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a link outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | -| $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{L}`$, $`0`$ where the data has no row — one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, `absent` where the data has no row — a given nominal power for an extendable link; one without a value has no row here | +| $`\mathrm{len}^{f}`$ | `Link_volume_weight` over $`\Xi \times \mathcal{G} \times \mathcal{L}`$, `absent` where the data has no row — the link's length in each scenario where its carrier is in the row's set (`global_constraints.py:847-848`) — data prep; a link outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\Xi \times \mathcal{G} \times \mathcal{L}`$, `absent` where the data has no row — the link's capital cost where its carrier is in the row's set, times the objective weights of the periods it stands in where the row names no `investment_period` under `multi_investment_periods` — data prep; a link outside the set, or one that does not stand in the row's period, has no row. The capital cost is PyPSA's `capital_cost` property, which is `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) | +| $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{L}`$, `absent` where the data has no row — one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks diff --git a/docs/examples/pypsa/link_commitment.md b/docs/examples/pypsa/link_commitment.md index 56699f2c..79f7077d 100644 --- a/docs/examples/pypsa/link_commitment.md +++ b/docs/examples/pypsa/link_commitment.md @@ -104,7 +104,7 @@ parameters: (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep dims: [scenario, link] - missing: 0 + missing: absent variables: Link_status: @@ -302,6 +302,15 @@ constraints: dims: [scenario, snapshot, link] where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 expression: Link_shut_down <= Link_n_mod + +assumptions: + Link_big_m_where_committed_and_extendable: + holds: "Link_big_m" + where: "Link_com_ext" + description: >- + a committable link with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) ``` #### Given @@ -349,7 +358,7 @@ constraints: | $`\mathrm{c}^{f,\mathrm{up}}`$ | `Link_start_up_cost` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of one start in this snapshot | | $`\mathrm{c}^{f,\mathrm{dn}}`$ | `Link_shut_down_cost` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{f,\mathrm{on}}`$ | `Link_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — cost of one snapshot spent on | -| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — the bound a committed extendable link's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep | +| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — the bound a committed extendable link's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep | #### Masks @@ -548,4 +557,12 @@ u^{f}_{\xi,t,l} \le N^{f}_{l} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ ```math \mathit{dn}^{f}_{\xi,t,l} \le N^{f}_{l} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com}}_{t,l} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` + +#### Assumptions + +**`Link_big_m_where_committed_and_extendable`** + +```math +\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{t,l} +``` diff --git a/docs/examples/pypsa/link_maintenance.md b/docs/examples/pypsa/link_maintenance.md index cac71d05..2703dee0 100644 --- a/docs/examples/pypsa/link_maintenance.md +++ b/docs/examples/pypsa/link_maintenance.md @@ -67,7 +67,7 @@ parameters: `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, link] - missing: 0 + missing: absent Link_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -274,7 +274,7 @@ assumptions: | $`\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:1016-1019`) | | $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\Xi \times \mathcal{L}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\Xi \times \mathcal{L}`$ — how many maintenance events the horizon holds | -| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the link is not maintainable. No row reads it: data prep turns it into `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the link is not maintainable. No row reads it: data prep turns it into `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}^{f}`$ | `Link_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the link does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | #### Masks diff --git a/docs/examples/pypsa/link_ramping.md b/docs/examples/pypsa/link_ramping.md index ab753143..61021573 100644 --- a/docs/examples/pypsa/link_ramping.md +++ b/docs/examples/pypsa/link_ramping.md @@ -54,19 +54,19 @@ parameters: Link_ramp_limit_up: description: most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_ramp_limit_down: description: most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_ramp_limit_start_up: description: most flow in the snapshot a link starts, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_ramp_limit_shut_down: description: most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_p_init: description: >- the flow a link brought into the horizon — PyPSA's `p_init`, read @@ -282,10 +282,10 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ru}^{f}`$ | `Link_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, $`0`$ where the data has no row — most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{ru}^{f,\mathrm{up}}`$ | `Link_ramp_limit_start_up` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — most flow in the snapshot a link starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{f,\mathrm{dn}}`$ | `Link_ramp_limit_shut_down` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}^{f}`$ | `Link_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{L}`$, `absent` where the data has no row — most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{ru}^{f,\mathrm{up}}`$ | `Link_ramp_limit_start_up` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — most flow in the snapshot a link starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{f,\mathrm{dn}}`$ | `Link_ramp_limit_shut_down` over $`\Xi \times \mathcal{L}`$, `absent` where the data has no row — most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit | | $`\mathrm{f}^{0}`$ | `Link_p_init` over $`\Xi \times \mathcal{L}`$, $`0`$ where the data has no row — the flow a link brought into the horizon — PyPSA's `p_init`, read only where the link came in running; no value means it is unknown, so the link carries no ramp row at the first snapshot | #### Masks diff --git a/docs/examples/pypsa/process.md b/docs/examples/pypsa/process.md index e7b7c807..eaf59b2c 100644 --- a/docs/examples/pypsa/process.md +++ b/docs/examples/pypsa/process.md @@ -123,7 +123,7 @@ parameters: Process_p_set: description: a given internal power schedule; a process without one has no row here dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_p_nom_min: description: least nominal power an extendable process may be built at dims: [scenario, process] @@ -141,7 +141,7 @@ parameters: Process_p_nom_set: description: a given nominal power for an extendable process; one without a value has no row here dims: [process] - missing: 0 + missing: absent Process_p_nom_mod: description: the module size a build comes in whole numbers of; no value means the build is continuous dims: [process] @@ -185,7 +185,7 @@ parameters: outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, process] - missing: 0 + missing: absent variables: Process_p: @@ -375,11 +375,11 @@ assumptions: | $`\mathrm{cyc}^{z}`$ | `Process_output_cyclic_delay` over $`\mathcal{R}`$ — whether a delayed port's transfer wraps from the end of its investment period — PyPSA's `cyclic_delay0`, `cyclic_delay1`, …; where it does not, the energy still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | | $`\mathrm{c}^{z}`$ | `Process_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one unit of internal power | | $`\mathrm{c}^{z,(2)}`$ | `Process_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of the square of one unit of internal power | -| $`\mathrm{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — a given internal power schedule; a process without one has no row here | +| $`\mathrm{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — a given internal power schedule; a process without one has no row here | | $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\Xi \times \mathcal{J}`$ — least nominal power an extendable process may be built at | | $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\Xi \times \mathcal{J}`$ — most nominal power an extendable process may be built at | | $`\mathrm{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\Xi \times \mathcal{J}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, $`0`$ where the data has no row — a given nominal power for an extendable process; one without a value has no row here | +| $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, `absent` where the data has no row — a given nominal power for an extendable process; one without a value has no row here | | $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\Xi \times \mathcal{J}`$ — how many whole modules a committable build has in place: `Process_p_nom / Process_p_nom_mod` where a fixed build is modular, one where it is not, data prep. PyPSA refuses a fixed modular build whose nominal power is not a whole number of modules | | $`\mathrm{nonneg}^{z}`$ | `Process_p_min_pu_nonneg` over $`\mathcal{J}`$ — true where none of the process's own minimums-per-unit is negative — PyPSA's per-unit `(p_min_pu >= 0).all()` over every snapshot and scenario, data prep | @@ -387,7 +387,7 @@ assumptions: | $`\mathrm{act}^{z}`$ | `Process_active_asset` over $`\mathcal{J}`$ — whether a process is one of PyPSA's `active_assets` — its `active` flag alone, without build year and lifetime, so a unit that stands in no snapshot of the horizon still counts. PyPSA refuses one that differs by scenario (`constants.py:51`) | | $`\mathrm{W}^{z}`$ | `Process_capital_weight` over $`\mathcal{J}`$ — the sum of period weights a process stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{new}^{z}`$ | `Process_first_active` over $`\mathcal{Y} \times \mathcal{J}`$ — one in the first period a process stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{J}`$, $`0`$ where the data has no row — one where the process is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{J}`$, `absent` where the data has no row — one where the process is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks diff --git a/docs/examples/pypsa/process_commitment.md b/docs/examples/pypsa/process_commitment.md index c9f927f8..d240d9ed 100644 --- a/docs/examples/pypsa/process_commitment.md +++ b/docs/examples/pypsa/process_commitment.md @@ -104,7 +104,7 @@ parameters: (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep dims: [scenario, process] - missing: 0 + missing: absent variables: Process_status: @@ -302,6 +302,15 @@ constraints: dims: [scenario, snapshot, process] where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 expression: Process_shut_down <= Process_n_mod + +assumptions: + Process_big_m_where_committed_and_extendable: + holds: "Process_big_m" + where: "Process_com_ext" + description: >- + a committable process with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) ``` #### Given @@ -349,7 +358,7 @@ constraints: | $`\mathrm{c}^{z,\mathrm{up}}`$ | `Process_start_up_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one start in this snapshot | | $`\mathrm{c}^{z,\mathrm{dn}}`$ | `Process_shut_down_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{z,\mathrm{on}}`$ | `Process_stand_by_cost` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — cost of one snapshot spent on | -| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — the bound a committed extendable process's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep | +| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — the bound a committed extendable process's big-M rows release it by — the build cap `p_nom_max` times the highest `p_max_pu`, where the cap is finite and positive. Elsewhere it is `committable_big_m` times the highest `p_max_pu`, and where that keyword is not given, ten times the largest of the peak total load and the component's largest finite `p_nom` and `p_nom_max`, or 1e6 where there is none of them (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep | #### Masks @@ -548,4 +557,12 @@ u^{z}_{\xi,t,j} \le N^{z}_{j} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ ```math \mathit{dn}^{z}_{\xi,t,j} \le N^{z}_{j} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com}}_{t,j} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` + +#### Assumptions + +**`Process_big_m_where_committed_and_extendable`** + +```math +\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{t,j} +``` diff --git a/docs/examples/pypsa/process_maintenance.md b/docs/examples/pypsa/process_maintenance.md index 9d1749a3..817ccfc9 100644 --- a/docs/examples/pypsa/process_maintenance.md +++ b/docs/examples/pypsa/process_maintenance.md @@ -67,7 +67,7 @@ parameters: `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, process] - missing: 0 + missing: absent Process_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -277,7 +277,7 @@ assumptions: | $`\mathrm{mnt}^{z}`$ | `Process_maintainable` over $`\mathcal{J}`$ — whether a process must be taken off for maintenance within the horizon — in any scenario, as PyPSA takes the union over them (`components.py:1016-1019`) | | $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\Xi \times \mathcal{J}`$ — the share of the build a maintenance event takes off | | $`\mathrm{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\Xi \times \mathcal{J}`$ — how many maintenance events the horizon holds | -| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the process is not maintainable. No row reads it: data prep turns it into `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon | +| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — the hours of generator weightings one maintenance event covers — PyPSA's `maintenance_duration`; no value where the process is not maintainable. No row reads it: data prep turns it into `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon | | $`\mathrm{blk}^{z}`$ | `Process_maintenance_start_blocked` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$ — true where no maintenance event may start, because the snapshots it would cover run past the end of the horizon or into one the process does not stand in — PyPSA's `active & ~valid`, from `maintenance_duration` and the generator weightings, data prep | #### Masks diff --git a/docs/examples/pypsa/process_ramping.md b/docs/examples/pypsa/process_ramping.md index 1db3b7c7..d4f6f204 100644 --- a/docs/examples/pypsa/process_ramping.md +++ b/docs/examples/pypsa/process_ramping.md @@ -54,19 +54,19 @@ parameters: Process_ramp_limit_up: description: most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_ramp_limit_down: description: most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_ramp_limit_start_up: description: most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_ramp_limit_shut_down: description: most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_p_init: description: >- the internal power a process brought into the horizon — PyPSA's `p_init`, read @@ -288,10 +288,10 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, $`0`$ where the data has no row — most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | -| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit | -| $`\mathrm{rd}^{z,\mathrm{dn}}`$ | `Process_ramp_limit_shut_down` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit | +| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\Xi \times \mathcal{T} \times \mathcal{J}`$, `absent` where the data has no row — most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time | +| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit | +| $`\mathrm{rd}^{z,\mathrm{dn}}`$ | `Process_ramp_limit_shut_down` over $`\Xi \times \mathcal{J}`$, `absent` where the data has no row — most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit | | $`\mathrm{z}^{0}`$ | `Process_p_init` over $`\Xi \times \mathcal{J}`$, $`0`$ where the data has no row — the internal power a process brought into the horizon — PyPSA's `p_init`, read only where the process came in running; no value means it is unknown, so the process carries no ramp row at the first snapshot | #### Masks diff --git a/docs/examples/pypsa/security.md b/docs/examples/pypsa/security.md index 7b316b9c..759a577b 100644 --- a/docs/examples/pypsa/security.md +++ b/docs/examples/pypsa/security.md @@ -71,14 +71,14 @@ parameters: the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) dims: [period, line, outage] - missing: 0 + missing: absent Transformer_BODF: description: >- the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network dims: [period, transformer, outage] - missing: 0 + missing: absent expressions: Outage_s: @@ -222,8 +222,8 @@ constraints: | Symbol | Meaning | |---|---| -| $`\beta`$ | `Line_BODF` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{K}^{\mathrm{out}}`$, $`0`$ where the data has no row — the share of an outaged branch's flow a line takes on when that branch goes out — PyPSA's `BODF`, from the PTDF of the sub-network the period's active branches form, data prep; a row only where the line and the outage are active in the period and share a sub-network, -1 at the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) | -| $`\beta^{\sigma}`$ | `Transformer_BODF` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{K}^{\mathrm{out}}`$, $`0`$ where the data has no row — the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network | +| $`\beta`$ | `Line_BODF` over $`\mathcal{Y} \times \mathcal{K} \times \mathcal{K}^{\mathrm{out}}`$, `absent` where the data has no row — the share of an outaged branch's flow a line takes on when that branch goes out — PyPSA's `BODF`, from the PTDF of the sub-network the period's active branches form, data prep; a row only where the line and the outage are active in the period and share a sub-network, -1 at the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) | +| $`\beta^{\sigma}`$ | `Transformer_BODF` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{K}^{\mathrm{out}}`$, `absent` where the data has no row — the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network | #### Definitions diff --git a/docs/examples/pypsa/storage_unit.md b/docs/examples/pypsa/storage_unit.md index 5fc2b161..1405c8e4 100644 --- a/docs/examples/pypsa/storage_unit.md +++ b/docs/examples/pypsa/storage_unit.md @@ -99,7 +99,7 @@ parameters: StorageUnit_p_nom_set: description: a given nominal power for an extendable storage unit; one without a value has no row here dims: [storage_unit] - missing: 0 + missing: absent StorageUnit_p_nom: description: nominal power dims: [scenario, storage_unit] @@ -190,34 +190,34 @@ parameters: StorageUnit_p_set: description: a given net dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_dispatch_set: description: a given dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_store_set: description: a given charging schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_state_of_charge_set: description: a given charge schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_primary_energy_weight: description: the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent StorageUnit_operational_limit_weight: description: one where the storage unit is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent StorageUnit_tech_capacity_weight: description: >- one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, storage_unit] - missing: 0 + missing: absent variables: StorageUnit_p_dispatch: @@ -579,7 +579,7 @@ assumptions: | $`\underline{\mathrm{h}}^{\mathrm{nom}}`$ | `StorageUnit_p_nom_min` over $`\Xi \times \mathcal{S}`$ — least nominal power an extendable storage unit may be built at | | $`\overline{\mathrm{h}}^{\mathrm{nom}}`$ | `StorageUnit_p_nom_max` over $`\Xi \times \mathcal{S}`$ — most nominal power an extendable storage unit may be built at | | $`\mathrm{c}^{\mathrm{cap},h}`$ | `StorageUnit_capital_cost` over $`\Xi \times \mathcal{S}`$ — cost of one unit of nominal power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, $`0`$ where the data has no row — a given nominal power for an extendable storage unit; one without a value has no row here | +| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, `absent` where the data has no row — a given nominal power for an extendable storage unit; one without a value has no row here | | $`\mathrm{h}^{\mathrm{nom}}`$ | `StorageUnit_p_nom` over $`\Xi \times \mathcal{S}`$ — nominal power | | $`\mathrm{ext}^{h}`$ | `StorageUnit_p_nom_extendable` over $`\mathcal{S}`$ — whether the nominal power is a decision | | $`\mathrm{h}^{\mathrm{mod}}`$ | `StorageUnit_p_nom_mod` over $`\mathcal{S}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | @@ -601,13 +601,13 @@ assumptions: | $`\mathrm{c}^{h,(2)}`$ | `StorageUnit_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of the square of one unit of dispatch; storing is not charged | | $`\mathrm{c}^{\mathrm{soc}}`$ | `StorageUnit_marginal_cost_storage` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of charge held over one snapshot | | $`\mathrm{c}^{\mathrm{spill}}`$ | `StorageUnit_spill_cost` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of inflow passed on unused | -| $`\mathrm{h}^{\mathrm{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given net dispatch schedule; a unit without one has no row here | -| $`\mathrm{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given dispatch schedule; a unit without one has no row here | -| $`\mathrm{h}^{-,\mathrm{set}}`$ | `StorageUnit_p_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given charging schedule; a unit without one has no row here | -| $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, $`0`$ where the data has no row — a given charge schedule; a unit without one has no row here | -| $`\mathrm{a}^{h}`$ | `StorageUnit_primary_energy_weight` over $`\Xi \times \mathcal{G} \times \mathcal{S}`$, $`0`$ where the data has no row — the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row | -| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\Xi \times \mathcal{G} \times \mathcal{S}`$, $`0`$ where the data has no row — one where the storage unit is in the row's set — data prep; one outside it has no row | -| $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{S}`$, $`0`$ where the data has no row — one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{h}^{\mathrm{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given net dispatch schedule; a unit without one has no row here | +| $`\mathrm{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given dispatch schedule; a unit without one has no row here | +| $`\mathrm{h}^{-,\mathrm{set}}`$ | `StorageUnit_p_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given charging schedule; a unit without one has no row here | +| $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `absent` where the data has no row — a given charge schedule; a unit without one has no row here | +| $`\mathrm{a}^{h}`$ | `StorageUnit_primary_energy_weight` over $`\Xi \times \mathcal{G} \times \mathcal{S}`$, `absent` where the data has no row — the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row | +| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\Xi \times \mathcal{G} \times \mathcal{S}`$, `absent` where the data has no row — one where the storage unit is in the row's set — data prep; one outside it has no row | +| $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{S}`$, `absent` where the data has no row — one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Masks diff --git a/docs/examples/pypsa/store.md b/docs/examples/pypsa/store.md index ad440c83..2ee44844 100644 --- a/docs/examples/pypsa/store.md +++ b/docs/examples/pypsa/store.md @@ -99,7 +99,7 @@ parameters: Store_e_nom_set: description: a given nominal capacity for an extendable store; one without a value has no row here dims: [store] - missing: 0 + missing: absent Store_e_nom: description: nominal energy capacity dims: [scenario, store] @@ -175,26 +175,26 @@ parameters: Store_e_set: description: a given energy schedule; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Store_p_set: description: a given schedule of power delivered; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Store_primary_energy_weight: description: the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Store_operational_limit_weight: description: one where the store is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Store_tech_capacity_weight: description: >- one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, store] - missing: 0 + missing: absent variables: Store_e: @@ -462,7 +462,7 @@ assumptions: | $`\underline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_min` over $`\Xi \times \mathcal{V}`$ — least nominal capacity an extendable store may be built at | | $`\overline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_max` over $`\Xi \times \mathcal{V}`$ — most nominal capacity an extendable store may be built at | | $`\mathrm{c}^{\mathrm{cap},e}`$ | `Store_capital_cost` over $`\Xi \times \mathcal{V}`$ — cost of one unit of nominal capacity for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, $`0`$ where the data has no row — a given nominal capacity for an extendable store; one without a value has no row here | +| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, `absent` where the data has no row — a given nominal capacity for an extendable store; one without a value has no row here | | $`\mathrm{e}^{\mathrm{nom}}`$ | `Store_e_nom` over $`\Xi \times \mathcal{V}`$ — nominal energy capacity | | $`\mathrm{ext}^{e}`$ | `Store_e_nom_extendable` over $`\mathcal{V}`$ — whether the nominal energy capacity is a decision | | $`\mathrm{e}^{\mathrm{mod}}`$ | `Store_e_nom_mod` over $`\mathcal{V}`$, `absent` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | @@ -479,11 +479,11 @@ assumptions: | $`\mathrm{c}^{q}`$ | `Store_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of one unit of power delivered | | $`\mathrm{c}^{q,(2)}`$ | `Store_marginal_cost_quadratic` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of the square of the net power delivered, so charging costs as much as delivering | | $`\mathrm{c}^{e}`$ | `Store_marginal_cost_storage` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — cost of one unit of energy held over one snapshot | -| $`\mathrm{e}^{\mathrm{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, $`0`$ where the data has no row — a given energy schedule; a store without one has no row here | -| $`\mathrm{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, $`0`$ where the data has no row — a given schedule of power delivered; a store without one has no row here | -| $`\mathrm{a}^{e}`$ | `Store_primary_energy_weight` over $`\Xi \times \mathcal{G} \times \mathcal{V}`$, $`0`$ where the data has no row — the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row | -| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\Xi \times \mathcal{G} \times \mathcal{V}`$, $`0`$ where the data has no row — one where the store is in the row's set — data prep; one outside it has no row | -| $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{V}`$, $`0`$ where the data has no row — one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | +| $`\mathrm{e}^{\mathrm{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `absent` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\mathrm{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `absent` where the data has no row — a given schedule of power delivered; a store without one has no row here | +| $`\mathrm{a}^{e}`$ | `Store_primary_energy_weight` over $`\Xi \times \mathcal{G} \times \mathcal{V}`$, `absent` where the data has no row — the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row | +| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\Xi \times \mathcal{G} \times \mathcal{V}`$, `absent` where the data has no row — one where the store is in the row's set — data prep; one outside it has no row | +| $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{V}`$, `absent` where the data has no row — one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row | #### Variables diff --git a/docs/examples/pypsa/transformer.md b/docs/examples/pypsa/transformer.md index cff8bd38..f5b2f5fd 100644 --- a/docs/examples/pypsa/transformer.md +++ b/docs/examples/pypsa/transformer.md @@ -107,11 +107,11 @@ parameters: Transformer_s_nom_set: description: a given nominal apparent power for an extendable transformer; one without a value has no row here dims: [transformer] - missing: 0 + missing: absent Transformer_s_set: description: a given flow schedule; a transformer without one has no row here dims: [scenario, snapshot, transformer] - missing: 0 + missing: absent Transformer_v_ang_max: description: >- the most the voltage angle difference across a transformer, its phase @@ -119,7 +119,7 @@ parameters: infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's dims: [scenario, transformer] - missing: 0 + missing: absent Transformer_x_pu_eff: description: >- the transformer's effective series reactance — PyPSA's `x_pu_eff`, `x` @@ -132,7 +132,7 @@ parameters: basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's dims: [period, transformer, cycle] - missing: 0 + missing: absent Transformer_phase_shift_weight: description: >- a fixed transformer's phase shift in radians at each snapshot, signed by @@ -141,7 +141,7 @@ parameters: the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row dims: [snapshot, transformer, cycle] - missing: 0 + missing: absent Transformer_phase_shift_varying: description: >- whether a transformer's phase shift is a decision — PyPSA's @@ -404,12 +404,12 @@ constraints: | $`\underline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_min` over $`\Xi \times \mathcal{M}`$ — least nominal apparent power an extendable transformer may be built at | | $`\overline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_max` over $`\Xi \times \mathcal{M}`$ — most nominal apparent power an extendable transformer may be built at | | $`\mathrm{c}^{\mathrm{cap},\sigma}`$ | `Transformer_capital_cost` over $`\Xi \times \mathcal{M}`$ — cost of one unit of nominal apparent power for the modelled horizon — PyPSA's `periodized_cost`: `overnight_cost` as an annuity over `lifetime` at `discount_rate`, times `nyears`, where it is given, and `capital_cost` where it is not, plus `fom_cost` (`components.py:1126-1147`, `costs.py:102-203`), data prep | -| $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, $`0`$ where the data has no row — a given nominal apparent power for an extendable transformer; one without a value has no row here | -| $`\sigma^{\mathrm{set}}`$ | `Transformer_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, $`0`$ where the data has no row — a given flow schedule; a transformer without one has no row here | -| $`\overline{\delta}^{\sigma}`$ | `Transformer_v_ang_max` over $`\Xi \times \mathcal{M}`$, $`0`$ where the data has no row — the most the voltage angle difference across a transformer, its phase shift included, may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's | +| $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, `absent` where the data has no row — a given nominal apparent power for an extendable transformer; one without a value has no row here | +| $`\sigma^{\mathrm{set}}`$ | `Transformer_s_set` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `absent` where the data has no row — a given flow schedule; a transformer without one has no row here | +| $`\overline{\delta}^{\sigma}`$ | `Transformer_v_ang_max` over $`\Xi \times \mathcal{M}`$, `absent` where the data has no row — the most the voltage angle difference across a transformer, its phase shift included, may be either way, in degrees — PyPSA's `v_ang_max`; infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's | | $`\mathrm{x}^{\mathrm{eff},\sigma}`$ | `Transformer_x_pu_eff` over $`\Xi \times \mathcal{M}`$ — the transformer's effective series reactance — PyPSA's `x_pu_eff`, `x` over its `s_nom` times its tap ratio, data prep | -| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{C}`$, $`0`$ where the data has no row — the transformer's effective series reactance, `x` times its tap ratio, signed by its orientation in the cycle — PyPSA's `x_pu_eff`, the cycle basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's | -| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{T} \times \mathcal{M} \times \mathcal{C}`$, $`0`$ where the data has no row — a fixed transformer's phase shift in radians at each snapshot, signed by its orientation in the cycle — a constant added to the cycle sum, data prep; zero for a varying transformer, whose shift is a decision instead, so the constant and the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row | +| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{Y} \times \mathcal{M} \times \mathcal{C}`$, `absent` where the data has no row — the transformer's effective series reactance, `x` times its tap ratio, signed by its orientation in the cycle — PyPSA's `x_pu_eff`, the cycle basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's | +| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{T} \times \mathcal{M} \times \mathcal{C}`$, `absent` where the data has no row — a fixed transformer's phase shift in radians at each snapshot, signed by its orientation in the cycle — a constant added to the cycle sum, data prep; zero for a varying transformer, whose shift is a decision instead, so the constant and the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row | | $`\mathrm{Transformer\_phase\_shift\_varying}`$ | `Transformer_phase_shift_varying` over $`\mathcal{M}`$ — whether a transformer's phase shift is a decision — PyPSA's `phase_shift_min < phase_shift_max`, read as a flag in data prep; false is a fixed shift carried by `phase_shift`. The shift parameters carry no scenario, but PyPSA reads them per scenario (`variables.py:433-443`, `constraints.py:1652`, `:1735`), so the spec and PyPSA differ here (\#783) | | $`\mathrm{Transformer\_phase\_shift\_min}`$ | `Transformer_phase_shift_min` over $`\mathcal{M}`$ — the least a varying transformer's phase shift may take, in degrees — PyPSA's `phase_shift_min`; where it is below `phase_shift_max` the shift is a decision, otherwise the transformer keeps its fixed `phase_shift` | | $`\mathrm{Transformer\_phase\_shift\_max}`$ | `Transformer_phase_shift_max` over $`\mathcal{M}`$ — the most a varying transformer's phase shift may take, in degrees — PyPSA's `phase_shift_max`; equal to `phase_shift_min` for a fixed transformer | diff --git a/examples/pypsa.yaml b/examples/pypsa.yaml index c605cefd..442dcba8 100644 --- a/examples/pypsa.yaml +++ b/examples/pypsa.yaml @@ -114,19 +114,19 @@ parameters: Generator_ramp_limit_up: description: most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_down: description: most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_start_up: description: most output in the snapshot a unit starts, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_ramp_limit_shut_down: description: most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_min_up_time: description: least snapshots a unit stays on once started dims: [scenario, generator] @@ -191,7 +191,7 @@ parameters: (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep dims: [scenario, generator] - missing: 0 + missing: absent Generator_p_min_pu_nonneg: description: >- true where none of the generator's own minimums-per-unit is negative — @@ -219,7 +219,7 @@ parameters: `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, generator] - missing: 0 + missing: absent Generator_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -231,11 +231,11 @@ parameters: Link_ramp_limit_up: description: most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_ramp_limit_down: description: most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_p_nom: description: nominal power dims: [scenario, link] @@ -286,11 +286,11 @@ parameters: Link_ramp_limit_start_up: description: most flow in the snapshot a link starts, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_ramp_limit_shut_down: description: most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_min_up_time: description: least snapshots a link stays on once started dims: [scenario, link] @@ -355,7 +355,7 @@ parameters: (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep dims: [scenario, link] - missing: 0 + missing: absent Link_p_min_pu_nonneg: description: >- true where none of the link's own minimums-per-unit is negative — @@ -383,7 +383,7 @@ parameters: `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, link] - missing: 0 + missing: absent Link_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -440,15 +440,15 @@ parameters: Process_ramp_limit_up: description: most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_ramp_limit_down: description: most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_p_set: description: a given internal power schedule; a process without one has no row here dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_p_nom_min: description: least nominal power an extendable process may be built at dims: [scenario, process] @@ -466,7 +466,7 @@ parameters: Process_p_nom_set: description: a given nominal power for an extendable process; one without a value has no row here dims: [process] - missing: 0 + missing: absent Process_committable: description: whether internal power is gated by an on/off status decision dims: [process] @@ -474,11 +474,11 @@ parameters: Process_ramp_limit_start_up: description: most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_ramp_limit_shut_down: description: most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_min_up_time: description: least snapshots a process stays on once started dims: [scenario, process] @@ -543,7 +543,7 @@ parameters: (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep dims: [scenario, process] - missing: 0 + missing: absent Process_p_min_pu_nonneg: description: >- true where none of the process's own minimums-per-unit is negative — @@ -571,7 +571,7 @@ parameters: `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, process] - missing: 0 + missing: absent Process_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it @@ -606,7 +606,7 @@ parameters: CVaR_alpha: description: PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` dims: [] - missing: 0 + missing: absent period_weight_objective: description: >- PyPSA's `investment_period_weightings.objective` — what a period's cost @@ -763,7 +763,7 @@ parameters: `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise dims: [carrier] - missing: 0 + missing: absent Carrier_max_relative_growth: description: >- share of the previous period's additions that may be added on top — the @@ -772,11 +772,11 @@ parameters: Generator_p_set: description: a given output schedule; a generator without one has no row here dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Link_p_set: description: a given flow schedule; a link without one has no row here dims: [scenario, snapshot, link] - missing: 0 + missing: absent snapshot_weightings_stores: description: PyPSA's `snapshot_weightings.stores` — hours a snapshot stands for in a storage balance dims: [snapshot] @@ -800,7 +800,7 @@ parameters: Generator_p_nom_set: description: a given nominal power for an extendable generator; one without a value has no row here dims: [generator] - missing: 0 + missing: absent Generator_e_sum_min: description: least energy over the horizon; minus infinity where no floor is meant dims: [scenario, generator] @@ -824,7 +824,7 @@ parameters: Link_p_nom_set: description: a given nominal power for an extendable link; one without a value has no row here dims: [link] - missing: 0 + missing: absent StorageUnit_p_nom_min: description: least nominal power an extendable storage unit may be built at dims: [scenario, storage_unit] @@ -842,7 +842,7 @@ parameters: StorageUnit_p_nom_set: description: a given nominal power for an extendable storage unit; one without a value has no row here dims: [storage_unit] - missing: 0 + missing: absent Store_e_nom_min: description: least nominal capacity an extendable store may be built at dims: [scenario, store] @@ -860,7 +860,7 @@ parameters: Store_e_nom_set: description: a given nominal capacity for an extendable store; one without a value has no row here dims: [store] - missing: 0 + missing: absent StorageUnit_p_nom: description: nominal power dims: [scenario, storage_unit] @@ -951,19 +951,19 @@ parameters: StorageUnit_p_set: description: a given net dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_dispatch_set: description: a given dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_store_set: description: a given charging schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_state_of_charge_set: description: a given charge schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent Store_e_nom: description: nominal energy capacity dims: [scenario, store] @@ -1039,11 +1039,11 @@ parameters: Store_e_set: description: a given energy schedule; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Store_p_set: description: a given schedule of power delivered; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Line_s_nom: description: nominal apparent power dims: [scenario, line] @@ -1075,11 +1075,11 @@ parameters: Line_s_nom_set: description: a given nominal apparent power for an extendable line; one without a value has no row here dims: [line] - missing: 0 + missing: absent Line_s_set: description: a given flow schedule; a line without one has no row here dims: [scenario, snapshot, line] - missing: 0 + missing: absent Line_v_ang_max: description: >- the most the voltage angle difference across a line may be either way, @@ -1088,7 +1088,7 @@ parameters: ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) dims: [scenario, line] - missing: 0 + missing: absent Line_x_pu_eff: description: >- the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over @@ -1100,7 +1100,7 @@ parameters: the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) dims: [period, line, cycle] - missing: 0 + missing: absent Line_BODF: description: >- the share of an outaged branch's flow a line takes on when that branch @@ -1110,7 +1110,7 @@ parameters: the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) dims: [period, line, outage] - missing: 0 + missing: absent transmission_losses: description: >- whether the network dissipates transmission losses — PyPSA's @@ -1167,11 +1167,11 @@ parameters: Transformer_s_nom_set: description: a given nominal apparent power for an extendable transformer; one without a value has no row here dims: [transformer] - missing: 0 + missing: absent Transformer_s_set: description: a given flow schedule; a transformer without one has no row here dims: [scenario, snapshot, transformer] - missing: 0 + missing: absent Transformer_v_ang_max: description: >- the most the voltage angle difference across a transformer, its phase @@ -1179,7 +1179,7 @@ parameters: infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's dims: [scenario, transformer] - missing: 0 + missing: absent Transformer_x_pu_eff: description: >- the transformer's effective series reactance — PyPSA's `x_pu_eff`, `x` @@ -1192,14 +1192,14 @@ parameters: basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's dims: [period, transformer, cycle] - missing: 0 + missing: absent Transformer_BODF: description: >- the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network dims: [period, transformer, outage] - missing: 0 + missing: absent Transformer_phase_shift_weight: description: >- a fixed transformer's phase shift in radians at each snapshot, signed by @@ -1208,7 +1208,7 @@ parameters: the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row dims: [snapshot, transformer, cycle] - missing: 0 + missing: absent Transformer_phase_shift_varying: description: >- whether a transformer's phase shift is a decision — PyPSA's @@ -1298,27 +1298,27 @@ parameters: `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row dims: [scenario, global_constraint, snapshot, generator] - missing: 0 + missing: absent StorageUnit_primary_energy_weight: description: the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent Store_primary_energy_weight: description: the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Generator_operational_limit_weight: description: one where the generator is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, generator] - missing: 0 + missing: absent StorageUnit_operational_limit_weight: description: one where the storage unit is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent Store_operational_limit_weight: description: one where the store is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Line_volume_weight: description: >- the line's length in each scenario where its carrier is in the row's @@ -1326,7 +1326,7 @@ parameters: line outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Link_volume_weight: description: >- the link's length in each scenario where its carrier is in the row's @@ -1334,7 +1334,7 @@ parameters: link outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Line_expansion_cost_weight: description: >- the line's capital cost where its carrier is in the row's set, times @@ -1345,7 +1345,7 @@ parameters: `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Link_expansion_cost_weight: description: >- the link's capital cost where its carrier is in the row's set, times @@ -1356,49 +1356,49 @@ parameters: `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Generator_tech_capacity_weight: description: >- one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, generator] - missing: 0 + missing: absent Link_tech_capacity_weight: description: >- one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, link] - missing: 0 + missing: absent Line_tech_capacity_weight: description: >- one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, line] - missing: 0 + missing: absent StorageUnit_tech_capacity_weight: description: >- one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, storage_unit] - missing: 0 + missing: absent Store_tech_capacity_weight: description: >- one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, store] - missing: 0 + missing: absent Process_tech_capacity_weight: description: >- one where the process is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, process] - missing: 0 + missing: absent relations: snapshot_period: @@ -4375,6 +4375,27 @@ constraints: expression: CVaR_theta + 1 / (1 - CVaR_alpha) * sum(scenario_weight * CVaR_a, over=scenario) <= CVaR assumptions: + Generator_big_m_where_committed_and_extendable: + holds: "Generator_big_m" + where: "Generator_com_ext" + description: >- + a committable generator with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) + Link_big_m_where_committed_and_extendable: + holds: "Link_big_m" + where: "Link_com_ext" + description: >- + a committable link with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) + Process_big_m_where_committed_and_extendable: + holds: "Process_big_m" + where: "Process_com_ext" + description: >- + a committable process with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) Generator_maintenance_events_positive: holds: "Generator_maintenance_events > 0" where: "Generator_maintainable" diff --git a/examples/pypsa/carrier.yaml b/examples/pypsa/carrier.yaml index 8f483beb..ed0ef48e 100644 --- a/examples/pypsa/carrier.yaml +++ b/examples/pypsa/carrier.yaml @@ -23,7 +23,7 @@ parameters: `multi_investment_periods` (`global_constraints.py:220-221`), so data prep feeds no value otherwise dims: [carrier] - missing: 0 + missing: absent Carrier_max_relative_growth: description: >- share of the previous period's additions that may be added on top — the diff --git a/examples/pypsa/cost.yaml b/examples/pypsa/cost.yaml index 845a4953..a4a4bdd7a 100644 --- a/examples/pypsa/cost.yaml +++ b/examples/pypsa/cost.yaml @@ -18,7 +18,7 @@ parameters: CVaR_alpha: description: PyPSA's `risk_preference['alpha']` — the confidence level; the tail holds the other `1 - alpha` of the probability. Data prep writes a row where it writes `CVaR_omega` dims: [] - missing: 0 + missing: absent variables: CVaR_a: diff --git a/examples/pypsa/generator.yaml b/examples/pypsa/generator.yaml index c9c708e4..06737f43 100644 --- a/examples/pypsa/generator.yaml +++ b/examples/pypsa/generator.yaml @@ -124,7 +124,7 @@ parameters: Generator_p_set: description: a given output schedule; a generator without one has no row here dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_p_nom_min: description: least nominal power an extendable generator may be built at dims: [scenario, generator] @@ -142,7 +142,7 @@ parameters: Generator_p_nom_set: description: a given nominal power for an extendable generator; one without a value has no row here dims: [generator] - missing: 0 + missing: absent Generator_e_sum_min: description: least energy over the horizon; minus infinity where no floor is meant dims: [scenario, generator] @@ -155,18 +155,18 @@ parameters: `co2_emissions` over the generator's efficiency at the snapshot, data prep; a generator of an unweighted carrier has no row dims: [scenario, global_constraint, snapshot, generator] - missing: 0 + missing: absent Generator_operational_limit_weight: description: one where the generator is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, generator] - missing: 0 + missing: absent Generator_tech_capacity_weight: description: >- one where the generator is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, generator] - missing: 0 + missing: absent variables: Generator_p: diff --git a/examples/pypsa/generator_commitment.yaml b/examples/pypsa/generator_commitment.yaml index 8478caa8..00cf647e 100644 --- a/examples/pypsa/generator_commitment.yaml +++ b/examples/pypsa/generator_commitment.yaml @@ -97,7 +97,7 @@ parameters: (`components.py:1050-1121`). Below the output a solve wants, it caps that output; data prep dims: [scenario, generator] - missing: 0 + missing: absent variables: Generator_status: @@ -295,3 +295,12 @@ constraints: dims: [scenario, snapshot, generator] where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 expression: Generator_shut_down <= Generator_n_mod + +assumptions: + Generator_big_m_where_committed_and_extendable: + holds: "Generator_big_m" + where: "Generator_com_ext" + description: >- + a committable generator with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) diff --git a/examples/pypsa/generator_maintenance.yaml b/examples/pypsa/generator_maintenance.yaml index 08bed071..a332d189 100644 --- a/examples/pypsa/generator_maintenance.yaml +++ b/examples/pypsa/generator_maintenance.yaml @@ -60,7 +60,7 @@ parameters: `Generator_maintenance_cover` and `Generator_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, generator] - missing: 0 + missing: absent Generator_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it diff --git a/examples/pypsa/generator_ramping.yaml b/examples/pypsa/generator_ramping.yaml index 1ed191cd..27798482 100644 --- a/examples/pypsa/generator_ramping.yaml +++ b/examples/pypsa/generator_ramping.yaml @@ -47,19 +47,19 @@ parameters: Generator_ramp_limit_up: description: most a generator may raise its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_down: description: most a generator may lower its output between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, generator] - missing: 0 + missing: absent Generator_ramp_limit_start_up: description: most output in the snapshot a unit starts, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_ramp_limit_shut_down: description: most output in the snapshot before a unit stops, per unit of nominal power; no value means no limit dims: [scenario, generator] - missing: 0 + missing: absent Generator_p_init: description: >- the output a unit brought into the horizon — PyPSA's `p_init`, read diff --git a/examples/pypsa/line.yaml b/examples/pypsa/line.yaml index a821a06c..a294fb8b 100644 --- a/examples/pypsa/line.yaml +++ b/examples/pypsa/line.yaml @@ -117,11 +117,11 @@ parameters: Line_s_nom_set: description: a given nominal apparent power for an extendable line; one without a value has no row here dims: [line] - missing: 0 + missing: absent Line_s_set: description: a given flow schedule; a line without one has no row here dims: [scenario, snapshot, line] - missing: 0 + missing: absent Line_v_ang_max: description: >- the most the voltage angle difference across a line may be either way, @@ -130,7 +130,7 @@ parameters: ignored, as PyPSA ignores it with a `DeprecationWarning` (`constraints.py:1702-1709`) dims: [scenario, line] - missing: 0 + missing: absent Line_x_pu_eff: description: >- the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over @@ -142,7 +142,7 @@ parameters: the cycle basis, data prep; a line in no cycle has no row. PyPSA builds the cycle basis from the first scenario only (`networks.py:1430-1437`) dims: [period, line, cycle] - missing: 0 + missing: absent Line_loss_max: description: the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep dims: [scenario, snapshot, line] @@ -164,7 +164,7 @@ parameters: line outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Line_expansion_cost_weight: description: >- the line's capital cost where its carrier is in the row's set, times @@ -175,14 +175,14 @@ parameters: `Line_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, line] - missing: 0 + missing: absent Line_tech_capacity_weight: description: >- one where the line is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, line] - missing: 0 + missing: absent variables: Line_s: diff --git a/examples/pypsa/link.yaml b/examples/pypsa/link.yaml index 2ecde6cb..a1775be4 100644 --- a/examples/pypsa/link.yaml +++ b/examples/pypsa/link.yaml @@ -157,7 +157,7 @@ parameters: Link_p_set: description: a given flow schedule; a link without one has no row here dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_p_nom_min: description: least nominal power an extendable link may be built at dims: [scenario, link] @@ -175,7 +175,7 @@ parameters: Link_p_nom_set: description: a given nominal power for an extendable link; one without a value has no row here dims: [link] - missing: 0 + missing: absent Link_volume_weight: description: >- the link's length in each scenario where its carrier is in the row's @@ -183,7 +183,7 @@ parameters: link outside it, or one that does not stand in the row's `investment_period`, has no row dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Link_expansion_cost_weight: description: >- the link's capital cost where its carrier is in the row's set, times @@ -194,14 +194,14 @@ parameters: `Link_capital_cost` without `fom_cost` (`components.py:1151-1169`, `global_constraints.py:870-879`) dims: [scenario, global_constraint, link] - missing: 0 + missing: absent Link_tech_capacity_weight: description: >- one where the link is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, link] - missing: 0 + missing: absent variables: Link_p: diff --git a/examples/pypsa/link_commitment.yaml b/examples/pypsa/link_commitment.yaml index 86685920..c451d2c5 100644 --- a/examples/pypsa/link_commitment.yaml +++ b/examples/pypsa/link_commitment.yaml @@ -97,7 +97,7 @@ parameters: (`components.py:1050-1121`). Below the flow a solve wants, it caps that flow; data prep dims: [scenario, link] - missing: 0 + missing: absent variables: Link_status: @@ -295,3 +295,12 @@ constraints: dims: [scenario, snapshot, link] where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 expression: Link_shut_down <= Link_n_mod + +assumptions: + Link_big_m_where_committed_and_extendable: + holds: "Link_big_m" + where: "Link_com_ext" + description: >- + a committable link with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) diff --git a/examples/pypsa/link_maintenance.yaml b/examples/pypsa/link_maintenance.yaml index 84f6840b..1ce4cacf 100644 --- a/examples/pypsa/link_maintenance.yaml +++ b/examples/pypsa/link_maintenance.yaml @@ -60,7 +60,7 @@ parameters: `Link_maintenance_cover` and `Link_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, link] - missing: 0 + missing: absent Link_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it diff --git a/examples/pypsa/link_ramping.yaml b/examples/pypsa/link_ramping.yaml index 106ad851..4873ffa8 100644 --- a/examples/pypsa/link_ramping.yaml +++ b/examples/pypsa/link_ramping.yaml @@ -47,19 +47,19 @@ parameters: Link_ramp_limit_up: description: most a link may raise its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_ramp_limit_down: description: most a link may lower its flow between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, link] - missing: 0 + missing: absent Link_ramp_limit_start_up: description: most flow in the snapshot a link starts, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_ramp_limit_shut_down: description: most flow in the snapshot before a link stops, per unit of nominal power; no value means no limit dims: [scenario, link] - missing: 0 + missing: absent Link_p_init: description: >- the flow a link brought into the horizon — PyPSA's `p_init`, read diff --git a/examples/pypsa/process.yaml b/examples/pypsa/process.yaml index 87c97076..3664f2f8 100644 --- a/examples/pypsa/process.yaml +++ b/examples/pypsa/process.yaml @@ -116,7 +116,7 @@ parameters: Process_p_set: description: a given internal power schedule; a process without one has no row here dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_p_nom_min: description: least nominal power an extendable process may be built at dims: [scenario, process] @@ -134,7 +134,7 @@ parameters: Process_p_nom_set: description: a given nominal power for an extendable process; one without a value has no row here dims: [process] - missing: 0 + missing: absent Process_p_nom_mod: description: the module size a build comes in whole numbers of; no value means the build is continuous dims: [process] @@ -178,7 +178,7 @@ parameters: outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, process] - missing: 0 + missing: absent variables: Process_p: diff --git a/examples/pypsa/process_commitment.yaml b/examples/pypsa/process_commitment.yaml index 4fa0b7fc..c75fab56 100644 --- a/examples/pypsa/process_commitment.yaml +++ b/examples/pypsa/process_commitment.yaml @@ -97,7 +97,7 @@ parameters: (`components.py:1050-1121`). Below the internal power a solve wants, it caps that internal power; data prep dims: [scenario, process] - missing: 0 + missing: absent variables: Process_status: @@ -295,3 +295,12 @@ constraints: dims: [scenario, snapshot, process] where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 expression: Process_shut_down <= Process_n_mod + +assumptions: + Process_big_m_where_committed_and_extendable: + holds: "Process_big_m" + where: "Process_com_ext" + description: >- + a committable process with an extendable, non-modular build has + the big-M its rows release it by — PyPSA computes one for each + (`get_committable_big_m_values`) diff --git a/examples/pypsa/process_maintenance.yaml b/examples/pypsa/process_maintenance.yaml index 17155b7e..71348d60 100644 --- a/examples/pypsa/process_maintenance.yaml +++ b/examples/pypsa/process_maintenance.yaml @@ -60,7 +60,7 @@ parameters: `Process_maintenance_cover` and `Process_maintenance_start_blocked`, and the assumptions hold it to the horizon dims: [scenario, process] - missing: 0 + missing: absent Process_maintenance_start_blocked: description: >- true where no maintenance event may start, because the snapshots it diff --git a/examples/pypsa/process_ramping.yaml b/examples/pypsa/process_ramping.yaml index c7f56cb3..2da3efad 100644 --- a/examples/pypsa/process_ramping.yaml +++ b/examples/pypsa/process_ramping.yaml @@ -47,19 +47,19 @@ parameters: Process_ramp_limit_up: description: most a process may raise its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_ramp_limit_down: description: most a process may lower its internal power between snapshots, per unit of nominal power; no value means no limit — read at the later of the two snapshots, so the limit may change over time dims: [scenario, snapshot, process] - missing: 0 + missing: absent Process_ramp_limit_start_up: description: most internal power in the snapshot a process starts, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_ramp_limit_shut_down: description: most internal power in the snapshot before a process stops, per unit of nominal power; no value means no limit dims: [scenario, process] - missing: 0 + missing: absent Process_p_init: description: >- the internal power a process brought into the horizon — PyPSA's `p_init`, read diff --git a/examples/pypsa/security.yaml b/examples/pypsa/security.yaml index 32a9b0c8..b0d7ccd8 100644 --- a/examples/pypsa/security.yaml +++ b/examples/pypsa/security.yaml @@ -64,14 +64,14 @@ parameters: the outaged line itself. The factors are the same in every scenario, because PyPSA takes those of the first scenario (`abstract.py:534`) dims: [period, line, outage] - missing: 0 + missing: absent Transformer_BODF: description: >- the share of an outaged branch's flow a transformer takes on when that branch goes out, as a line's; a row only where the transformer and the outage are active in the period and share a sub-network dims: [period, transformer, outage] - missing: 0 + missing: absent expressions: Outage_s: diff --git a/examples/pypsa/storage_unit.yaml b/examples/pypsa/storage_unit.yaml index 1c5aac6c..7db4dd71 100644 --- a/examples/pypsa/storage_unit.yaml +++ b/examples/pypsa/storage_unit.yaml @@ -92,7 +92,7 @@ parameters: StorageUnit_p_nom_set: description: a given nominal power for an extendable storage unit; one without a value has no row here dims: [storage_unit] - missing: 0 + missing: absent StorageUnit_p_nom: description: nominal power dims: [scenario, storage_unit] @@ -183,34 +183,34 @@ parameters: StorageUnit_p_set: description: a given net dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_dispatch_set: description: a given dispatch schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_p_store_set: description: a given charging schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_state_of_charge_set: description: a given charge schedule; a unit without one has no row here dims: [scenario, snapshot, storage_unit] - missing: 0 + missing: absent StorageUnit_primary_energy_weight: description: the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent StorageUnit_operational_limit_weight: description: one where the storage unit is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, storage_unit] - missing: 0 + missing: absent StorageUnit_tech_capacity_weight: description: >- one where the storage unit is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, storage_unit] - missing: 0 + missing: absent variables: StorageUnit_p_dispatch: diff --git a/examples/pypsa/store.yaml b/examples/pypsa/store.yaml index bb3b6d4c..73c4b4e9 100644 --- a/examples/pypsa/store.yaml +++ b/examples/pypsa/store.yaml @@ -92,7 +92,7 @@ parameters: Store_e_nom_set: description: a given nominal capacity for an extendable store; one without a value has no row here dims: [store] - missing: 0 + missing: absent Store_e_nom: description: nominal energy capacity dims: [scenario, store] @@ -168,26 +168,26 @@ parameters: Store_e_set: description: a given energy schedule; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Store_p_set: description: a given schedule of power delivered; a store without one has no row here dims: [scenario, snapshot, store] - missing: 0 + missing: absent Store_primary_energy_weight: description: the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Store_operational_limit_weight: description: one where the store is in the row's set — data prep; one outside it has no row dims: [scenario, global_constraint, store] - missing: 0 + missing: absent Store_tech_capacity_weight: description: >- one where the store is in the row's carrier-and-bus set — data prep; one outside it, or one that does not stand in the row's `investment_period`, has no row dims: [global_constraint, store] - missing: 0 + missing: absent variables: Store_e: diff --git a/examples/pypsa/transformer.yaml b/examples/pypsa/transformer.yaml index f2f824e0..54f3fe71 100644 --- a/examples/pypsa/transformer.yaml +++ b/examples/pypsa/transformer.yaml @@ -100,11 +100,11 @@ parameters: Transformer_s_nom_set: description: a given nominal apparent power for an extendable transformer; one without a value has no row here dims: [transformer] - missing: 0 + missing: absent Transformer_s_set: description: a given flow schedule; a transformer without one has no row here dims: [scenario, snapshot, transformer] - missing: 0 + missing: absent Transformer_v_ang_max: description: >- the most the voltage angle difference across a transformer, its phase @@ -112,7 +112,7 @@ parameters: infinite, and so no row, by default. The deprecated `v_ang_min` is ignored, as a line's dims: [scenario, transformer] - missing: 0 + missing: absent Transformer_x_pu_eff: description: >- the transformer's effective series reactance — PyPSA's `x_pu_eff`, `x` @@ -125,7 +125,7 @@ parameters: basis, data prep; a transformer in no cycle has no row. From the first scenario only, as a line's dims: [period, transformer, cycle] - missing: 0 + missing: absent Transformer_phase_shift_weight: description: >- a fixed transformer's phase shift in radians at each snapshot, signed by @@ -134,7 +134,7 @@ parameters: the variable term never both count a shift. A transformer with no shift or in no cycle of its snapshot's period has no row dims: [snapshot, transformer, cycle] - missing: 0 + missing: absent Transformer_phase_shift_varying: description: >- whether a transformer's phase shift is a decision — PyPSA's From 8cdfc3bcce550079e4b12c89e5f50acd64492fa1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 15:32:34 +0000 Subject: [PATCH 2/3] docs(changelog): link the line to its pull request Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e049881..e7c31e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ it releases that version ([RELEASING.md](https://github.com/energy-models/mathsp ## Upcoming version -- docs(pypsa): a PyPSA schedule, weight or limit that the data leaves out is absent rather than zero, and a committable extendable unit is assumed to have its big-M ([#PR](https://github.com/energy-models/mathspec/pull/PR)) +- docs(pypsa): a PyPSA schedule, weight or limit that the data leaves out is absent rather than zero, and a committable extendable unit is assumed to have its big-M ([#912](https://github.com/energy-models/mathspec/pull/912)) - feat(language)!: a missing row reads as the value the file names, and `missing: neutral` is gone ([#894](https://github.com/energy-models/mathspec/pull/894)) - docs: the changelog is listed under Reference rather than About ([#895](https://github.com/energy-models/mathspec/pull/895)) - docs(pypsa): an extendable unit has a capacity to choose exactly where its active flag is set, as in PyPSA ([#886](https://github.com/energy-models/mathspec/pull/886)) From 6c6afb925d70017ff43380855b5e67ddead5f46e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 06:23:42 +0000 Subject: [PATCH 3/3] docs(pypsa): regenerate the gallery pages on the merged base The big-M assumptions print their condition's indices sorted by name, as #911 prints every derived frame. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6 --- docs/examples/pypsa.md | 6 +++--- docs/examples/pypsa/generator_commitment.md | 2 +- docs/examples/pypsa/link_commitment.md | 2 +- docs/examples/pypsa/process_commitment.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/examples/pypsa.md b/docs/examples/pypsa.md index 73531564..db2aff67 100644 --- a/docs/examples/pypsa.md +++ b/docs/examples/pypsa.md @@ -12434,7 +12434,7 @@ Generator_big_m_where_committed_and_extendable: ``` ```math -\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{t,g} +\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` ### `Link_big_m_where_committed_and_extendable` @@ -12450,7 +12450,7 @@ Link_big_m_where_committed_and_extendable: ``` ```math -\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{t,l} +\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` ### `Process_big_m_where_committed_and_extendable` @@ -12466,7 +12466,7 @@ Process_big_m_where_committed_and_extendable: ``` ```math -\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{t,j} +\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` ### `Generator_maintenance_events_positive` diff --git a/docs/examples/pypsa/generator_commitment.md b/docs/examples/pypsa/generator_commitment.md index ab5610c7..60de7a02 100644 --- a/docs/examples/pypsa/generator_commitment.md +++ b/docs/examples/pypsa/generator_commitment.md @@ -563,6 +563,6 @@ u_{\xi,t,g} \le N_{g} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \ **`Generator_big_m_where_committed_and_extendable`** ```math -\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{t,g} +\mathrm{M}_{\xi,g} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ g \in \mathcal{G} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` diff --git a/docs/examples/pypsa/link_commitment.md b/docs/examples/pypsa/link_commitment.md index 1ff65240..cf27e4f8 100644 --- a/docs/examples/pypsa/link_commitment.md +++ b/docs/examples/pypsa/link_commitment.md @@ -563,6 +563,6 @@ u^{f}_{\xi,t,l} \le N^{f}_{l} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ **`Link_big_m_where_committed_and_extendable`** ```math -\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{t,l} +\mathrm{M}^{f}_{\xi,l} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ l \in \mathcal{L} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` diff --git a/docs/examples/pypsa/process_commitment.md b/docs/examples/pypsa/process_commitment.md index ddf188ab..62ad9998 100644 --- a/docs/examples/pypsa/process_commitment.md +++ b/docs/examples/pypsa/process_commitment.md @@ -563,6 +563,6 @@ u^{z}_{\xi,t,j} \le N^{z}_{j} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ **`Process_big_m_where_committed_and_extendable`** ```math -\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{t,j} +\mathrm{M}^{z}_{\xi,j} \text{ is defined} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ j \in \mathcal{J} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ```