diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ddfa4ef..99146dcb 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 +- feat(spec): the entries of each section and the regions under `cases:` are sorted by name as a spec loads, so every output lists them in that order ([#921](https://github.com/energy-models/mathspec/pull/921)) - feat(spec): a spec writes back the fields its file wrote, and the canonical form writes no default ([#918](https://github.com/energy-models/mathspec/pull/918)) - feat(spec): a loaded spec holds each `dims:` list and each side of a relation sorted by name ([#916](https://github.com/energy-models/mathspec/pull/916)) - feat(language)!: every entry is indexed by its dimensions sorted by name, whatever order the file writes them in ([#914](https://github.com/energy-models/mathspec/pull/914)) diff --git a/README.md b/README.md index 32797e53..aee741ff 100644 --- a/README.md +++ b/README.md @@ -120,16 +120,16 @@ Least-cost dispatch of a generator fleet against an hourly load. | Symbol | Meaning | |---|---| -| $`\mathcal{S}`$ | index $`s`$ — `snapshot` — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units | +| $`\mathcal{S}`$ | index $`s`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| | $`\bar p`$ | `capacity` over $`\mathcal{G}`$ — installed capacity | -| $`\ell`$ | `load` over $`\mathcal{S}`$ — demand to be met | | $`c`$ | `cost` over $`\mathcal{G}`$ — marginal cost | +| $`\ell`$ | `load` over $`\mathcal{S}`$ — demand to be met | #### Variables diff --git a/docs/examples/commitment.md b/docs/examples/commitment.md index 20958f38..52d84821 100644 --- a/docs/examples/commitment.md +++ b/docs/examples/commitment.md @@ -102,21 +102,21 @@ Unit commitment with a start-up ramp, the formulation `cases:` exists for. The s | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{committable}`$ | `committable` over $`\mathcal{G}`$ — whether the unit may be switched off | -| $`\mathrm{status}^{\mathrm{initial}}`$ | `status_initial` over $`\mathcal{G}`$ — whether the unit was running before the horizon | | $`\mathrm{capacity}`$ | `capacity` over $`\mathcal{G}`$ — installed capacity | +| $`\mathrm{committable}`$ | `committable` over $`\mathcal{G}`$ — whether the unit may be switched off | +| $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$ — marginal cost | +| $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | | $`\mathrm{min\_output}`$ | `min_output` over $`\mathcal{G}`$ — output floor while running | | $`\mathrm{ramp\_limit}`$ | `ramp_limit` over $`\mathcal{G}`$ — how far output may move between snapshots while running | | $`\mathrm{start\_up\_limit}`$ | `start_up_limit` over $`\mathcal{G}`$ — how far it may move in the snapshot it starts in | -| $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | -| $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$ — marginal cost | +| $`\mathrm{status}^{\mathrm{initial}}`$ | `status_initial` over $`\mathcal{G}`$ — whether the unit was running before the horizon | #### Variables @@ -168,28 +168,28 @@ Unit commitment with a start-up ramp, the formulation `cases:` exists for. The s #### Subject to -**`power_balance`** +**`lower`** ```math -\sum_{g \in \mathcal{G}} \mathit{dispatch}_{g,t} = \mathrm{load}_{t} \qquad \forall\, t \in \mathcal{T} +\mathit{dispatch}_{g,t} \ge \mathit{status}_{g,t} \cdot \mathrm{min\_output}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`upper`** +**`power_balance`** ```math -\mathit{dispatch}_{g,t} \le \mathit{status}_{g,t} \cdot \mathrm{capacity}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G}} \mathit{dispatch}_{g,t} = \mathrm{load}_{t} \qquad \forall\, t \in \mathcal{T} ``` -**`lower`** +**`ramp_up`** ```math -\mathit{dispatch}_{g,t} \ge \mathit{status}_{g,t} \cdot \mathrm{min\_output}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{dispatch}_{g,t} - \mathit{dispatch}_{g,t \boxminus_{0} 1} \le \mathrm{ramp\_limit}_{g} \cdot \mathit{previous\_status}_{g,t} + \mathrm{start\_up\_limit}_{g} \cdot \left( 1 - \mathit{previous\_status}_{g,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`ramp_up`** +**`upper`** ```math -\mathit{dispatch}_{g,t} - \mathit{dispatch}_{g,t \boxminus_{0} 1} \le \mathrm{ramp\_limit}_{g} \cdot \mathit{previous\_status}_{g,t} + \mathrm{start\_up\_limit}_{g} \cdot \left( 1 - \mathit{previous\_status}_{g,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{dispatch}_{g,t} \le \mathit{status}_{g,t} \cdot \mathrm{capacity}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` #### Assumptions diff --git a/docs/examples/dispatch.md b/docs/examples/dispatch.md index cfb2f7da..0d02781e 100644 --- a/docs/examples/dispatch.md +++ b/docs/examples/dispatch.md @@ -50,16 +50,16 @@ Least-cost dispatch of a generator fleet against an hourly load. | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| | $`\mathrm{capacity}`$ | `capacity` over $`\mathcal{G}`$ — installed capacity | -| $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | | $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$ — marginal cost | +| $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | #### Variables diff --git a/docs/examples/library/composed.md b/docs/examples/library/composed.md index 32fe7a34..9cccf191 100644 --- a/docs/examples/library/composed.md +++ b/docs/examples/library/composed.md @@ -41,33 +41,33 @@ the tab prints the patch beside that math. ```yaml version: 0 dimensions: - snapshot: {dtype: datetime, description: dispatch periods} bus: {dtype: str, description: network nodes} - port: {dtype: str, description: 'the connections components make, one label per connection'} generator: {dtype: str, description: 'generating units, each on one port'} load: {dtype: str, description: 'demands, each on one port'} + port: {dtype: str, description: 'the connections components make, one label per connection'} + snapshot: {dtype: datetime, description: dispatch periods} relations: - Port_bus: {key: port, values: bus} Generator_port: {key: generator, values: port} Load_port: {key: load, values: port} + Port_bus: {key: port, values: bus} parameters: - Generator_p_nom: - dims: [generator] - description: nominal power Generator_marginal_cost: dims: [generator] description: cost of one unit of output + Generator_p_nom: + dims: [generator] + description: nominal power Load_p_set: dims: [load, snapshot] description: '`Load-p_set` — what a load takes in a snapshot' variables: - Port_p: - dims: [port, snapshot] - description: what a port puts into its bus in a snapshot, negative for a withdrawal Generator_p: dims: [generator, snapshot] bounds: {lower: 0.0, upper: Generator_p_nom} description: '`Generator-p` — what a generator produces in a snapshot' + Port_p: + dims: [port, snapshot] + description: what a port puts into its bus in a snapshot, negative for a withdrawal expressions: Generator_cost: sum(Generator_p * Generator_marginal_cost) total_cost: @@ -98,26 +98,26 @@ constraints: | Symbol | Meaning | |---|---| - | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — network nodes | - | $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N},\ \mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J},\ \mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — the connections components make, one label per connection | | $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J}`$ — generating units, each on one port | | $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — demands, each on one port | + | $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J},\ \mathrm{Load\_port}: \mathcal{D} \to \mathcal{J},\ \mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — the connections components make, one label per connection | + | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| - | $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | | $`\mathrm{c}`$ | `Generator_marginal_cost` over $`\mathcal{G}`$ — cost of one unit of output | + | $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | | $`\mathrm{load}`$ | `Load_p_set` over $`\mathcal{D} \times \mathcal{T}`$ — `Load-p_set` — what a load takes in a snapshot | #### Variables | Symbol | Meaning | |---|---| - | $`f`$ | `Port_p` over $`\mathcal{J} \times \mathcal{T}`$ — what a port puts into its bus in a snapshot, negative for a withdrawal | | $`p`$ | `Generator_p` over $`\mathcal{G} \times \mathcal{T}`$ — `Generator-p` — what a generator produces in a snapshot | + | $`f`$ | `Port_p` over $`\mathcal{J} \times \mathcal{T}`$ — what a port puts into its bus in a snapshot, negative for a withdrawal | #### Definitions @@ -128,16 +128,16 @@ constraints: #### Variable domains - **`Port_p`** + **`Generator_p`** ```math - f_{j,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} + 0 \le p_{g,t} \le \mathrm{p}^{\mathrm{nom}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` - **`Generator_p`** + **`Port_p`** ```math - 0 \le p_{g,t} \le \mathrm{p}^{\mathrm{nom}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} + f_{j,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} ``` #### Definitions @@ -206,28 +206,28 @@ constraints: | Symbol | Meaning | |---|---| - | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — network nodes | - | $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N},\ \mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J},\ \mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — the connections components make, one label per connection | | $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J}`$ — generating units, each on one port | | $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — demands, each on one port | + | $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J},\ \mathrm{Load\_port}: \mathcal{D} \to \mathcal{J},\ \mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — the connections components make, one label per connection | + | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| - | $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | | $`\mathrm{c}`$ | `Generator_marginal_cost` over $`\mathcal{G}`$ — cost of one unit of output | - | $`\mathrm{load}`$ | `Load_p_set` over $`\mathcal{D} \times \mathcal{T}`$ — `Load-p_set` — what a load takes in a snapshot | | $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G}`$ — least output, per unit of nominal power | + | $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | + | $`\mathrm{load}`$ | `Load_p_set` over $`\mathcal{D} \times \mathcal{T}`$ — `Load-p_set` — what a load takes in a snapshot | #### Variables | Symbol | Meaning | |---|---| - | $`f`$ | `Port_p` over $`\mathcal{J} \times \mathcal{T}`$ — what a port puts into its bus in a snapshot, negative for a withdrawal | | $`p`$ | `Generator_p` over $`\mathcal{G} \times \mathcal{T}`$ — `Generator-p` — what a generator produces in a snapshot | | $`u`$ | `Generator_status` over $`\mathcal{G} \times \mathcal{T}`$ — `Generator-status` — whether a unit is on in a snapshot | + | $`f`$ | `Port_p` over $`\mathcal{J} \times \mathcal{T}`$ — what a port puts into its bus in a snapshot, negative for a withdrawal | #### Definitions @@ -238,12 +238,6 @@ constraints: #### Variable domains - **`Port_p`** - - ```math - f_{j,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} - ``` - **`Generator_p`** ```math @@ -256,6 +250,12 @@ constraints: u_{g,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` + **`Port_p`** + + ```math + f_{j,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} + ``` + #### Definitions **`Generator_cost`** @@ -284,27 +284,27 @@ constraints: \sum_{j \in \mathcal{J} \,:\, \mathrm{Port\_bus}(j) = n} f_{j,t} = 0 \qquad \forall\, n \in \mathcal{N},\ t \in \mathcal{T} ``` - **`Generator_injection`** + **`Generator_com_p_lower`** ```math - f_{\mathrm{Generator\_port}(g),t} = p_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} + p_{g,t} \ge \underline{\mathrm{p}}_{g} \cdot \mathrm{p}^{\mathrm{nom}}_{g} \cdot u_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` - **`Load_withdrawal`** + **`Generator_com_p_upper`** ```math - f_{\mathrm{Load\_port}(d),t} = -\mathrm{load}_{d,t} \qquad \forall\, d \in \mathcal{D},\ t \in \mathcal{T} + p_{g,t} \le \mathrm{p}^{\mathrm{nom}}_{g} \cdot u_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` - **`Generator_com_p_upper`** + **`Generator_injection`** ```math - p_{g,t} \le \mathrm{p}^{\mathrm{nom}}_{g} \cdot u_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} + f_{\mathrm{Generator\_port}(g),t} = p_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` - **`Generator_com_p_lower`** + **`Load_withdrawal`** ```math - p_{g,t} \ge \underline{\mathrm{p}}_{g} \cdot \mathrm{p}^{\mathrm{nom}}_{g} \cdot u_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} + f_{\mathrm{Load\_port}(d),t} = -\mathrm{load}_{d,t} \qquad \forall\, d \in \mathcal{D},\ t \in \mathcal{T} ``` diff --git a/docs/examples/library/generator.md b/docs/examples/library/generator.md index e5c578eb..9891a7bd 100644 --- a/docs/examples/library/generator.md +++ b/docs/examples/library/generator.md @@ -79,16 +79,16 @@ PyPSA's `Generator`, wired to a port rather than straight to a bus, and cut to w | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | -| $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J}`$ — the connections components make, one label per connection | | $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J}`$ — generating units, each on one port | +| $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Generator\_port}: \mathcal{G} \to \mathcal{J}`$ — the connections components make, one label per connection | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | | $`\mathrm{c}`$ | `Generator_marginal_cost` over $`\mathcal{G}`$ — cost of one unit of output | +| $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G}`$ — nominal power | #### Variables diff --git a/docs/examples/library/load.md b/docs/examples/library/load.md index d1f6ffcd..05d567d3 100644 --- a/docs/examples/library/load.md +++ b/docs/examples/library/load.md @@ -49,9 +49,9 @@ PyPSA's `Load`, wired to a port rather than straight to a bus. What it takes is | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | -| $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — the connections components make, one label per connection | | $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — demands, each on one port | +| $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Load\_port}: \mathcal{D} \to \mathcal{J}`$ — the connections components make, one label per connection | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters diff --git a/docs/examples/library/surface.md b/docs/examples/library/surface.md index 58682efc..e0aad3a7 100644 --- a/docs/examples/library/surface.md +++ b/docs/examples/library/surface.md @@ -63,9 +63,9 @@ The coupling surface every component in this library is written against: one flo | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — network nodes | | $`\mathcal{J}`$ | index $`j`$ — `port` with $`\mathrm{Port\_bus}: \mathcal{J} \to \mathcal{N}`$ — the connections components make, one label per connection | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Variables diff --git a/docs/examples/pypsa.md b/docs/examples/pypsa.md index da6e53f7..808286f9 100644 --- a/docs/examples/pypsa.md +++ b/docs/examples/pypsa.md @@ -5476,479 +5476,479 @@ A plain `n.optimize()`, and its multi-period and stochastic classes, in one file | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row, `Link_maintenance_cover` is `absent` where the data has no row, `Process_maintenance_cover` is `absent` where the data has no row — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y},\ \mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row, `Link_maintenance_cover` is `absent` where the data has no row, `Process_maintenance_cover` is `absent` where the data has no row — dispatch periods | -| $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N},\ \mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N},\ \mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N},\ \mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N},\ \mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N},\ \mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N},\ \mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N},\ \mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I},\ \mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N},\ \mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — generating units, each on one bus | -| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `Link_maintenance_cover` is `absent` where the data has no row — controllable connections, each from one bus to the buses it delivers to | -| $`\mathcal{O}`$ | index $`o`$ — `link_output` with $`\mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L},\ \mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N}`$ — a link's output ports, one label per port a link declares — PyPSA's `bus1`, `bus2`, … columns read long, so a link of any number of output ports is one term in the balance, data prep | -| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Process_maintenance_cover` is `absent` where the data has no row — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | -| $`\mathcal{R}`$ | index $`r`$ — `process_output` with $`\mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J},\ \mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N}`$ — a process's ports, one label per port a process declares — PyPSA's `bus0`, `bus1`, … each carry a signed `rate`, so a process of any number of ports is one term in the balance, data prep | -| $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N}`$ — demands, each on one bus | -| $`\mathcal{S}`$ | index $`s`$ — `storage_unit` with $`\mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I},\ \mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N}`$ — storage units, dispatch and store behind one bus connection | -| $`\mathcal{V}`$ | index $`v`$ — `store` with $`\mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I},\ \mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N}`$ — pure energy stores, each on one bus | -| $`\mathcal{K}`$ | index $`k`$ — `line` with $`\mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I},\ \mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N},\ \mathrm{Outage\_line}: \mathcal{K}^{\mathrm{out}} \to \mathcal{K}`$, `Outage_line` is `absent` where the data has no row — passive branches, each between two buses, their flow set by impedance | -| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N},\ \mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M}`$, `Outage_transformer` is `absent` where the data has no row — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | +| $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N},\ \mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N},\ \mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N},\ \mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N},\ \mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N},\ \mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N},\ \mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N},\ \mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$ — network nodes | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I},\ \mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I},\ \mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I},\ \mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{C}`$ | index $`c`$ — `cycle` — independent cycles of the passive network graph — the cycle basis, data prep. Each period has its own basis, of the branches that stand in it; a label is a position in that period's basis, so one label names a different cycle in another period | +| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N},\ \mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I},\ \mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — generating units, each on one bus | +| $`\mathcal{L}`$ | index $`l`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | +| $`\mathcal{K}`$ | index $`k`$ — `line` with $`\mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I},\ \mathrm{Outage\_line}: \mathcal{K}^{\mathrm{out}} \to \mathcal{K}`$, `Outage_line` is `absent` where the data has no row — passive branches, each between two buses, their flow set by impedance | +| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L}`$, `Link_maintenance_cover` is `absent` where the data has no row — controllable connections, each from one bus to the buses it delivers to | +| $`\mathcal{O}`$ | index $`o`$ — `link_output` with $`\mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L}`$ — a link's output ports, one label per port a link declares — PyPSA's `bus1`, `bus2`, … columns read long, so a link of any number of output ports is one term in the balance, data prep | +| $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N}`$ — demands, each on one bus | | $`\mathcal{K}^{\mathrm{out}}`$ | index $`\kappa`$ — `outage` with $`\mathrm{Outage\_line}: \mathcal{K}^{\mathrm{out}} \to \mathcal{K},\ \mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M}`$, `Outage_line` is `absent` where the data has no row, `Outage_transformer` is `absent` where the data has no row — the passive branches a security-constrained run takes out one at a time — PyPSA's `branch_outages`, each a line or a transformer; none on a plain run | -| $`\mathcal{B}`$ | index $`b`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | -| $`\mathcal{I}`$ | index $`i`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I},\ \mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I},\ \mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I},\ \mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J}`$, `Process_maintenance_cover` is `absent` where the data has no row — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | +| $`\mathcal{R}`$ | index $`r`$ — `process_output` with $`\mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J}`$ — a process's ports, one label per port a process declares — PyPSA's `bus0`, `bus1`, … each carry a signed `rate`, so a process of any number of ports is one term in the balance, data prep | +| $`\Xi`$ | index $`\xi`$ — `scenario` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row, `Link_maintenance_cover` is `absent` where the data has no row, `Process_maintenance_cover` is `absent` where the data has no row — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{M}`$ | index $`m`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T},\ \mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T},\ \mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T},\ \mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$, `Generator_maintenance_cover` is `absent` where the data has no row, `Link_maintenance_cover` is `absent` where the data has no row, `Process_maintenance_cover` is `absent` where the data has no row — dispatch periods | +| $`\mathcal{S}`$ | index $`s`$ — `storage_unit` with $`\mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N},\ \mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I}`$ — storage units, dispatch and store behind one bus connection | +| $`\mathcal{V}`$ | index $`v`$ — `store` with $`\mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N},\ \mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — pure energy stores, each on one bus | +| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M},\ \mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$, `Outage_transformer` is `absent` where the data has no row — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.objective` — hours a snapshot stands for in the cost | -| $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G} \times \Xi`$ — nominal power | -| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$ — whether the nominal power is a decision | -| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — least output, per unit of nominal power | -| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — most output, per unit of nominal power — an availability profile | +| $`\alpha`$ | `CVaR_alpha` (scalar), `neutral` 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` | +| $`\omega`$ | `CVaR_omega` (scalar), `neutral` 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 | +| $`\overline{\Delta}`$ | `Carrier_max_growth` over $`\mathcal{I}`$, `neutral` 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{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$ — whether a generator stands in a snapshot's period — PyPSA's `active`, from build year and lifetime, data prep | +| $`\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{M}`$ | `Generator_big_m` over $`\mathcal{G} \times \Xi`$, `neutral` 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{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\mathcal{G} \times \Xi`$ — 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{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{com}`$ | `Generator_committable` over $`\mathcal{G}`$ — whether output is gated by an on/off status decision | +| $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\mathcal{G} \times \Xi`$ — most energy over the horizon — a fuel or emission budget in energy terms; infinity where no cap is meant | +| $`\underline{\mathrm{E}}`$ | `Generator_e_sum_min` over $`\mathcal{G} \times \Xi`$ — least energy over the horizon; minus infinity where no floor is meant | +| $`\mathrm{new}`$ | `Generator_first_active` over $`\mathcal{G} \times \mathcal{Y}`$ — one in the first period a generator stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | +| $`\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`) | +| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\mathcal{G} \times \Xi`$, `neutral` 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{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\mathcal{G} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma`$ | `Generator_maintenance_pu` over $`\mathcal{G} \times \Xi`$ — the share of the build a maintenance event takes off | +| $`\mathrm{blk}`$ | `Generator_maintenance_start_blocked` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — 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{c}`$ | `Generator_marginal_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one unit of output | | $`\mathrm{c}^{(2)}`$ | `Generator_marginal_cost_quadratic` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays on once started | | $`\mathrm{DT}`$ | `Generator_min_down_time` over $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays off once stopped | -| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$ — one where the unit was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{p}^{0}`$ | `Generator_p_init` over $`\mathcal{G} \times \Xi`$, `neutral` 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 | -| $`\mathrm{hold}`$ | `Generator_must_stay_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the up time a unit brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{UT}`$ | `Generator_min_up_time` over $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays on once started | +| $`\mathrm{N}^{\mathrm{fix}}`$ | `Generator_modules_installed` over $`\mathcal{G} \times \Xi`$ — 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{rest}`$ | `Generator_must_stay_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the down time a unit brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{\mathrm{up}}`$ | `Generator_start_up_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{hold}`$ | `Generator_must_stay_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the up time a unit brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{b}`$ | `Generator_operational_limit_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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{p}^{0}`$ | `Generator_p_init` over $`\mathcal{G} \times \Xi`$, `neutral` 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 | +| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — most output, per unit of nominal power — an availability profile | +| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — least output, per unit of nominal power | +| $`\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{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G} \times \Xi`$ — nominal power | +| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$ — whether the nominal power is a decision | +| $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\mathcal{G} \times \Xi`$ — most nominal power an extendable generator may be built at | +| $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\mathcal{G} \times \Xi`$ — least nominal power an extendable generator may be built at | +| $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, `neutral` 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{set}}`$ | `Generator_p_set` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given output schedule; a generator without one has no row here | +| $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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{rd}`$ | `Generator_ramp_limit_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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{rd}^{\mathrm{dn}}`$ | `Generator_ramp_limit_shut_down` over $`\mathcal{G} \times \Xi`$, `neutral` 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}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\mathcal{G} \times \Xi`$, `neutral` 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{ru}`$ | `Generator_ramp_limit_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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{c}^{\mathrm{dn}}`$ | `Generator_shut_down_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | +| $`\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{c}^{\mathrm{on}}`$ | `Generator_stand_by_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\mathcal{G} \times \Xi`$ — how many maintenance events the horizon holds | -| $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — least flow, per unit of nominal power — negative for a link that carries both ways | -| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — most flow, per unit of nominal power | +| $`\mathrm{c}^{\mathrm{up}}`$ | `Generator_start_up_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$ — one where the unit was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | +| $`\mathrm{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{L}`$, `neutral` 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{K}`$ | `GlobalConstraint_constant` over $`\mathcal{L} \times \Xi`$ — 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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{sense}`$ | `GlobalConstraint_sense` over $`\mathcal{L} \times \Xi`$ — which way the row binds in each scenario — `<=`, `>=` or `==`; PyPSA reads a row's sense per scenario (`global_constraints.py:551`, `:749`, `:829`) | +| $`\mathrm{type}`$ | `GlobalConstraint_type` over $`\mathcal{L}`$ — which formula the row takes — `primary_energy`, `operational_limit`, `transmission_volume_expansion_limit`, `transmission_expansion_cost_limit` or `tech_capacity_expansion_limit` | +| $`\beta`$ | `Line_BODF` over $`\mathcal{K} \times \mathcal{K}^{\mathrm{out}} \times \mathcal{Y}`$, `neutral` 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{on}^{s}`$ | `Line_active` over $`\mathcal{K} \times \mathcal{T}`$ — whether a line stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\mathrm{act}^{s}`$ | `Line_active_asset` over $`\mathcal{K}`$ — whether a line 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{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\mathcal{K} \times \Xi`$ — 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{W}^{s}`$ | `Line_capital_weight` over $`\mathcal{K}`$ — the sum of period weights a line stands in — PyPSA's `active * period_weighting`, summed, data prep | +| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{C} \times \mathcal{K} \times \mathcal{Y}`$, `neutral` 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{cc}`$ | `Line_expansion_cost_weight` over $`\mathcal{L} \times \mathcal{K} \times \Xi`$, `neutral` 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{new}^{s}`$ | `Line_first_active` over $`\mathcal{K} \times \mathcal{Y}`$ — one in the first period a line stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | +| $`\overline{\ell}`$ | `Line_loss_max` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep | +| $`\mathrm{b}`$ | `Line_loss_offset` over $`\mathcal{K} \times \Xi \times \mathcal{M} \times \mathcal{T}`$ — 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{a}`$ | `Line_loss_slope` over $`\mathcal{K} \times \Xi \times \mathcal{M} \times \mathcal{T}`$ — 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 | +| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — most flow either way, per unit of nominal apparent power | +| $`\mathrm{s}^{\mathrm{nom}}`$ | `Line_s_nom` over $`\mathcal{K} \times \Xi`$ — nominal apparent power | +| $`\mathrm{ext}^{s}`$ | `Line_s_nom_extendable` over $`\mathcal{K}`$ — whether the nominal apparent power is a decision | +| $`\overline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_max` over $`\mathcal{K} \times \Xi`$ — most nominal apparent power an extendable line may be built at | +| $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\mathcal{K} \times \Xi`$ — least nominal apparent power an extendable line may be built at | +| $`\mathrm{s}^{\mathrm{mod}}`$ | `Line_s_nom_mod` over $`\mathcal{K}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, `neutral` 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 $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given flow schedule; a line without one has no row here | +| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{K}`$, `neutral` 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 | +| $`\overline{\delta}`$ | `Line_v_ang_max` over $`\mathcal{K} \times \Xi`$, `neutral` 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{len}`$ | `Line_volume_weight` over $`\mathcal{L} \times \mathcal{K} \times \Xi`$, `neutral` 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{x}^{\mathrm{eff}}`$ | `Line_x_pu_eff` over $`\mathcal{K} \times \Xi`$ — the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over the square of its bus's nominal voltage, data prep | +| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$ — whether a link stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\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{M}^{f}`$ | `Link_big_m` over $`\mathcal{L} \times \Xi`$, `neutral` 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{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\mathcal{L} \times \Xi`$ — 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{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{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$ — whether flow is gated by an on/off status decision | | $`\eta`$ | `Link_efficiency` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — share of the flow that arrives at an output port, PyPSA's `efficiency`, `efficiency2`, … read long — negative where that port consumes rather than delivers. Read at the snapshot the flow arrives, so a delayed port delivers at its arrival snapshot's efficiency (`constraints.py:1498`) | -| $`\mathrm{d}^{f}`$ | `Link_output_delay` over $`\mathcal{O}`$ — snapshots a port's delivery lags its link's flow — PyPSA's `delay`, `delay2`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that delivers at once. A port has the same delay in every scenario, because PyPSA refuses a delay that differs by scenario (`constants.py:52`) | -| $`\mathrm{cyc}^{f}`$ | `Link_output_cyclic_delay` over $`\mathcal{O}`$ — whether a delayed port's flow wraps from the end of its investment period — PyPSA's `cyclic_delay`, `cyclic_delay2`, …; where it does not, the flow still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | +| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\mathcal{L} \times \mathcal{L} \times \Xi`$, `neutral` 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{new}^{f}`$ | `Link_first_active` over $`\mathcal{L} \times \mathcal{Y}`$ — one in the first period a link stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | +| $`\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`) | +| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\mathcal{L} \times \Xi`$, `neutral` 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{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\mathcal{L} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$ — the share of the build a maintenance event takes off | +| $`\mathrm{blk}^{f}`$ | `Link_maintenance_start_blocked` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true where no maintenance event may start, 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{c}^{f}`$ | `Link_marginal_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one unit of flow | | $`\mathrm{c}^{f,(2)}`$ | `Link_marginal_cost_quadratic` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — least snapshots a link stays on once started | | $`\mathrm{DT}^{f}`$ | `Link_min_down_time` over $`\mathcal{L} \times \Xi`$ — least snapshots a link stays off once stopped | -| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$ — one where the link was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{f}^{0}`$ | `Link_p_init` over $`\mathcal{L} \times \Xi`$, `neutral` 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 | -| $`\mathrm{hold}^{f}`$ | `Link_must_stay_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the up time a link brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{UT}^{f}`$ | `Link_min_up_time` over $`\mathcal{L} \times \Xi`$ — least snapshots a link stays on once started | +| $`\mathrm{N}^{f,\mathrm{fix}}`$ | `Link_modules_installed` over $`\mathcal{L} \times \Xi`$ — 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{rest}^{f}`$ | `Link_must_stay_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the down time a link brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{f,\mathrm{up}}`$ | `Link_start_up_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{hold}^{f}`$ | `Link_must_stay_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the up time a link brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{cyc}^{f}`$ | `Link_output_cyclic_delay` over $`\mathcal{O}`$ — whether a delayed port's flow wraps from the end of its investment period — PyPSA's `cyclic_delay`, `cyclic_delay2`, …; where it does not, the flow still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | +| $`\mathrm{d}^{f}`$ | `Link_output_delay` over $`\mathcal{O}`$ — snapshots a port's delivery lags its link's flow — PyPSA's `delay`, `delay2`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that delivers at once. A port has the same delay in every scenario, because PyPSA refuses a delay that differs by scenario (`constants.py:52`) | +| $`\mathrm{f}^{0}`$ | `Link_p_init` over $`\mathcal{L} \times \Xi`$, `neutral` 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 | +| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — most flow, per unit of nominal power | +| $`\underline{\mathrm{f}}`$ | `Link_p_min_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — least flow, per unit of nominal power — negative for a link that carries both ways | +| $`\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{f}^{\mathrm{nom}}`$ | `Link_p_nom` over $`\mathcal{L} \times \Xi`$ — nominal power | +| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$ — whether the nominal power is a decision | +| $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\mathcal{L} \times \Xi`$ — most nominal power an extendable link may be built at | +| $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\mathcal{L} \times \Xi`$ — least nominal power an extendable link may be built at | +| $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, `neutral` 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{set}}`$ | `Link_p_set` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given flow schedule; a link without one has no row here | +| $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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{rd}^{f,\mathrm{dn}}`$ | `Link_ramp_limit_shut_down` over $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$, `neutral` 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{ru}^{f}`$ | `Link_ramp_limit_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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{c}^{f,\mathrm{dn}}`$ | `Link_shut_down_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{f,\mathrm{on}}`$ | `Link_stand_by_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\mathcal{L} \times \Xi`$ — how many maintenance events the horizon holds | -| $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{J} \times \Xi`$ — nominal internal power | -| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$ — whether the nominal internal power is a decision | -| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — least internal power, per unit of nominal power — negative for a process that runs both ways | -| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — most internal power, per unit of nominal power | -| $`\alpha`$ | `Process_rate` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — the energy a port draws or delivers per unit of internal power, PyPSA's `rate0`, `rate1`, … read long — negative where the port withdraws, positive where it injects; a link is a process whose `bus0` rate is minus one and whose output rates are its efficiencies. Read at the snapshot the transfer arrives, so a delayed port transfers at its arrival snapshot's rate (`constraints.py:1498`) | -| $`\mathrm{d}^{z}`$ | `Process_output_delay` over $`\mathcal{R}`$ — snapshots a port's transfer lags its process's internal power — PyPSA's `delay0`, `delay1`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that transfers at once. A port has the same delay in every scenario, as a link's port has | -| $`\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}^{f,\mathrm{up}}`$ | `Link_start_up_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$ — one where the link was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | +| $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{L}`$, `neutral` 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{len}^{f}`$ | `Link_volume_weight` over $`\mathcal{L} \times \mathcal{L} \times \Xi`$, `neutral` 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{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`) | +| $`\mathrm{load}`$ | `Load_p_set` over $`\mathcal{D} \times \Xi \times \mathcal{T}`$ — 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}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$ — whether a process stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\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{M}^{z}`$ | `Process_big_m` over $`\mathcal{J} \times \Xi`$, `neutral` 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{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\mathcal{J} \times \Xi`$ — 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{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{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$ — whether internal power is gated by an on/off status decision | +| $`\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{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`) | +| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\mathcal{J} \times \Xi`$, `neutral` 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{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\mathcal{J} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\mathcal{J} \times \Xi`$ — the share of the build a maintenance event takes off | +| $`\mathrm{blk}^{z}`$ | `Process_maintenance_start_blocked` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — 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{c}^{z}`$ | `Process_marginal_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one unit of internal power | | $`\mathrm{c}^{z,(2)}`$ | `Process_marginal_cost_quadratic` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of the square of one unit of internal power | -| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — least nominal power an extendable process may be built at | +| $`\mathrm{DT}^{z}`$ | `Process_min_down_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays off once stopped | +| $`\mathrm{UT}^{z}`$ | `Process_min_up_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays on once started | +| $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\mathcal{J} \times \Xi`$ — 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{rest}^{z}`$ | `Process_must_stay_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the down time a process brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | +| $`\mathrm{hold}^{z}`$ | `Process_must_stay_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the up time a process brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\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{d}^{z}`$ | `Process_output_delay` over $`\mathcal{R}`$ — snapshots a port's transfer lags its process's internal power — PyPSA's `delay0`, `delay1`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that transfers at once. A port has the same delay in every scenario, as a link's port has | +| $`\mathrm{z}^{0}`$ | `Process_p_init` over $`\mathcal{J} \times \Xi`$, `neutral` 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 | +| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — most internal power, per unit of nominal power | +| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — least internal power, per unit of nominal power — negative for a process that runs both ways | +| $`\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{z}^{\mathrm{nom}}`$ | `Process_p_nom` over $`\mathcal{J} \times \Xi`$ — nominal internal power | +| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$ — whether the nominal internal power is a decision | | $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\mathcal{J} \times \Xi`$ — most nominal power an extendable process may be built at | -| $`\mathrm{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\mathcal{J} \times \Xi`$ — 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 | +| $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\mathcal{J} \times \Xi`$ — least nominal power an extendable process may be built at | +| $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$, `neutral` 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{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given internal power schedule; a process without one has no row here | +| $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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{rd}^{z,\mathrm{dn}}`$ | `Process_ramp_limit_shut_down` over $`\mathcal{J} \times \Xi`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — least snapshots a process stays on once started | -| $`\mathrm{DT}^{z}`$ | `Process_min_down_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays off once stopped | -| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$ — one where the process was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{z}^{0}`$ | `Process_p_init` over $`\mathcal{J} \times \Xi`$, `neutral` 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 | -| $`\mathrm{hold}^{z}`$ | `Process_must_stay_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the up time a process brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | -| $`\mathrm{rest}^{z}`$ | `Process_must_stay_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the down time a process brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{z,\mathrm{up}}`$ | `Process_start_up_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\mathcal{J} \times \Xi`$, `neutral` 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{ru}^{z}`$ | `Process_ramp_limit_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 | +| $`\alpha`$ | `Process_rate` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — the energy a port draws or delivers per unit of internal power, PyPSA's `rate0`, `rate1`, … read long — negative where the port withdraws, positive where it injects; a link is a process whose `bus0` rate is minus one and whose output rates are its efficiencies. Read at the snapshot the transfer arrives, so a delayed port transfers at its arrival snapshot's rate (`constraints.py:1498`) | | $`\mathrm{c}^{z,\mathrm{dn}}`$ | `Process_shut_down_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{z,\mathrm{on}}`$ | `Process_stand_by_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — 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 $`\mathcal{J} \times \Xi`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\mathcal{J} \times \Xi`$ — how many maintenance events the horizon holds | -| $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\mathcal{J} \times \Xi`$, `neutral` 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 $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{D} \times \Xi \times \mathcal{T}`$ — 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), `neutral` 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), `neutral` 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{G} \times \mathcal{T}`$ — whether a generator stands in a snapshot's period — PyPSA's `active`, from build year and lifetime, data prep | -| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$ — whether a link stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\mathrm{c}^{z,\mathrm{up}}`$ | `Process_start_up_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$ — one where the process was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | +| $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{J}`$, `neutral` 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{on}^{h}`$ | `StorageUnit_active` over $`\mathcal{T} \times \mathcal{S}`$ — whether a storage unit stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\mathrm{on}^{e}`$ | `Store_active` over $`\mathcal{T} \times \mathcal{V}`$ — whether a store stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\mathrm{on}^{s}`$ | `Line_active` over $`\mathcal{K} \times \mathcal{T}`$ — whether a line stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$ — whether a process stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\mathrm{on}^{\sigma}`$ | `Transformer_active` over $`\mathcal{T} \times \mathcal{M}`$ — whether a transformer stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\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{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{act}^{h}`$ | `StorageUnit_active_asset` over $`\mathcal{S}`$ — whether a storage unit 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{act}^{e}`$ | `Store_active_asset` over $`\mathcal{V}`$ — whether a store 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{act}^{s}`$ | `Line_active_asset` over $`\mathcal{K}`$ — whether a line 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{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{act}^{\sigma}`$ | `Transformer_active_asset` over $`\mathcal{M}`$ — whether a transformer 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{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{W}^{h}`$ | `StorageUnit_capital_weight` over $`\mathcal{S}`$ — the sum of period weights a storage unit stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\mathrm{W}^{e}`$ | `Store_capital_weight` over $`\mathcal{V}`$ — the sum of period weights a store stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\mathrm{W}^{s}`$ | `Line_capital_weight` over $`\mathcal{K}`$ — the sum of period weights a line stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\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{W}^{\sigma}`$ | `Transformer_capital_weight` over $`\mathcal{M}`$ — the sum of period weights a transformer stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\mathrm{new}`$ | `Generator_first_active` over $`\mathcal{G} \times \mathcal{Y}`$ — one in the first period a generator stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\mathrm{new}^{f}`$ | `Link_first_active` over $`\mathcal{L} \times \mathcal{Y}`$ — one in the first period a link stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\mathrm{new}^{h}`$ | `StorageUnit_first_active` over $`\mathcal{Y} \times \mathcal{S}`$ — one in the first period a storage unit stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\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{K} \times \mathcal{Y}`$ — 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}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — least nominal power an extendable generator may be built at | -| $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\mathcal{G} \times \Xi`$ — most nominal power an extendable generator may be built at | -| $`\mathrm{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\mathcal{G} \times \Xi`$ — 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}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — least energy over the horizon; minus infinity where no floor is meant | -| $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\mathcal{G} \times \Xi`$ — 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 $`\mathcal{L} \times \Xi`$ — least nominal power an extendable link may be built at | -| $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\mathcal{L} \times \Xi`$ — most nominal power an extendable link may be built at | -| $`\mathrm{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\mathcal{L} \times \Xi`$ — 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}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\underline{\mathrm{h}}`$ | `StorageUnit_p_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most storing, per unit of nominal power and negated | -| $`\overline{\mathrm{h}}`$ | `StorageUnit_p_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most dispatch, per unit of nominal power | -| $`\mathrm{T}^{h}`$ | `StorageUnit_max_hours` over $`\Xi \times \mathcal{S}`$ — energy capacity, as hours of dispatch at nominal power | -| $`\eta^{-}`$ | `StorageUnit_efficiency_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the power drawn from the bus that becomes charge | -| $`\eta^{+}`$ | `StorageUnit_efficiency_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the charge drawn down that reaches the bus | -| $`\mathrm{sgn}^{h}`$ | `StorageUnit_sign` over $`\mathcal{S}`$ — the sign net dispatch enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | -| $`\rho`$ | `StorageUnit_retention` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of charge kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | -| $`\mathrm{inflow}`$ | `StorageUnit_inflow` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — energy arriving per hour, a river into a reservoir | -| $`\mathrm{soc}^{0}`$ | `StorageUnit_state_of_charge_initial` over $`\Xi \times \mathcal{S}`$ — charge held before the first snapshot | +| $`\mathrm{W}^{h}`$ | `StorageUnit_capital_weight` over $`\mathcal{S}`$ — the sum of period weights a storage unit stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{cyc}`$ | `StorageUnit_cyclic_state_of_charge` over $`\Xi \times \mathcal{S}`$ — whether the horizon closes on itself instead of opening on the initial charge | | $`\mathrm{cyc}^{y}`$ | `StorageUnit_cyclic_state_of_charge_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period closes on itself instead of carrying its charge on to the next; it overrides `cyclic_state_of_charge` and `state_of_charge_initial_per_period`. PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{reset}`$ | `StorageUnit_state_of_charge_initial_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period opens on the initial charge instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{open}`$ | `StorageUnit_opens_late` over $`\mathcal{T} \times \mathcal{S}`$ — whether a snapshot is the first a storage unit stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every unit stands throughout | +| $`\eta^{+}`$ | `StorageUnit_efficiency_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the charge drawn down that reaches the bus | +| $`\eta^{-}`$ | `StorageUnit_efficiency_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the power drawn from the bus that becomes charge | +| $`\mathrm{new}^{h}`$ | `StorageUnit_first_active` over $`\mathcal{Y} \times \mathcal{S}`$ — one in the first period a storage unit stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | | $`\mathrm{idle}`$ | `StorageUnit_inactive_snapshots` over $`\mathcal{S}`$ — how many snapshots a storage unit does not stand in — PyPSA's `(~active).sum()`, data prep. A cyclic unit reaches back this many snapshots further, so it closes on the last snapshot it stands in | +| $`\mathrm{inflow}`$ | `StorageUnit_inflow` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — energy arriving per hour, a river into a reservoir | | $`\mathrm{c}^{h}`$ | `StorageUnit_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of dispatch | | $`\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}`$, `neutral` where the data has no row — a given net dispatch schedule; a unit without one has no row here | +| $`\mathrm{T}^{h}`$ | `StorageUnit_max_hours` over $`\Xi \times \mathcal{S}`$ — energy capacity, as hours of dispatch at nominal power | +| $`\mathrm{open}`$ | `StorageUnit_opens_late` over $`\mathcal{T} \times \mathcal{S}`$ — whether a snapshot is the first a storage unit stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every unit stands throughout | +| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\mathcal{L} \times \Xi \times \mathcal{S}`$, `neutral` 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{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the data has no row — a given dispatch schedule; a unit without one has no row here | +| $`\overline{\mathrm{h}}`$ | `StorageUnit_p_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most dispatch, per unit of nominal power | +| $`\underline{\mathrm{h}}`$ | `StorageUnit_p_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most storing, per unit of nominal power and negated | +| $`\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 | +| $`\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 | +| $`\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 | +| $`\mathrm{h}^{\mathrm{mod}}`$ | `StorageUnit_p_nom_mod` over $`\mathcal{S}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, `neutral` 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{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` 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_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the data has no row — a given charging schedule; a unit without one has no row here | +| $`\mathrm{a}^{h}`$ | `StorageUnit_primary_energy_weight` over $`\mathcal{L} \times \Xi \times \mathcal{S}`$, `neutral` where the data has no row — the constrained attribute per unit of charge depleted — data prep; an unweighted unit has no row | +| $`\rho`$ | `StorageUnit_retention` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of charge kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | +| $`\mathrm{sgn}^{h}`$ | `StorageUnit_sign` over $`\mathcal{S}`$ — the sign net dispatch enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | +| $`\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{soc}^{0}`$ | `StorageUnit_state_of_charge_initial` over $`\Xi \times \mathcal{S}`$ — charge held before the first snapshot | +| $`\mathrm{reset}`$ | `StorageUnit_state_of_charge_initial_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period opens on the initial charge instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | | $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\underline{\mathrm{e}}`$ | `Store_e_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — least energy held, per unit of nominal capacity — negative for a store that may go short | -| $`\overline{\mathrm{e}}`$ | `Store_e_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — most energy held, per unit of nominal capacity | -| $`\mathrm{sgn}^{q}`$ | `Store_sign` over $`\mathcal{V}`$ — the sign the power a store delivers enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | -| $`\rho^{e}`$ | `Store_retention` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — share of energy kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | -| $`\mathrm{e}^{0}`$ | `Store_e_initial` over $`\Xi \times \mathcal{V}`$ — energy held before the first snapshot | +| $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{S}`$, `neutral` 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{on}^{e}`$ | `Store_active` over $`\mathcal{T} \times \mathcal{V}`$ — whether a store stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\mathrm{act}^{e}`$ | `Store_active_asset` over $`\mathcal{V}`$ — whether a store 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{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{W}^{e}`$ | `Store_capital_weight` over $`\mathcal{V}`$ — the sum of period weights a store stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{cyc}^{e}`$ | `Store_e_cyclic` over $`\Xi \times \mathcal{V}`$ — whether the horizon closes on itself instead of opening on the initial energy | | $`\mathrm{cyc}^{e,y}`$ | `Store_e_cyclic_per_period` over $`\Xi \times \mathcal{V}`$ — whether each investment period closes on itself instead of carrying its energy on to the next; it overrides `e_cyclic` and `e_initial_per_period`. PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | +| $`\mathrm{e}^{0}`$ | `Store_e_initial` over $`\Xi \times \mathcal{V}`$ — energy held before the first snapshot | | $`\mathrm{reset}^{e}`$ | `Store_e_initial_per_period` over $`\Xi \times \mathcal{V}`$ — whether each investment period opens on the initial energy instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{open}^{e}`$ | `Store_opens_late` over $`\mathcal{T} \times \mathcal{V}`$ — whether a snapshot is the first a store stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every store stands throughout | +| $`\overline{\mathrm{e}}`$ | `Store_e_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — most energy held, per unit of nominal capacity | +| $`\underline{\mathrm{e}}`$ | `Store_e_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — least energy held, per unit of nominal capacity — negative for a store that may go short | +| $`\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 | +| $`\overline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_max` over $`\Xi \times \mathcal{V}`$ — most nominal capacity an extendable store may be built at | +| $`\underline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_min` over $`\Xi \times \mathcal{V}`$ — least nominal capacity an extendable store may be built at | +| $`\mathrm{e}^{\mathrm{mod}}`$ | `Store_e_nom_mod` over $`\mathcal{V}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, `neutral` 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{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `neutral` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\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{idle}^{e}`$ | `Store_inactive_snapshots` over $`\mathcal{V}`$ — how many snapshots a store does not stand in — PyPSA's `(~active).sum()`, data prep. A cyclic store reaches back this many snapshots further, so it closes on the last snapshot it stands in | | $`\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}`$, `neutral` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\mathrm{open}^{e}`$ | `Store_opens_late` over $`\mathcal{T} \times \mathcal{V}`$ — whether a snapshot is the first a store stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every store stands throughout | +| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\mathcal{L} \times \Xi \times \mathcal{V}`$, `neutral` 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{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `neutral` 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 $`\mathcal{K} \times \Xi`$ — 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — most flow either way, per unit of nominal apparent power | -| $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\mathcal{K} \times \Xi`$ — least nominal apparent power an extendable line may be built at | -| $`\overline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_max` over $`\mathcal{K} \times \Xi`$ — most nominal apparent power an extendable line may be built at | -| $`\mathrm{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\mathcal{K} \times \Xi`$ — 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}`$, `neutral` 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 $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{K} \times \Xi`$, `neutral` 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 $`\mathcal{K} \times \Xi`$ — 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{C} \times \mathcal{K} \times \mathcal{Y}`$, `neutral` 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{K} \times \mathcal{K}^{\mathrm{out}} \times \mathcal{Y}`$, `neutral` 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 $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{K} \times \Xi \times \mathcal{B} \times \mathcal{T}`$ — 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 $`\mathcal{K} \times \Xi \times \mathcal{B} \times \mathcal{T}`$ — 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{a}^{e}`$ | `Store_primary_energy_weight` over $`\mathcal{L} \times \Xi \times \mathcal{V}`$, `neutral` where the data has no row — the constrained attribute per unit of energy depleted — data prep; an unweighted store has no row | +| $`\rho^{e}`$ | `Store_retention` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — share of energy kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | +| $`\mathrm{sgn}^{q}`$ | `Store_sign` over $`\mathcal{V}`$ — the sign the power a store delivers enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | +| $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{L} \times \mathcal{V}`$, `neutral` 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 | +| $`\beta^{\sigma}`$ | `Transformer_BODF` over $`\mathcal{K}^{\mathrm{out}} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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 | +| $`\mathrm{on}^{\sigma}`$ | `Transformer_active` over $`\mathcal{T} \times \mathcal{M}`$ — whether a transformer stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\mathrm{act}^{\sigma}`$ | `Transformer_active_asset` over $`\mathcal{M}`$ — whether a transformer 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{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 | +| $`\mathrm{W}^{\sigma}`$ | `Transformer_capital_weight` over $`\mathcal{M}`$ — the sum of period weights a transformer stands in — PyPSA's `active * period_weighting`, summed, data prep | +| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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 | +| $`\overline{\ell}^{\sigma}`$ | `Transformer_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the loss at a transformer's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, its `r_pu_eff` the resistance over the given `s_nom` times the tap ratio, data prep | +| $`\mathrm{b}^{\sigma}`$ | `Transformer_loss_offset` over $`\Xi \times \mathcal{M} \times \mathcal{T} \times \mathcal{M}`$ — 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{a}^{\sigma}`$ | `Transformer_loss_slope` over $`\Xi \times \mathcal{M} \times \mathcal{T} \times \mathcal{M}`$ — the slope of a cut to a transformer's loss curve — a tangent's `2 * r_pu_eff * p_k`, a secant's `r_pu_eff * (p_k + p_k+1)`, as a line's, over the transformer's own `r_pu_eff` and rating, data prep | +| $`\mathrm{Transformer\_phase\_shift\_cycle\_weight}`$ | `Transformer_phase_shift_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$ — the cycle sign for a varying transformer's phase shift, times π/180 so a shift in degrees enters the cycle sum in radians — data prep; zero for a fixed transformer or one in no cycle | +| $`\varphi^{\sigma}`$ | `Transformer_phase_shift_fixed` over $`\mathcal{T} \times \mathcal{M}`$ — a fixed transformer's phase shift at each snapshot, in degrees — PyPSA's `phase_shift`, zero by default; a varying transformer's shift is a decision instead | +| $`\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 | +| $`\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\_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) | +| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{C} \times \mathcal{T} \times \mathcal{M}`$, `neutral` 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 | +| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — most flow either way, per unit of nominal apparent power | | $`\sigma^{\mathrm{nom}}`$ | `Transformer_s_nom` over $`\Xi \times \mathcal{M}`$ — nominal apparent power | | $`\mathrm{ext}^{\sigma}`$ | `Transformer_s_nom_extendable` over $`\mathcal{M}`$ — whether the nominal apparent power is a decision | -| $`\sigma^{\mathrm{mod}}`$ | `Transformer_s_nom_mod` over $`\mathcal{M}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — most flow either way, per unit of nominal apparent power | -| $`\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 | +| $`\underline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_min` over $`\Xi \times \mathcal{M}`$ — least nominal apparent power an extendable transformer may be built at | +| $`\sigma^{\mathrm{mod}}`$ | `Transformer_s_nom_mod` over $`\mathcal{M}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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{C} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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{K}^{\mathrm{out}} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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{C} \times \mathcal{T} \times \mathcal{M}`$, `neutral` 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 | -| $`\varphi^{\sigma}`$ | `Transformer_phase_shift_fixed` over $`\mathcal{T} \times \mathcal{M}`$ — a fixed transformer's phase shift at each snapshot, in degrees — PyPSA's `phase_shift`, zero by default; a varying transformer's shift is a decision instead | -| $`\mathrm{Transformer\_phase\_shift\_cycle\_weight}`$ | `Transformer_phase_shift_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$ — the cycle sign for a varying transformer's phase shift, times π/180 so a shift in degrees enters the cycle sum in radians — data prep; zero for a fixed transformer or one in no cycle | -| $`\overline{\ell}^{\sigma}`$ | `Transformer_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the loss at a transformer's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, its `r_pu_eff` the resistance over the given `s_nom` times the tap ratio, data prep | -| $`\mathrm{a}^{\sigma}`$ | `Transformer_loss_slope` over $`\Xi \times \mathcal{B} \times \mathcal{T} \times \mathcal{M}`$ — the slope of a cut to a transformer's loss curve — a tangent's `2 * r_pu_eff * p_k`, a secant's `r_pu_eff * (p_k + p_k+1)`, as a line's, over the transformer's own `r_pu_eff` and rating, data prep | -| $`\mathrm{b}^{\sigma}`$ | `Transformer_loss_offset` over $`\Xi \times \mathcal{B} \times \mathcal{T} \times \mathcal{M}`$ — 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{type}`$ | `GlobalConstraint_type` over $`\mathcal{I}`$ — which formula the row takes — `primary_energy`, `operational_limit`, `transmission_volume_expansion_limit`, `transmission_expansion_cost_limit` or `tech_capacity_expansion_limit` | -| $`\mathrm{sense}`$ | `GlobalConstraint_sense` over $`\mathcal{I} \times \Xi`$ — 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 $`\mathcal{I} \times \Xi`$ — 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 $`\mathcal{I} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \mathcal{I} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{I} \times \Xi \times \mathcal{S}`$, `neutral` 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 $`\mathcal{I} \times \Xi \times \mathcal{V}`$, `neutral` 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 $`\mathcal{G} \times \mathcal{I} \times \Xi`$, `neutral` 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 $`\mathcal{I} \times \Xi \times \mathcal{S}`$, `neutral` 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 $`\mathcal{I} \times \Xi \times \mathcal{V}`$, `neutral` 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 $`\mathcal{I} \times \mathcal{K} \times \Xi`$, `neutral` 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 $`\mathcal{I} \times \mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{I} \times \mathcal{K} \times \Xi`$, `neutral` 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 $`\mathcal{I} \times \mathcal{L} \times \Xi`$, `neutral` 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{G} \times \mathcal{I}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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{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 | +| $`\pi`$ | `scenario_weight` over $`\Xi`$ — PyPSA's `scenario_weightings.weight` — the probability of a future | +| $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.generators` — hours a snapshot stands for in an energy total | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.objective` — hours a snapshot stands for in the cost | +| $`\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{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 | #### Conditions | Symbol | Meaning | |---|---| | $`\mathrm{on}^{\mathrm{com,ext}}`$ | `Generator_com_ext` over $`\mathcal{G} \times \mathcal{T}`$ — a committable generator with an extendable, non-modular build that stands in the snapshot's period — PyPSA's `com-ext` rows, whose status is relaxed against the chosen build | -| $`\mathrm{on}^{\mathrm{mnt,ext}}`$ | `Generator_maint_ext` over $`\mathcal{G} \times \mathcal{T}`$ — a maintainable generator with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{on}^{\mathrm{com}}`$ | `Generator_committed` over $`\mathcal{G} \times \mathcal{T}`$ — a committable generator that stands in the snapshot's period — every unit-commitment row's set | +| $`\mathrm{on}^{\mathrm{mnt,ext}}`$ | `Generator_maint_ext` over $`\mathcal{G} \times \mathcal{T}`$ — a maintainable generator with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{prev}`$ | `Generator_ramps_from_previous` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — a snapshot whose ramp reads a previous output — any snapshot but its period's first, and the horizon's first where the generator comes in off or carries an initial output | +| $`\mathrm{on}^{s,\mathrm{lossy}}`$ | `Line_lossy` over $`\mathcal{K} \times \mathcal{T}`$ — a line that stands in the snapshot's period, where the run models transmission losses | | $`\mathrm{on}^{f,\mathrm{com,ext}}`$ | `Link_com_ext` over $`\mathcal{L} \times \mathcal{T}`$ — a committable link with an extendable, non-modular build that stands in the snapshot's period — PyPSA's `com-ext` rows, whose status is relaxed against the chosen build | -| $`\mathrm{on}^{f,\mathrm{mnt,ext}}`$ | `Link_maint_ext` over $`\mathcal{L} \times \mathcal{T}`$ — a maintainable link with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{on}^{f,\mathrm{com}}`$ | `Link_committed` over $`\mathcal{L} \times \mathcal{T}`$ — a committable link that stands in the snapshot's period — every unit-commitment row's set | +| $`\mathrm{on}^{f,\mathrm{mnt,ext}}`$ | `Link_maint_ext` over $`\mathcal{L} \times \mathcal{T}`$ — a maintainable link with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{prev}^{f}`$ | `Link_ramps_from_previous` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — a snapshot whose ramp reads a previous output — any snapshot but its period's first, and the horizon's first where the link comes in off or carries an initial output | | $`\mathrm{on}^{z,\mathrm{com,ext}}`$ | `Process_com_ext` over $`\mathcal{J} \times \mathcal{T}`$ — a committable process with an extendable, non-modular build that stands in the snapshot's period — PyPSA's `com-ext` rows, whose status is relaxed against the chosen build | -| $`\mathrm{on}^{z,\mathrm{mnt,ext}}`$ | `Process_maint_ext` over $`\mathcal{J} \times \mathcal{T}`$ — a maintainable process with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{on}^{z,\mathrm{com}}`$ | `Process_committed` over $`\mathcal{J} \times \mathcal{T}`$ — a committable process that stands in the snapshot's period — every unit-commitment row's set | +| $`\mathrm{on}^{z,\mathrm{mnt,ext}}`$ | `Process_maint_ext` over $`\mathcal{J} \times \mathcal{T}`$ — a maintainable process with an extendable build, unless it is committable and modular, that stands in the snapshot's period — the maintenance rows against the chosen build | | $`\mathrm{prev}^{z}`$ | `Process_ramps_from_previous` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — a snapshot whose ramp reads a previous output — any snapshot but its period's first, and the horizon's first where the process comes in off or carries an initial output | -| $`\mathrm{on}^{h,\mathrm{fix}}`$ | `StorageUnit_fix` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with a fixed build that stands in the snapshot's period — PyPSA's `fix` rows | | $`\mathrm{on}^{h,\mathrm{ext}}`$ | `StorageUnit_ext` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with an extendable build that stands in the snapshot's period — PyPSA's `ext` rows | -| $`\mathrm{on}^{s,\mathrm{lossy}}`$ | `Line_lossy` over $`\mathcal{K} \times \mathcal{T}`$ — a line that stands in the snapshot's period, where the run models transmission losses | +| $`\mathrm{on}^{h,\mathrm{fix}}`$ | `StorageUnit_fix` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with a fixed build that stands in the snapshot's period — PyPSA's `fix` rows | | $`\mathrm{on}^{\sigma,\mathrm{lossy}}`$ | `Transformer_lossy` over $`\mathcal{T} \times \mathcal{M}`$ — a transformer that stands in the snapshot's period, where the run models transmission losses | #### Variables | Symbol | Meaning | |---|---| -| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-p` — output of a generator in a snapshot | -| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-p` — PyPSA's `p0`, the flow measured at the `Link_bus0` end: a positive value withdraws there and injects at every bus the link's output ports deliver to | -| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-p` — PyPSA's internal power `p`: a positive value drives every port at its own rate, withdrawing where the rate is negative and injecting where it is positive | -| $`h^{+}`$ | `StorageUnit_p_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_dispatch` — power delivered to the bus | -| $`h^{-}`$ | `StorageUnit_p_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_store` — power drawn from the bus into charge | -| $`\mathit{soc}`$ | `StorageUnit_state_of_charge` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-state_of_charge` — energy held at the end of a snapshot | -| $`\mathit{spill}`$ | `StorageUnit_spill` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the mask leaves it out — `StorageUnit-spill` — inflow passed on unused. Zero where there is no inflow, so the balance keeps its row there; the bounds are PyPSA's, on the variable rather than as rows | -| $`e`$ | `Store_e` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-e` — energy held at the end of a snapshot | -| $`q`$ | `Store_p` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-p` — power delivered to the bus; charging is negative | -| $`N`$ | `Generator_n_mod` over $`\mathcal{G}`$ — `Generator-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-status` — how much of a committable unit is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-start_up` — how much of a committable unit turns on this snapshot, capped as the status is | -| $`\mathit{dn}`$ | `Generator_shut_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-shut_down` — how much of a committable unit turns off this snapshot, capped as the status is | +| $`CVaR`$ | `CVaR` (scalar), `neutral` where the mask leaves it out — `CVaR` — the tail's average cost, what the objective prices at `omega` | +| $`a`$ | `CVaR_a` over $`\Xi`$, `neutral` where the mask leaves it out — `CVaR-a` — how far a scenario's operating cost exceeds the tail's start; nothing where it does not | +| $`\theta`$ | `CVaR_theta` (scalar), `neutral` where the mask leaves it out — `CVaR-theta` — where the tail starts, the value at risk | | $`\mu`$ | `Generator_maintenance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance` — whether a maintainable generator is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{\mathrm{up}}`$ | `Generator_maintenance_start` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{\mathrm{nom}}`$ | `Generator_maintenance_capacity` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{\mathrm{up}}`$ | `Generator_maintenance_start` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{u}`$ | `Generator_maintenance_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | -| $`N^{f}`$ | `Link_n_mod` over $`\mathcal{L}`$ — `Link-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-status` — how much of a committable link is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-start_up` — how much of a committable link turns on this snapshot, capped as the status is | -| $`\mathit{dn}^{f}`$ | `Link_shut_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-shut_down` — how much of a committable link turns off this snapshot, capped as the status is | +| $`N`$ | `Generator_n_mod` over $`\mathcal{G}`$ — `Generator-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-p` — output of a generator in a snapshot | +| $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ — `Generator-p_nom` — nominal power where it is a decision, for a generator that is active; the parameter of the same PyPSA name carries the fixed regime | +| $`\mathit{dn}`$ | `Generator_shut_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-shut_down` — how much of a committable unit turns off this snapshot, capped as the status is | +| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-start_up` — how much of a committable unit turns on this snapshot, capped as the status is | +| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-status` — how much of a committable unit is on: an integer the rows below cap at one, or at the module count where the build is modular | +| $`\ell`$ | `Line_loss` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Line-loss` — what a line dissipates carrying its flow, pushed down by the cost and held up by the cuts; absent, and zero in the balance, where the network is lossless | +| $`N^{s}`$ | `Line_n_mod` over $`\mathcal{K}`$ — `Line-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`s`$ | `Line_s` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — `Line-s` — PyPSA's `p0`, the flow measured at the `Line_bus0` end: a positive value withdraws there and injects at `Line_bus1`, lossless | +| $`S`$ | `Line_s_nom_ext` over $`\mathcal{K}`$ — `Line-s_nom` — nominal apparent power where it is a decision, for a line that is active; the parameter of the same PyPSA name carries the fixed regime | | $`\mu^{f}`$ | `Link_maintenance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance` — whether a maintainable link is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{f,\mathrm{up}}`$ | `Link_maintenance_start` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{f,\mathrm{nom}}`$ | `Link_maintenance_capacity` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{f,\mathrm{up}}`$ | `Link_maintenance_start` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{f,u}`$ | `Link_maintenance_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | -| $`N^{z}`$ | `Process_n_mod` over $`\mathcal{J}`$ — `Process-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-status` — how much of a committable process is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-start_up` — how much of a committable process turns on this snapshot, capped as the status is | -| $`\mathit{dn}^{z}`$ | `Process_shut_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-shut_down` — how much of a committable process turns off this snapshot, capped as the status is | +| $`N^{f}`$ | `Link_n_mod` over $`\mathcal{L}`$ — `Link-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-p` — PyPSA's `p0`, the flow measured at the `Link_bus0` end: a positive value withdraws there and injects at every bus the link's output ports deliver to | +| $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ — `Link-p_nom` — nominal power where it is a decision, for a link that is active; the parameter of the same PyPSA name carries the fixed regime | +| $`\mathit{dn}^{f}`$ | `Link_shut_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-shut_down` — how much of a committable link turns off this snapshot, capped as the status is | +| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-start_up` — how much of a committable link turns on this snapshot, capped as the status is | +| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-status` — how much of a committable link is on: an integer the rows below cap at one, or at the module count where the build is modular | | $`\mu^{z}`$ | `Process_maintenance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance` — whether a maintainable process is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{z,\mathrm{up}}`$ | `Process_maintenance_start` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{z,\mathrm{nom}}`$ | `Process_maintenance_capacity` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{z,\mathrm{up}}`$ | `Process_maintenance_start` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{z,u}`$ | `Process_maintenance_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | -| $`s`$ | `Line_s` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — `Line-s` — PyPSA's `p0`, the flow measured at the `Line_bus0` end: a positive value withdraws there and injects at `Line_bus1`, lossless | -| $`\ell`$ | `Line_loss` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Line-loss` — what a line dissipates carrying its flow, pushed down by the cost and held up by the cuts; absent, and zero in the balance, where the network is lossless | -| $`\sigma`$ | `Transformer_s` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — `Transformer-s` — PyPSA's `p0`, the flow measured at the `Transformer_bus0` end: a positive value withdraws there and injects at `Transformer_bus1`, lossless | -| $`\ell^{\sigma}`$ | `Transformer_loss` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-loss` — what a transformer dissipates carrying its flow, as a line does; absent, and zero in the balance, where the network is lossless | -| $`\mathit{Transformer\_phase\_shift}`$ | `Transformer_phase_shift` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-phase_shift` — a phase-shifting transformer's voltage angle shift in degrees, chosen per snapshot to redistribute the flows around its cycles without moving active power; absent, and zero in the cycle sum, where the shift is fixed | -| $`S`$ | `Line_s_nom_ext` over $`\mathcal{K}`$ — `Line-s_nom` — nominal apparent power where it is a decision, for a line that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`N^{s}`$ | `Line_n_mod` over $`\mathcal{K}`$ — `Line-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ — `Generator-p_nom` — nominal power where it is a decision, for a generator that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ — `Link-p_nom` — nominal power where it is a decision, for a link that is active; the parameter of the same PyPSA name carries the fixed regime | +| $`N^{z}`$ | `Process_n_mod` over $`\mathcal{J}`$ — `Process-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-p` — PyPSA's internal power `p`: a positive value drives every port at its own rate, withdrawing where the rate is negative and injecting where it is positive | | $`Z`$ | `Process_p_nom_ext` over $`\mathcal{J}`$ — `Process-p_nom` — nominal internal power where it is a decision, for a process that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`\Sigma`$ | `Transformer_s_nom_ext` over $`\mathcal{M}`$ — `Transformer-s_nom` — nominal apparent power where it is a decision, for a transformer that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`N^{\sigma}`$ | `Transformer_n_mod` over $`\mathcal{M}`$ — `Transformer-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`H`$ | `StorageUnit_p_nom_ext` over $`\mathcal{S}`$ — `StorageUnit-p_nom` — nominal power where it is a decision, for a storage unit that is active; the parameter of the same PyPSA name carries the fixed regime | +| $`\mathit{dn}^{z}`$ | `Process_shut_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-shut_down` — how much of a committable process turns off this snapshot, capped as the status is | +| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-start_up` — how much of a committable process turns on this snapshot, capped as the status is | +| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-status` — how much of a committable process is on: an integer the rows below cap at one, or at the module count where the build is modular | | $`N^{h}`$ | `StorageUnit_n_mod` over $`\mathcal{S}`$ — `StorageUnit-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`h^{+}`$ | `StorageUnit_p_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_dispatch` — power delivered to the bus | +| $`H`$ | `StorageUnit_p_nom_ext` over $`\mathcal{S}`$ — `StorageUnit-p_nom` — nominal power where it is a decision, for a storage unit that is active; the parameter of the same PyPSA name carries the fixed regime | +| $`h^{-}`$ | `StorageUnit_p_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_store` — power drawn from the bus into charge | +| $`\mathit{spill}`$ | `StorageUnit_spill` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the mask leaves it out — `StorageUnit-spill` — inflow passed on unused. Zero where there is no inflow, so the balance keeps its row there; the bounds are PyPSA's, on the variable rather than as rows | +| $`\mathit{soc}`$ | `StorageUnit_state_of_charge` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-state_of_charge` — energy held at the end of a snapshot | +| $`e`$ | `Store_e` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-e` — energy held at the end of a snapshot | | $`E`$ | `Store_e_nom_ext` over $`\mathcal{V}`$ — `Store-e_nom` — nominal capacity where it is a decision, for a store that is active; the parameter of the same PyPSA name carries the fixed regime | | $`N^{e}`$ | `Store_n_mod` over $`\mathcal{V}`$ — `Store-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | -| $`a`$ | `CVaR_a` over $`\Xi`$, `neutral` where the mask leaves it out — `CVaR-a` — how far a scenario's operating cost exceeds the tail's start; nothing where it does not | -| $`\theta`$ | `CVaR_theta` (scalar), `neutral` where the mask leaves it out — `CVaR-theta` — where the tail starts, the value at risk | -| $`CVaR`$ | `CVaR` (scalar), `neutral` where the mask leaves it out — `CVaR` — the tail's average cost, what the objective prices at `omega` | +| $`q`$ | `Store_p` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-p` — power delivered to the bus; charging is negative | +| $`\ell^{\sigma}`$ | `Transformer_loss` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-loss` — what a transformer dissipates carrying its flow, as a line does; absent, and zero in the balance, where the network is lossless | +| $`N^{\sigma}`$ | `Transformer_n_mod` over $`\mathcal{M}`$ — `Transformer-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`\mathit{Transformer\_phase\_shift}`$ | `Transformer_phase_shift` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-phase_shift` — a phase-shifting transformer's voltage angle shift in degrees, chosen per snapshot to redistribute the flows around its cycles without moving active power; absent, and zero in the cycle sum, where the shift is fixed | +| $`\sigma`$ | `Transformer_s` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — `Transformer-s` — PyPSA's `p0`, the flow measured at the `Transformer_bus0` end: a positive value withdraws there and injects at `Transformer_bus1`, lossless | +| $`\Sigma`$ | `Transformer_s_nom_ext` over $`\mathcal{M}`$ — `Transformer-s_nom` — nominal apparent power where it is a decision, for a transformer that is active; the parameter of the same PyPSA name carries the fixed regime | #### Definitions | Symbol | Meaning | |---|---| -| $`\overleftarrow{u}`$ | `Generator_previous_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the commitment state a generator carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | -| $`\overleftarrow{u}^{\circ}`$ | `Generator_status_carried_over` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the state a generator carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | -| $`\overleftarrow{p}`$ | `Generator_previous_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the output a generator carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ — what every component puts into a bus, less what it takes out of it; PyPSA writes each term into the balance, and a load on its right-hand side | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$ — what a carrier adds in a period — every extendable component of that carrier, counting each build in the first period it stands in. Like PyPSA, it sums only the components that carry a carrier attribute, so a transformer, which has none, counts in no carrier | +| $`\mathrm{r}^{+}`$ | `Carrier_relative_growth` over $`\mathcal{I}`$ — the share of the previous period's additions a carrier's growth limit reads — PyPSA's `max_relative_growth` clipped at zero, so a negative share adds nothing and never tightens the limit | +| $`\mathit{Cycle\_angle\_sum}`$ | `Cycle_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ — the voltage angle differences around a cycle: every branch flow times its cycle weight, and every transformer phase shift | +| $`\mathit{Generator\_additions}`$ | `Generator_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Generator\_capex}`$ | `Generator_capex` (scalar) | +| $`\mathit{Generator\_commitment\_opex}`$ | `Generator_commitment_opex` over $`\Xi`$ | +| $`\mathit{Generator\_injection}`$ | `Generator_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Generator\_operational\_limit}`$ | `Generator_operational_limit` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Generator\_opex}`$ | `Generator_opex` over $`\Xi`$ | +| $`\widehat{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_committed` over $`\mathcal{G} \times \Xi`$ — the build a committed unit's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\widetilde{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_effective` over $`\mathcal{G} \times \Xi`$ — the build a generator's limits are taken against — the chosen one where it is extendable, the given one otherwise | -| $`\widetilde{\mathrm{ru}}`$ | `Generator_ramp_up_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\overleftarrow{p}`$ | `Generator_previous_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the output a generator carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | +| $`\overleftarrow{u}`$ | `Generator_previous_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the commitment state a generator carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | +| $`\mathit{Generator\_primary\_energy}`$ | `Generator_primary_energy` over $`\mathcal{L} \times \Xi`$ | +| $`\Delta^{-}`$ | `Generator_ramp_down_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may lower output between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}`$ | `Generator_ramp_down_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{\mathrm{up}}`$ | `Generator_start_up_rate` over $`\mathcal{G} \times \Xi`$ — the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{\mathrm{dn}}`$ | `Generator_shut_down_rate` over $`\mathcal{G} \times \Xi`$ — the shut-down ramp a unit's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | -| $`\widehat{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_committed` over $`\mathcal{G} \times \Xi`$ — the build a committed unit's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\Delta^{+}`$ | `Generator_ramp_up_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may raise output between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{-}`$ | `Generator_ramp_down_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may lower output between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}`$ | `Generator_ramp_up_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{\mathrm{dn}}`$ | `Generator_shut_down_rate` over $`\mathcal{G} \times \Xi`$ — the shut-down ramp a unit's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{\mathrm{up}}`$ | `Generator_start_up_rate` over $`\mathcal{G} \times \Xi`$ — the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | +| $`\overleftarrow{u}^{\circ}`$ | `Generator_status_carried_over` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the state a generator carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | +| $`\mathit{Generator\_tech\_capacity\_expansion}`$ | `Generator_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{w}^{\mathrm{gc}}`$ | `GlobalConstraint_energy_weight` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — what one unit of power at a snapshot counts for in a row — the generator weighting times the years of the snapshot's period, where the row counts the snapshot, and nothing where it does not | +| $`\mathit{Line\_additions}`$ | `Line_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Line\_angle\_sum}`$ | `Line_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Line\_capex}`$ | `Line_capex` (scalar) | +| $`\mathit{Line\_injection}`$ | `Line_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\check{s}`$ | `Line_s_monitored` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the flow a line's post-contingency rows read — its flow where it stands, nothing where it does not, since PyPSA builds those rows for every branch of the sub-network in every snapshot | +| $`\mathit{Line\_tech\_capacity\_expansion}`$ | `Line_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{Line\_transmission\_expansion\_cost}`$ | `Line_transmission_expansion_cost` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Line\_transmission\_volume\_expansion}`$ | `Line_transmission_volume_expansion` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Link\_additions}`$ | `Link_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Link\_capex}`$ | `Link_capex` (scalar) | +| $`\mathit{Link\_commitment\_opex}`$ | `Link_commitment_opex` over $`\Xi`$ | +| $`\mathit{Link\_injection}`$ | `Link_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Link\_opex}`$ | `Link_opex` over $`\Xi`$ | +| $`\overrightarrow{f}`$ | `Link_output_arrival` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — what a link delivers to an output port at a snapshot — its flow delayed by the port's `delay` within its investment period, times the port's efficiency at the snapshot the flow arrives; where the port is `cyclic_delay` the delayed flow wraps from the period's end, and where it is not the flow still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) delivers its flow unshifted, cyclic or not | +| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$ — the build a committed link's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\widetilde{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_effective` over $`\mathcal{L} \times \Xi`$ — the build a link's limits are taken against — the chosen one where it is extendable, the given one otherwise | -| $`\overleftarrow{u}^{f}`$ | `Link_previous_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the commitment state a link carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | -| $`\overleftarrow{u}^{\circ f}`$ | `Link_status_carried_over` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the state a link carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | | $`\overleftarrow{f}`$ | `Link_previous_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the flow a link carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | -| $`\widetilde{\mathrm{ru}}^{f}`$ | `Link_ramp_up_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\overleftarrow{u}^{f}`$ | `Link_previous_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the commitment state a link carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | +| $`\Delta^{f,-}`$ | `Link_ramp_down_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may lower flow between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}^{f}`$ | `Link_ramp_down_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{f,\mathrm{up}}`$ | `Link_start_up_rate` over $`\mathcal{L} \times \Xi`$ — the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}`$ | `Link_shut_down_rate` over $`\mathcal{L} \times \Xi`$ — the shut-down ramp a link's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | -| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$ — the build a committed link's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\Delta^{f,+}`$ | `Link_ramp_up_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may raise flow between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{f,-}`$ | `Link_ramp_down_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may lower flow between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}^{f}`$ | `Link_ramp_up_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}`$ | `Link_shut_down_rate` over $`\mathcal{L} \times \Xi`$ — the shut-down ramp a link's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{f,\mathrm{up}}`$ | `Link_start_up_rate` over $`\mathcal{L} \times \Xi`$ — the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | +| $`\overleftarrow{u}^{\circ f}`$ | `Link_status_carried_over` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the state a link carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | +| $`\mathit{Link\_tech\_capacity\_expansion}`$ | `Link_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{Link\_transmission\_expansion\_cost}`$ | `Link_transmission_expansion_cost` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Link\_transmission\_volume\_expansion}`$ | `Link_transmission_volume_expansion` over $`\mathcal{L} \times \Xi`$ | +| $`\check{\mathrm{load}}`$ | `Load_demand` over $`\mathcal{D} \times \Xi \times \mathcal{T}`$ — what a load draws from its bus's balance — its demand times its sign where it is active, nothing where it is not, since PyPSA drops an inactive load from the balance (`constraints.py:1513-1514`) | +| $`\mathrm{Load\_injection}`$ | `Load_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\hat{s}`$ | `Outage_s` over $`\mathcal{K}^{\mathrm{out}} \times \Xi \times \mathcal{T}`$ — the flow an outage takes off its branch — the outaged line's or transformer's flow before it goes out | +| $`\mathit{Process\_additions}`$ | `Process_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Process\_capex}`$ | `Process_capex` (scalar) | +| $`\mathit{Process\_commitment\_opex}`$ | `Process_commitment_opex` over $`\Xi`$ | +| $`\mathit{Process\_injection}`$ | `Process_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Process\_opex}`$ | `Process_opex` over $`\Xi`$ | +| $`\overrightarrow{z}`$ | `Process_output_arrival` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — what a process transfers at a port at a snapshot — its internal power delayed by the port's `delay` within its investment period, times the port's rate at the snapshot the transfer arrives; where the port is `cyclic_delay` the delayed transfer wraps from the period's end, and where it is not the energy still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) transfers at once, cyclic or not | +| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$ — the build a committed process's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\widetilde{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_effective` over $`\mathcal{J} \times \Xi`$ — the build a process's limits are taken against — the chosen one where it is extendable, the given one otherwise | -| $`\overleftarrow{u}^{z}`$ | `Process_previous_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the commitment state a process carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | -| $`\overleftarrow{u}^{\circ z}`$ | `Process_status_carried_over` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the state a process carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | | $`\overleftarrow{z}`$ | `Process_previous_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the internal power a process carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | -| $`\widetilde{\mathrm{ru}}^{z}`$ | `Process_ramp_up_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\overleftarrow{u}^{z}`$ | `Process_previous_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the commitment state a process carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | +| $`\Delta^{z,-}`$ | `Process_ramp_down_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may lower internal power between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}^{z}`$ | `Process_ramp_down_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{z,\mathrm{up}}`$ | `Process_start_up_rate` over $`\mathcal{J} \times \Xi`$ — the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}`$ | `Process_shut_down_rate` over $`\mathcal{J} \times \Xi`$ — the shut-down ramp a process's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | -| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$ — the build a committed process's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | | $`\Delta^{z,+}`$ | `Process_ramp_up_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may raise internal power between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{z,-}`$ | `Process_ramp_down_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may lower internal power between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}^{z}`$ | `Process_ramp_up_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}`$ | `Process_shut_down_rate` over $`\mathcal{J} \times \Xi`$ — the shut-down ramp a process's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{z,\mathrm{up}}`$ | `Process_start_up_rate` over $`\mathcal{J} \times \Xi`$ — the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | +| $`\overleftarrow{u}^{\circ z}`$ | `Process_status_carried_over` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the state a process carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | +| $`\mathit{Process\_tech\_capacity\_expansion}`$ | `Process_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{StorageUnit\_additions}`$ | `StorageUnit_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{StorageUnit\_capex}`$ | `StorageUnit_capex` (scalar) | | $`\overleftarrow{\mathit{soc}}`$ | `StorageUnit_charge_carried_in` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — the charge a unit opens a snapshot with — at the first snapshot it stands in, its last such snapshot's less standing loss where it is cyclic and the given initial charge, which no standing loss has touched yet, where it is not; the previous snapshot's less standing loss otherwise. A unit built in a later period opens in that period, and a cyclic one that retires closes on its own last snapshot. Per period, the same holds with each investment period as the horizon | -| $`\overleftarrow{e}`$ | `Store_energy_carried_in` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — the energy a store opens a snapshot with — at the first snapshot it stands in, its last such snapshot's less standing loss where it is cyclic and the given initial energy, which no standing loss has touched yet, where it is not; the previous snapshot's less standing loss otherwise. A store built in a later period opens in that period, and a cyclic one that retires closes on its own last snapshot. Per period, the same holds with each investment period as the horizon | -| $`\overrightarrow{f}`$ | `Link_output_arrival` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — what a link delivers to an output port at a snapshot — its flow delayed by the port's `delay` within its investment period, times the port's efficiency at the snapshot the flow arrives; where the port is `cyclic_delay` the delayed flow wraps from the period's end, and where it is not the flow still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) delivers its flow unshifted, cyclic or not | -| $`\overrightarrow{z}`$ | `Process_output_arrival` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — what a process transfers at a port at a snapshot — its internal power delayed by the port's `delay` within its investment period, times the port's rate at the snapshot the transfer arrives; where the port is `cyclic_delay` the delayed transfer wraps from the period's end, and where it is not the energy still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) transfers at once, cyclic or not | -| $`\mathit{w}^{\mathrm{gc}}`$ | `GlobalConstraint_energy_weight` over $`\mathcal{I} \times \Xi \times \mathcal{T}`$ — what one unit of power at a snapshot counts for in a row — the generator weighting times the years of the snapshot's period, where the row counts the snapshot, and nothing where it does not | -| $`\mathit{last}^{h}`$ | `StorageUnit_last_counted_active` over $`\mathcal{I} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — one at the last snapshot a row counts where a unit stands, and zero elsewhere — a unit that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:455-458`) | -| $`\mathit{w}^{h}`$ | `StorageUnit_closing_weight` over $`\mathcal{I} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — what the charge a unit holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the unit reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | -| $`\mathit{last}^{e}`$ | `Store_last_counted_active` over $`\mathcal{I} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — one at the last snapshot a row counts where a store stands, and zero elsewhere — a store that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:507-510`) | -| $`\mathit{w}^{e}`$ | `Store_closing_weight` over $`\mathcal{I} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — what the energy a store holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the store reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | -| $`\mathit{Generator\_primary\_energy}`$ | `Generator_primary_energy` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{StorageUnit\_primary\_energy}`$ | `StorageUnit_primary_energy` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{Store\_primary\_energy}`$ | `Store_primary_energy` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{I} \times \Xi`$ — what a `primary_energy` row totals — weighted generator energy over the snapshots it counts, less the charge left in weighted storage at the close; the initial charge it is compared against is folded into the row's constant | -| $`\mathit{Generator\_operational\_limit}`$ | `Generator_operational_limit` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{StorageUnit\_operational\_limit}`$ | `StorageUnit_operational_limit` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{Store\_operational\_limit}`$ | `Store_operational_limit` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{I} \times \Xi`$ — what an `operational_limit` row totals — the weighted energy its generators deliver over the snapshots it counts, plus what its non-cyclic storage draws down; the initial charge it draws from is folded into the row's constant | -| $`\mathit{Line\_transmission\_volume\_expansion}`$ | `Line_transmission_volume_expansion` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{Link\_transmission\_volume\_expansion}`$ | `Link_transmission_volume_expansion` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{I} \times \Xi`$ — what a `transmission_volume_expansion_limit` row totals — length times the chosen build of the row's branches | -| $`\mathit{Line\_transmission\_expansion\_cost}`$ | `Line_transmission_expansion_cost` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{Link\_transmission\_expansion\_cost}`$ | `Link_transmission_expansion_cost` over $`\mathcal{I} \times \Xi`$ | -| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{I} \times \Xi`$ — what a `transmission_expansion_cost_limit` row totals — capital cost times the chosen build of the row's branches | -| $`\mathit{Generator\_tech\_capacity\_expansion}`$ | `Generator_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{Line\_tech\_capacity\_expansion}`$ | `Line_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{Link\_tech\_capacity\_expansion}`$ | `Link_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{Process\_tech\_capacity\_expansion}`$ | `Process_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{StorageUnit\_tech\_capacity\_expansion}`$ | `StorageUnit_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{Store\_tech\_capacity\_expansion}`$ | `Store_tech_capacity_expansion` over $`\mathcal{I}`$ | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{I}`$ — what a `tech_capacity_expansion_limit` row totals — the chosen build of the row's carrier-and-bus set | -| $`\mathit{Generator\_opex}`$ | `Generator_opex` over $`\Xi`$ | -| $`\mathit{Generator\_commitment\_opex}`$ | `Generator_commitment_opex` over $`\Xi`$ | -| $`\mathit{Link\_opex}`$ | `Link_opex` over $`\Xi`$ | -| $`\mathit{Link\_commitment\_opex}`$ | `Link_commitment_opex` over $`\Xi`$ | -| $`\mathit{Process\_opex}`$ | `Process_opex` over $`\Xi`$ | -| $`\mathit{Process\_commitment\_opex}`$ | `Process_commitment_opex` over $`\Xi`$ | +| $`\mathit{w}^{h}`$ | `StorageUnit_closing_weight` over $`\mathcal{L} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — what the charge a unit holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the unit reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | +| $`\mathit{StorageUnit\_injection}`$ | `StorageUnit_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{last}^{h}`$ | `StorageUnit_last_counted_active` over $`\mathcal{L} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — one at the last snapshot a row counts where a unit stands, and zero elsewhere — a unit that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:455-458`) | +| $`\mathit{StorageUnit\_operational\_limit}`$ | `StorageUnit_operational_limit` over $`\mathcal{L} \times \Xi`$ | | $`\mathit{StorageUnit\_opex}`$ | `StorageUnit_opex` over $`\Xi`$ | -| $`\mathit{Store\_opex}`$ | `Store_opex` over $`\Xi`$ | -| $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$ — what a future costs to run — every operating term, weighted by the snapshot's hours and its period, before the scenario's own weight; a start and a stop cost what they cost, unweighted, as PyPSA adds them (`optimize.py:415-432`) | -| $`\mathit{Generator\_capex}`$ | `Generator_capex` (scalar) | -| $`\mathit{Link\_capex}`$ | `Link_capex` (scalar) | -| $`\mathit{StorageUnit\_capex}`$ | `StorageUnit_capex` (scalar) | +| $`\mathit{StorageUnit\_primary\_energy}`$ | `StorageUnit_primary_energy` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{StorageUnit\_tech\_capacity\_expansion}`$ | `StorageUnit_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{Store\_additions}`$ | `Store_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | | $`\mathit{Store\_capex}`$ | `Store_capex` (scalar) | -| $`\mathit{Line\_capex}`$ | `Line_capex` (scalar) | -| $`\mathit{Process\_capex}`$ | `Process_capex` (scalar) | +| $`\mathit{w}^{e}`$ | `Store_closing_weight` over $`\mathcal{L} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — what the energy a store holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the store reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | +| $`\overleftarrow{e}`$ | `Store_energy_carried_in` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — the energy a store opens a snapshot with — at the first snapshot it stands in, its last such snapshot's less standing loss where it is cyclic and the given initial energy, which no standing loss has touched yet, where it is not; the previous snapshot's less standing loss otherwise. A store built in a later period opens in that period, and a cyclic one that retires closes on its own last snapshot. Per period, the same holds with each investment period as the horizon | +| $`\mathit{Store\_injection}`$ | `Store_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{last}^{e}`$ | `Store_last_counted_active` over $`\mathcal{L} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — one at the last snapshot a row counts where a store stands, and zero elsewhere — a store that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:507-510`) | +| $`\mathit{Store\_operational\_limit}`$ | `Store_operational_limit` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Store\_opex}`$ | `Store_opex` over $`\Xi`$ | +| $`\mathit{Store\_primary\_energy}`$ | `Store_primary_energy` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Store\_tech\_capacity\_expansion}`$ | `Store_tech_capacity_expansion` over $`\mathcal{L}`$ | +| $`\mathit{Transformer\_angle\_sum}`$ | `Transformer_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | | $`\mathit{Transformer\_capex}`$ | `Transformer_capex` (scalar) | +| $`\mathit{Transformer\_injection}`$ | `Transformer_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\check{\sigma}`$ | `Transformer_s_monitored` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the flow a transformer's post-contingency rows read, as a line's | +| $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{L} \times \Xi`$ — what an `operational_limit` row totals — the weighted energy its generators deliver over the snapshots it counts, plus what its non-cyclic storage draws down; the initial charge it draws from is folded into the row's constant | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{L} \times \Xi`$ — what a `primary_energy` row totals — weighted generator energy over the snapshots it counts, less the charge left in weighted storage at the close; the initial charge it is compared against is folded into the row's constant | | $`\mathit{risk\_weighted\_opex}`$ | `risk_weighted_opex` (scalar) | +| $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$ — what a future costs to run — every operating term, weighted by the snapshot's hours and its period, before the scenario's own weight; a start and a stop cost what they cost, unweighted, as PyPSA adds them (`optimize.py:415-432`) | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{L}`$ — what a `tech_capacity_expansion_limit` row totals — the chosen build of the row's carrier-and-bus set | | $`\mathit{total\_cost}`$ | `total_cost` (scalar) — what the system costs — capacity once per active period at its expected cost over the scenarios, operation in expectation over the scenarios, and a share of it at the tail | -| $`\mathit{Generator\_additions}`$ | `Generator_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Line\_additions}`$ | `Line_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Link\_additions}`$ | `Link_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Process\_additions}`$ | `Process_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{StorageUnit\_additions}`$ | `StorageUnit_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Store\_additions}`$ | `Store_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$ — what a carrier adds in a period — every extendable component of that carrier, counting each build in the first period it stands in. Like PyPSA, it sums only the components that carry a carrier attribute, so a transformer, which has none, counts in no carrier | -| $`\mathrm{r}^{+}`$ | `Carrier_relative_growth` over $`\mathcal{I}`$ — the share of the previous period's additions a carrier's growth limit reads — PyPSA's `max_relative_growth` clipped at zero, so a negative share adds nothing and never tightens the limit | -| $`\check{\mathrm{load}}`$ | `Load_demand` over $`\mathcal{D} \times \Xi \times \mathcal{T}`$ — what a load draws from its bus's balance — its demand times its sign where it is active, nothing where it is not, since PyPSA drops an inactive load from the balance (`constraints.py:1513-1514`) | -| $`\check{s}`$ | `Line_s_monitored` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the flow a line's post-contingency rows read — its flow where it stands, nothing where it does not, since PyPSA builds those rows for every branch of the sub-network in every snapshot | -| $`\check{\sigma}`$ | `Transformer_s_monitored` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the flow a transformer's post-contingency rows read, as a line's | -| $`\hat{s}`$ | `Outage_s` over $`\mathcal{K}^{\mathrm{out}} \times \Xi \times \mathcal{T}`$ — the flow an outage takes off its branch — the outaged line's or transformer's flow before it goes out | -| $`\mathit{Generator\_injection}`$ | `Generator_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Line\_injection}`$ | `Line_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Link\_injection}`$ | `Link_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathrm{Load\_injection}`$ | `Load_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Process\_injection}`$ | `Process_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{StorageUnit\_injection}`$ | `StorageUnit_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Store\_injection}`$ | `Store_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Transformer\_injection}`$ | `Transformer_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ — what every component puts into a bus, less what it takes out of it; PyPSA writes each term into the balance, and a load on its right-hand side | -| $`\mathit{Line\_angle\_sum}`$ | `Line_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Transformer\_angle\_sum}`$ | `Transformer_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Cycle\_angle\_sum}`$ | `Cycle_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ — the voltage angle differences around a cycle: every branch flow times its cycle weight, and every transformer phase shift | +| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{L} \times \Xi`$ — what a `transmission_expansion_cost_limit` row totals — capital cost times the chosen build of the row's branches | +| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{L} \times \Xi`$ — what a `transmission_volume_expansion_limit` row totals — length times the chosen build of the row's branches | #### Notation @@ -5980,6 +5980,20 @@ Generator_com_ext: \mathrm{on}^{\mathrm{com,ext}}_{g,t} \iff \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \wedge \mathrm{on}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` +### `Generator_committed` + +```yaml +Generator_committed: + description: >- + a committable generator that stands in the snapshot's period — every + unit-commitment row's set + condition: Generator_committable AND Generator_active +``` + +```math +\mathrm{on}^{\mathrm{com}}_{g,t} \iff \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +``` + ### `Generator_maint_ext` ```yaml @@ -5999,20 +6013,6 @@ Generator_maint_ext: \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} \iff \mathrm{mnt}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \wedge \mathrm{on}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -### `Generator_committed` - -```yaml -Generator_committed: - description: >- - a committable generator that stands in the snapshot's period — every - unit-commitment row's set - condition: Generator_committable AND Generator_active -``` - -```math -\mathrm{on}^{\mathrm{com}}_{g,t} \iff \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} -``` - ### `Generator_ramps_from_previous` ```yaml @@ -6030,6 +6030,20 @@ Generator_ramps_from_previous: \mathrm{prev}_{g,\xi,t} \iff \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) > 0 \vee \mathrm{pos}(t) = 0 \wedge \left( \mathrm{u}^{0}_{g,\xi} = 0 \vee \mathrm{p}^{0}_{g,\xi} \text{ is defined} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` +### `Line_lossy` + +```yaml +Line_lossy: + description: >- + a line that stands in the snapshot's period, where the run models + transmission losses + condition: transmission_losses AND Line_active +``` + +```math +\mathrm{on}^{s,\mathrm{lossy}}_{k,t} \iff \mathrm{lossy} \wedge \mathrm{on}^{s}_{k,t} \qquad \forall\, k \in \mathcal{K},\ t \in \mathcal{T} +``` + ### `Link_com_ext` ```yaml @@ -6049,6 +6063,20 @@ Link_com_ext: \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \iff \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \wedge \mathrm{on}^{f}_{l,t} \qquad \forall\, l \in \mathcal{L},\ t \in \mathcal{T} ``` +### `Link_committed` + +```yaml +Link_committed: + description: >- + a committable link that stands in the snapshot's period — every + unit-commitment row's set + condition: Link_committable AND Link_active +``` + +```math +\mathrm{on}^{f,\mathrm{com}}_{l,t} \iff \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \qquad \forall\, l \in \mathcal{L},\ t \in \mathcal{T} +``` + ### `Link_maint_ext` ```yaml @@ -6068,20 +6096,6 @@ Link_maint_ext: \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} \iff \mathrm{mnt}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \wedge \mathrm{on}^{f}_{l,t} \qquad \forall\, l \in \mathcal{L},\ t \in \mathcal{T} ``` -### `Link_committed` - -```yaml -Link_committed: - description: >- - a committable link that stands in the snapshot's period — every - unit-commitment row's set - condition: Link_committable AND Link_active -``` - -```math -\mathrm{on}^{f,\mathrm{com}}_{l,t} \iff \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \qquad \forall\, l \in \mathcal{L},\ t \in \mathcal{T} -``` - ### `Link_ramps_from_previous` ```yaml @@ -6115,7 +6129,21 @@ Process_com_ext: ``` ```math -\mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \iff \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \wedge \mathrm{on}^{z}_{j,t} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} +\mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \iff \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \wedge \mathrm{on}^{z}_{j,t} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} +``` + +### `Process_committed` + +```yaml +Process_committed: + description: >- + a committable process that stands in the snapshot's period — every + unit-commitment row's set + condition: Process_committable AND Process_active +``` + +```math +\mathrm{on}^{z,\mathrm{com}}_{j,t} \iff \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} ``` ### `Process_maint_ext` @@ -6137,20 +6165,6 @@ Process_maint_ext: \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} \iff \mathrm{mnt}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \wedge \mathrm{on}^{z}_{j,t} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} ``` -### `Process_committed` - -```yaml -Process_committed: - description: >- - a committable process that stands in the snapshot's period — every - unit-commitment row's set - condition: Process_committable AND Process_active -``` - -```math -\mathrm{on}^{z,\mathrm{com}}_{j,t} \iff \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \qquad \forall\, j \in \mathcal{J},\ t \in \mathcal{T} -``` - ### `Process_ramps_from_previous` ```yaml @@ -6168,20 +6182,6 @@ Process_ramps_from_previous: \mathrm{prev}^{z}_{j,\xi,t} \iff \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) > 0 \vee \mathrm{pos}(t) = 0 \wedge \left( \mathrm{u}^{z,0}_{j,\xi} = 0 \vee \mathrm{z}^{0}_{j,\xi} \text{ is defined} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `StorageUnit_fix` - -```yaml -StorageUnit_fix: - description: >- - a storage unit with a fixed build that stands in the snapshot's period — - PyPSA's `fix` rows - condition: NOT StorageUnit_p_nom_extendable AND StorageUnit_active -``` - -```math -\mathrm{on}^{h,\mathrm{fix}}_{t,s} \iff \neg \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} -``` - ### `StorageUnit_ext` ```yaml @@ -6196,18 +6196,18 @@ StorageUnit_ext: \mathrm{on}^{h,\mathrm{ext}}_{t,s} \iff \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} ``` -### `Line_lossy` +### `StorageUnit_fix` ```yaml -Line_lossy: +StorageUnit_fix: description: >- - a line that stands in the snapshot's period, where the run models - transmission losses - condition: transmission_losses AND Line_active + a storage unit with a fixed build that stands in the snapshot's period — + PyPSA's `fix` rows + condition: NOT StorageUnit_p_nom_extendable AND StorageUnit_active ``` ```math -\mathrm{on}^{s,\mathrm{lossy}}_{k,t} \iff \mathrm{lossy} \wedge \mathrm{on}^{s}_{k,t} \qquad \forall\, k \in \mathcal{K},\ t \in \mathcal{T} +\mathrm{on}^{h,\mathrm{fix}}_{t,s} \iff \neg \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} ``` ### `Transformer_lossy` @@ -6226,58 +6226,46 @@ Transformer_lossy: #### Variable domains -**`Generator_p`** - -```math -p_{g,\xi,t} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}_{g,t} -``` - -**`Link_p`** - -```math -f_{l,\xi,t} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f}_{l,t} -``` - -**`Process_p`** +**`CVaR`** ```math -z_{j,\xi,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z}_{j,t} +CVaR \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} ``` -**`StorageUnit_p_dispatch`** +**`CVaR_a`** ```math -h^{+}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +a_{\xi} \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} ``` -**`StorageUnit_p_store`** +**`CVaR_theta`** ```math -h^{-}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +\theta \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} ``` -**`StorageUnit_state_of_charge`** +**`Generator_maintenance`** ```math -\mathit{soc}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +0 \le \mu_{g,\xi,t} \le 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` -**`StorageUnit_spill`** +**`Generator_maintenance_capacity`** ```math -0 \le \mathit{spill}_{\xi,t,s} \le \mathrm{inflow}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{inflow}_{\xi,t,s} > 0 \wedge \mathrm{on}^{h}_{t,s} +\mu^{\mathrm{nom}}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -**`Store_e`** +**`Generator_maintenance_start`** ```math -e_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} +\mu^{\mathrm{up}}_{g,\xi,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Store_p`** +**`Generator_maintenance_status`** ```math -q_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} +\mu^{u}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) ``` **`Generator_n_mod`** @@ -6286,16 +6274,16 @@ q_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v N_{g} \ge 0, N_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \wedge \mathrm{act}_{g} ``` -**`Generator_status`** +**`Generator_p`** ```math -u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +p_{g,\xi,t} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}_{g,t} ``` -**`Generator_start_up`** +**`Generator_p_nom_ext`** ```math -\mathit{up}_{g,\xi,t} \ge 0, \mathit{up}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +P_{g} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} ``` **`Generator_shut_down`** @@ -6304,58 +6292,52 @@ u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} \mathit{dn}_{g,\xi,t} \ge 0, \mathit{dn}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_maintenance`** - -```math -0 \le \mu_{g,\xi,t} \le 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} -``` - -**`Generator_maintenance_start`** +**`Generator_start_up`** ```math -\mu^{\mathrm{up}}_{g,\xi,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} +\mathit{up}_{g,\xi,t} \ge 0, \mathit{up}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_maintenance_capacity`** +**`Generator_status`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_maintenance_status`** +**`Line_loss`** ```math -\mu^{u}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) +\ell_{k,\xi,t} \ge 0 \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -**`Link_n_mod`** +**`Line_n_mod`** ```math -N^{f}_{l} \ge 0, N^{f}_{l} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} +N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} ``` -**`Link_status`** +**`Line_s`** ```math -u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +s_{k,\xi,t} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s}_{k,t} ``` -**`Link_start_up`** +**`Line_s_nom_ext`** ```math -\mathit{up}^{f}_{l,\xi,t} \ge 0, \mathit{up}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +S_{k} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} ``` -**`Link_shut_down`** +**`Link_maintenance`** ```math -\mathit{dn}^{f}_{l,\xi,t} \ge 0, \mathit{dn}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +0 \le \mu^{f}_{l,\xi,t} \le 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_maintenance`** +**`Link_maintenance_capacity`** ```math -0 \le \mu^{f}_{l,\xi,t} \le 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` **`Link_maintenance_start`** @@ -6364,52 +6346,52 @@ u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \ma \mu^{f,\mathrm{up}}_{l,\xi,t} \in \{0, 1\} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_maintenance_capacity`** +**`Link_maintenance_status`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +\mu^{f,u}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) ``` -**`Link_maintenance_status`** +**`Link_n_mod`** ```math -\mu^{f,u}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) +N^{f}_{l} \ge 0, N^{f}_{l} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} ``` -**`Process_n_mod`** +**`Link_p`** ```math -N^{z}_{j} \ge 0, N^{z}_{j} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} +f_{l,\xi,t} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f}_{l,t} ``` -**`Process_status`** +**`Link_p_nom_ext`** ```math -u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +F_{l} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} ``` -**`Process_start_up`** +**`Link_shut_down`** ```math -\mathit{up}^{z}_{j,\xi,t} \ge 0, \mathit{up}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +\mathit{dn}^{f}_{l,\xi,t} \ge 0, \mathit{dn}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Process_shut_down`** +**`Link_start_up`** ```math -\mathit{dn}^{z}_{j,\xi,t} \ge 0, \mathit{dn}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +\mathit{up}^{f}_{l,\xi,t} \ge 0, \mathit{up}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Process_maintenance`** +**`Link_status`** ```math -0 \le \mu^{z}_{j,\xi,t} \le 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Process_maintenance_start`** +**`Process_maintenance`** ```math -\mu^{z,\mathrm{up}}_{j,\xi,t} \in \{0, 1\} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +0 \le \mu^{z}_{j,\xi,t} \le 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` **`Process_maintenance_capacity`** @@ -6418,94 +6400,94 @@ u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \ma \mu^{z,\mathrm{nom}}_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -**`Process_maintenance_status`** +**`Process_maintenance_start`** ```math -\mu^{z,u}_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) +\mu^{z,\mathrm{up}}_{j,\xi,t} \in \{0, 1\} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Line_s`** +**`Process_maintenance_status`** ```math -s_{k,\xi,t} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s}_{k,t} +\mu^{z,u}_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) ``` -**`Line_loss`** +**`Process_n_mod`** ```math -\ell_{k,\xi,t} \ge 0 \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +N^{z}_{j} \ge 0, N^{z}_{j} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} ``` -**`Transformer_s`** +**`Process_p`** ```math -\sigma_{\xi,t,m} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma}_{t,m} +z_{j,\xi,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z}_{j,t} ``` -**`Transformer_loss`** +**`Process_p_nom_ext`** ```math -\ell^{\sigma}_{\xi,t,m} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +Z_{j} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} ``` -**`Transformer_phase_shift`** +**`Process_shut_down`** ```math -\mathrm{Transformer\_phase\_shift\_min}_{m} \le \mathit{Transformer\_phase\_shift}_{\xi,t,m} \le \mathrm{Transformer\_phase\_shift\_max}_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mathit{dn}^{z}_{j,\xi,t} \ge 0, \mathit{dn}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Line_s_nom_ext`** +**`Process_start_up`** ```math -S_{k} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} +\mathit{up}^{z}_{j,\xi,t} \ge 0, \mathit{up}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Line_n_mod`** +**`Process_status`** ```math -N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} +u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Generator_p_nom_ext`** +**`StorageUnit_n_mod`** ```math -P_{g} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} +N^{h}_{s} \ge 0, N^{h}_{s} \in \mathbb{Z} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} ``` -**`Link_p_nom_ext`** +**`StorageUnit_p_dispatch`** ```math -F_{l} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} +h^{+}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -**`Process_p_nom_ext`** +**`StorageUnit_p_nom_ext`** ```math -Z_{j} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} +H_{s} \in \mathbb{R} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} ``` -**`Transformer_s_nom_ext`** +**`StorageUnit_p_store`** ```math -\Sigma_{m} \in \mathbb{R} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} +h^{-}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -**`Transformer_n_mod`** +**`StorageUnit_spill`** ```math -N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} +0 \le \mathit{spill}_{\xi,t,s} \le \mathrm{inflow}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{inflow}_{\xi,t,s} > 0 \wedge \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_p_nom_ext`** +**`StorageUnit_state_of_charge`** ```math -H_{s} \in \mathbb{R} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} +\mathit{soc}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_n_mod`** +**`Store_e`** ```math -N^{h}_{s} \ge 0, N^{h}_{s} \in \mathbb{Z} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} +e_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} ``` **`Store_e_nom_ext`** @@ -6517,1448 +6499,1377 @@ E_{v} \in \mathbb{R} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{ **`Store_n_mod`** ```math -N^{e}_{v} \ge 0, N^{e}_{v} \in \mathbb{Z} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} -``` - -**`CVaR_a`** - -```math -a_{\xi} \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} -``` - -**`CVaR_theta`** - -```math -\theta \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} -``` - -**`CVaR`** - -```math -CVaR \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} -``` - -### `Generator_previous_status` - -```yaml -Generator_previous_status: - description: >- - the commitment state a generator carries into a snapshot — off at the - first snapshot it stands in past the first of the horizon, as PyPSA - reads a status it did not build (`constraints.py:298`), and the state - carried over otherwise - dims: [scenario, snapshot, generator] - cases: - opening_late: { when: "position(snapshot) > 0 AND NOT shift(Generator_active, along=snapshot, offset=1)", expression: 0 } - otherwise: Generator_status_carried_over +N^{e}_{v} \ge 0, N^{e}_{v} \in \mathbb{Z} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} ``` +**`Store_p`** + ```math -\overleftarrow{u}_{g,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}_{g,t - 1} \\ \overleftarrow{u}^{\circ}_{g,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +q_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} ``` -### `Generator_status_carried_over` +**`Transformer_loss`** -```yaml -Generator_status_carried_over: - description: >- - the state a generator carries over into a snapshot — the state it brought - into the horizon at the first, the previous snapshot's after that - dims: [scenario, snapshot, generator] - cases: - opening: { when: "position(snapshot) == 0", expression: Generator_status_initial } - otherwise: shift(Generator_status, along=snapshot, offset=1) +```math +\ell^{\sigma}_{\xi,t,m} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` +**`Transformer_n_mod`** + ```math -\overleftarrow{u}^{\circ}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} ``` -### `Generator_previous_p` +**`Transformer_phase_shift`** -```yaml -Generator_previous_p: - description: >- - the output a generator carries into a snapshot — at the first, the - `p_init` it brought in where it came in running and nothing where it - came in off; the previous snapshot's after that - dims: [scenario, snapshot, generator] - cases: - opening: { when: "position(snapshot) == 0", expression: Generator_status_initial * Generator_p_init } - otherwise: shift(Generator_p, along=snapshot, offset=1) +```math +\mathrm{Transformer\_phase\_shift\_min}_{m} \le \mathit{Transformer\_phase\_shift}_{\xi,t,m} \le \mathrm{Transformer\_phase\_shift\_max}_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` +**`Transformer_s`** + ```math -\overleftarrow{p}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} \cdot \mathrm{p}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ p_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\sigma_{\xi,t,m} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma}_{t,m} ``` -### `Generator_p_nom_effective` +**`Transformer_s_nom_ext`** + +```math +\Sigma_{m} \in \mathbb{R} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} +``` + +### `Bus_injection` ```yaml -Generator_p_nom_effective: - description: the build a generator's limits are taken against — the chosen one where it is extendable, the given one otherwise - dims: [scenario, generator] - cases: - extendable: { when: Generator_p_nom_extendable, expression: Generator_p_nom_ext } - otherwise: Generator_p_nom +Bus_injection: + dims: [scenario, snapshot, bus] + expression: >- + Generator_injection + + Line_injection + + Link_injection + + Load_injection + + Process_injection + + StorageUnit_injection + + Store_injection + + Transformer_injection + description: >- + what every component puts into a bus, less what it takes out of it; + PyPSA writes each term into the balance, and a load on its right-hand + side ``` ```math -\widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} P_{g} & \text{if } \mathrm{ext}_{g} \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Bus\_injection}_{n,\xi,t} = \mathit{Generator\_injection}_{n,\xi,t} + \mathit{Line\_injection}_{n,\xi,t} + \mathit{Link\_injection}_{n,\xi,t} + \mathrm{Load\_injection}_{n,\xi,t} + \mathit{Process\_injection}_{n,\xi,t} + \mathit{StorageUnit\_injection}_{n,\xi,t} + \mathit{Store\_injection}_{n,\xi,t} + \mathit{Transformer\_injection}_{n,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_ramp_up_rate` +### `Carrier_additions` ```yaml -Generator_ramp_up_rate: +Carrier_additions: + dims: [period, carrier] + expression: >- + Generator_additions + + Line_additions + + Link_additions + + Process_additions + + StorageUnit_additions + + Store_additions description: >- - the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the - full build where it has none, since a start-up ramp alone builds the row - dims: [scenario, snapshot, generator] - cases: - given: { when: Generator_ramp_limit_up, expression: Generator_ramp_limit_up } - otherwise: 1 + what a carrier adds in a period — every extendable component of that + carrier, counting each build in the first period it stands in. Like + PyPSA, it sums only the components that carry a carrier attribute, so a + transformer, which has none, counts in no carrier ``` ```math -\widetilde{\mathrm{ru}}_{g,\xi,t} = \begin{cases} \mathrm{ru}_{g,\xi,t} & \text{if } \mathrm{ru}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Carrier\_additions}_{i,y} = \mathit{Generator\_additions}_{i,y} + \mathit{Line\_additions}_{i,y} + \mathit{Link\_additions}_{i,y} + \mathit{Process\_additions}_{i,y} + \mathit{StorageUnit\_additions}_{i,y} + \mathit{Store\_additions}_{i,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Generator_ramp_down_rate` +### `Carrier_relative_growth` ```yaml -Generator_ramp_down_rate: +Carrier_relative_growth: description: >- - the ramp limit a unit's down row reads — PyPSA's `ramp_limit_down`, or - the full build where it has none, since a shut-down ramp alone builds the row - dims: [scenario, snapshot, generator] + the share of the previous period's additions a carrier's growth limit + reads — PyPSA's `max_relative_growth` clipped at zero, so a negative + share adds nothing and never tightens the limit + dims: [carrier] cases: - given: { when: Generator_ramp_limit_down, expression: Generator_ramp_limit_down } - otherwise: 1 + positive: { when: Carrier_max_relative_growth > 0, expression: Carrier_max_relative_growth } + otherwise: 0 ``` ```math -\widetilde{\mathrm{rd}}_{g,\xi,t} = \begin{cases} \mathrm{rd}_{g,\xi,t} & \text{if } \mathrm{rd}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathrm{r}^{+}_{i} = \begin{cases} \mathrm{r}_{i} & \text{if } \mathrm{r}_{i} > 0 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I} ``` -### `Generator_start_up_rate` +### `Cycle_angle_sum` ```yaml -Generator_start_up_rate: +Cycle_angle_sum: + dims: [scenario, snapshot, cycle] + expression: Line_angle_sum + Transformer_angle_sum description: >- - the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, - or the full build where it has none - dims: [scenario, generator] - cases: - given: { when: Generator_ramp_limit_start_up, expression: Generator_ramp_limit_start_up } - otherwise: 1 + the voltage angle differences around a cycle: every branch flow times + its cycle weight, and every transformer phase shift ``` ```math -\widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} = \begin{cases} \mathrm{ru}^{\mathrm{up}}_{g,\xi} & \text{if } \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Cycle\_angle\_sum}_{c,\xi,t} = \mathit{Line\_angle\_sum}_{c,\xi,t} + \mathit{Transformer\_angle\_sum}_{c,\xi,t} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_shut_down_rate` +### `Generator_additions` ```yaml -Generator_shut_down_rate: - description: >- - the shut-down ramp a unit's down row reads — PyPSA's - `ramp_limit_shut_down`, or the full build where it has none - dims: [scenario, generator] - cases: - given: { when: Generator_ramp_limit_shut_down, expression: Generator_ramp_limit_shut_down } - otherwise: 1 +Generator_additions: + expression: >- + sum(Generator_p_nom_ext * Generator_first_active, over=generator, by=Generator_carrier[carrier]) ``` ```math -\widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} = \begin{cases} \mathrm{rd}^{\mathrm{dn}}_{g,\xi} & \text{if } \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Generator\_additions}_{i,y} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_carrier}(g) = i} P_{g} \cdot \mathrm{new}_{g,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Generator_p_nom_committed` +### `Generator_capex` ```yaml -Generator_p_nom_committed: - description: >- - the build a committed unit's ramp rows are taken against — one module - where the build is extendable and modular, the given build otherwise - dims: [scenario, generator] - cases: - modular_build: { when: Generator_p_nom_extendable AND Generator_p_nom_mod > 0, expression: Generator_p_nom_mod } - otherwise: Generator_p_nom +Generator_capex: + expression: sum(scenario_weight * Generator_p_nom_ext * Generator_capital_cost * Generator_capital_weight) ``` ```math -\widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} \mathrm{p}^{\mathrm{mod}}_{g} & \text{if } \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Generator\_capex} = \sum_{g \in \mathcal{G},\ \xi \in \Xi} \pi_{\xi} \cdot P_{g} \cdot \mathrm{c}^{\mathrm{cap}}_{g,\xi} \cdot \mathrm{W}_{g} ``` -### `Generator_ramp_up_allowance` +### `Generator_commitment_opex` ```yaml -Generator_ramp_up_allowance: - description: >- - how far a generator may raise output between two snapshots — its ramp - limit of the build while it stays on, plus its start-up ramp in the - snapshot it turns on - dims: [scenario, snapshot, generator] - cases: - committed: - when: Generator_committable - expression: >- - Generator_ramp_up_rate * Generator_p_nom_committed * Generator_previous_status - + Generator_start_up_rate * Generator_p_nom_committed - * (Generator_status - Generator_previous_status) - otherwise: Generator_ramp_up_rate * Generator_p_nom_effective +Generator_commitment_opex: + expression: >- + sum(sum(((Generator_status * Generator_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) + + sum(sum(Generator_start_up * Generator_start_up_cost, over=generator), over=snapshot) + + sum(sum(Generator_shut_down * Generator_shut_down_cost, over=generator), over=snapshot) ``` ```math -\Delta^{+}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} + \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} u_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{on}}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{up}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{up}}_{g,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{dn}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{dn}}_{g,\xi,t} \qquad \forall\, \xi \in \Xi ``` -### `Generator_ramp_down_allowance` +### `Generator_injection` ```yaml -Generator_ramp_down_allowance: - description: >- - how far a generator may lower output between two snapshots — its ramp - limit of the build while it stays on, plus its shut-down ramp in the - snapshot it turns off - dims: [scenario, snapshot, generator] - cases: - committed: - when: Generator_committable - expression: >- - Generator_ramp_down_rate * Generator_p_nom_committed * Generator_status - + Generator_shut_down_rate * Generator_p_nom_committed - * (Generator_previous_status - Generator_status) - otherwise: Generator_ramp_down_rate * Generator_p_nom_effective +Generator_injection: + expression: sum(Generator_sign * Generator_p, over=generator, by=Generator_bus[bus]) ``` ```math -\Delta^{-}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot u_{g,\xi,t} + \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_injection}_{n,\xi,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_p_nom_effective` +### `Generator_operational_limit` ```yaml -Link_p_nom_effective: - description: the build a link's limits are taken against — the chosen one where it is extendable, the given one otherwise - dims: [scenario, link] - cases: - extendable: { when: Link_p_nom_extendable, expression: Link_p_nom_ext } - otherwise: Link_p_nom +Generator_operational_limit: + expression: >- + sum(sum((Generator_p * GlobalConstraint_energy_weight) * Generator_operational_limit_weight, over=snapshot), over=generator) ``` ```math -\widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} F_{l} & \text{if } \mathrm{ext}^{f}_{l} \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\mathit{Generator\_operational\_limit}_{l,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{l,\xi,t} \cdot \mathrm{b}_{g,l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_previous_status` +### `Generator_opex` ```yaml -Link_previous_status: - description: >- - the commitment state a link carries into a snapshot — off at the - first snapshot it stands in past the first of the horizon, as PyPSA - reads a status it did not build (`constraints.py:298`), and the state - carried over otherwise - dims: [scenario, snapshot, link] - cases: - opening_late: { when: "position(snapshot) > 0 AND NOT shift(Link_active, along=snapshot, offset=1)", expression: 0 } - otherwise: Link_status_carried_over +Generator_opex: + expression: >- + sum(sum(((Generator_p * Generator_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) + + sum(sum((((Generator_p * Generator_p) * Generator_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) ``` ```math -\overleftarrow{u}^{f}_{l,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{f}_{l,t - 1} \\ \overleftarrow{u}^{\circ f}_{l,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot \mathrm{c}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot p_{g,\xi,t} \cdot \mathrm{c}^{(2)}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -### `Link_status_carried_over` +### `Generator_p_nom_committed` ```yaml -Link_status_carried_over: +Generator_p_nom_committed: description: >- - the state a link carries over into a snapshot — the state it brought - into the horizon at the first, the previous snapshot's after that - dims: [scenario, snapshot, link] + the build a committed unit's ramp rows are taken against — one module + where the build is extendable and modular, the given build otherwise + dims: [scenario, generator] cases: - opening: { when: "position(snapshot) == 0", expression: Link_status_initial } - otherwise: shift(Link_status, along=snapshot, offset=1) + modular_build: { when: Generator_p_nom_extendable AND Generator_p_nom_mod > 0, expression: Generator_p_nom_mod } + otherwise: Generator_p_nom ``` ```math -\overleftarrow{u}^{\circ f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{f}_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} \mathrm{p}^{\mathrm{mod}}_{g} & \text{if } \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -### `Link_previous_p` +### `Generator_p_nom_effective` ```yaml -Link_previous_p: - description: >- - the flow a link carries into a snapshot — at the first, the - `p_init` it brought in where it came in running and nothing where it - came in off; the previous snapshot's after that - dims: [scenario, snapshot, link] +Generator_p_nom_effective: + description: the build a generator's limits are taken against — the chosen one where it is extendable, the given one otherwise + dims: [scenario, generator] cases: - opening: { when: "position(snapshot) == 0", expression: Link_status_initial * Link_p_init } - otherwise: shift(Link_p, along=snapshot, offset=1) + extendable: { when: Generator_p_nom_extendable, expression: Generator_p_nom_ext } + otherwise: Generator_p_nom ``` ```math -\overleftarrow{f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} \cdot \mathrm{f}^{0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ f_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} P_{g} & \text{if } \mathrm{ext}_{g} \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -### `Link_ramp_up_rate` +### `Generator_previous_p` ```yaml -Link_ramp_up_rate: +Generator_previous_p: description: >- - the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the - full build where it has none, since a start-up ramp alone builds the row - dims: [scenario, snapshot, link] + the output a generator carries into a snapshot — at the first, the + `p_init` it brought in where it came in running and nothing where it + came in off; the previous snapshot's after that + dims: [scenario, snapshot, generator] cases: - given: { when: Link_ramp_limit_up, expression: Link_ramp_limit_up } - otherwise: 1 + opening: { when: "position(snapshot) == 0", expression: Generator_status_initial * Generator_p_init } + otherwise: shift(Generator_p, along=snapshot, offset=1) ``` ```math -\widetilde{\mathrm{ru}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{ru}^{f}_{l,\xi,t} & \text{if } \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{p}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} \cdot \mathrm{p}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ p_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_ramp_down_rate` +### `Generator_previous_status` ```yaml -Link_ramp_down_rate: +Generator_previous_status: description: >- - the ramp limit a link's down row reads — PyPSA's `ramp_limit_down`, or - the full build where it has none, since a shut-down ramp alone builds the row - dims: [scenario, snapshot, link] + the commitment state a generator carries into a snapshot — off at the + first snapshot it stands in past the first of the horizon, as PyPSA + reads a status it did not build (`constraints.py:298`), and the state + carried over otherwise + dims: [scenario, snapshot, generator] cases: - given: { when: Link_ramp_limit_down, expression: Link_ramp_limit_down } - otherwise: 1 + opening_late: { when: "position(snapshot) > 0 AND NOT shift(Generator_active, along=snapshot, offset=1)", expression: 0 } + otherwise: Generator_status_carried_over ``` ```math -\widetilde{\mathrm{rd}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{rd}^{f}_{l,\xi,t} & \text{if } \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{u}_{g,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}_{g,t - 1} \\ \overleftarrow{u}^{\circ}_{g,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_start_up_rate` +### `Generator_primary_energy` ```yaml -Link_start_up_rate: - description: >- - the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, - or the full build where it has none - dims: [scenario, link] - cases: - given: { when: Link_ramp_limit_start_up, expression: Link_ramp_limit_start_up } - otherwise: 1 +Generator_primary_energy: + expression: >- + sum(sum((Generator_p * GlobalConstraint_energy_weight) * Generator_primary_energy_weight, over=snapshot), over=generator) ``` ```math -\widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} = \begin{cases} \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} & \text{if } \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\mathit{Generator\_primary\_energy}_{l,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{l,\xi,t} \cdot \mathrm{a}_{g,l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_shut_down_rate` +### `Generator_ramp_down_allowance` ```yaml -Link_shut_down_rate: +Generator_ramp_down_allowance: description: >- - the shut-down ramp a link's down row reads — PyPSA's - `ramp_limit_shut_down`, or the full build where it has none - dims: [scenario, link] + how far a generator may lower output between two snapshots — its ramp + limit of the build while it stays on, plus its shut-down ramp in the + snapshot it turns off + dims: [scenario, snapshot, generator] cases: - given: { when: Link_ramp_limit_shut_down, expression: Link_ramp_limit_shut_down } - otherwise: 1 + committed: + when: Generator_committable + expression: >- + Generator_ramp_down_rate * Generator_p_nom_committed * Generator_status + + Generator_shut_down_rate * Generator_p_nom_committed + * (Generator_previous_status - Generator_status) + otherwise: Generator_ramp_down_rate * Generator_p_nom_effective ``` ```math -\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} = \begin{cases} \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} & \text{if } \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\Delta^{-}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot u_{g,\xi,t} + \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_p_nom_committed` +### `Generator_ramp_down_rate` ```yaml -Link_p_nom_committed: +Generator_ramp_down_rate: description: >- - the build a committed link's ramp rows are taken against — one module - where the build is extendable and modular, the given build otherwise - dims: [scenario, link] + the ramp limit a unit's down row reads — PyPSA's `ramp_limit_down`, or + the full build where it has none, since a shut-down ramp alone builds the row + dims: [scenario, snapshot, generator] cases: - modular_build: { when: Link_p_nom_extendable AND Link_p_nom_mod > 0, expression: Link_p_nom_mod } - otherwise: Link_p_nom + given: { when: Generator_ramp_limit_down, expression: Generator_ramp_limit_down } + otherwise: 1 ``` ```math -\widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} \mathrm{f}^{\mathrm{mod}}_{l} & \text{if } \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\widetilde{\mathrm{rd}}_{g,\xi,t} = \begin{cases} \mathrm{rd}_{g,\xi,t} & \text{if } \mathrm{rd}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_ramp_up_allowance` +### `Generator_ramp_up_allowance` ```yaml -Link_ramp_up_allowance: +Generator_ramp_up_allowance: description: >- - how far a link may raise flow between two snapshots — its ramp + how far a generator may raise output between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on - dims: [scenario, snapshot, link] + dims: [scenario, snapshot, generator] cases: committed: - when: Link_committable + when: Generator_committable expression: >- - Link_ramp_up_rate * Link_p_nom_committed * Link_previous_status - + Link_start_up_rate * Link_p_nom_committed - * (Link_status - Link_previous_status) - otherwise: Link_ramp_up_rate * Link_p_nom_effective + Generator_ramp_up_rate * Generator_p_nom_committed * Generator_previous_status + + Generator_start_up_rate * Generator_p_nom_committed + * (Generator_status - Generator_previous_status) + otherwise: Generator_ramp_up_rate * Generator_p_nom_effective ``` ```math -\Delta^{f,+}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} + \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\Delta^{+}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} + \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_ramp_down_allowance` +### `Generator_ramp_up_rate` ```yaml -Link_ramp_down_allowance: +Generator_ramp_up_rate: description: >- - how far a link may lower flow between two snapshots — its ramp - limit of the build while it stays on, plus its shut-down ramp in the - snapshot it turns off - dims: [scenario, snapshot, link] + the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the + full build where it has none, since a start-up ramp alone builds the row + dims: [scenario, snapshot, generator] cases: - committed: - when: Link_committable - expression: >- - Link_ramp_down_rate * Link_p_nom_committed * Link_status - + Link_shut_down_rate * Link_p_nom_committed - * (Link_previous_status - Link_status) - otherwise: Link_ramp_down_rate * Link_p_nom_effective + given: { when: Generator_ramp_limit_up, expression: Generator_ramp_limit_up } + otherwise: 1 ``` ```math -\Delta^{f,-}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot u^{f}_{l,\xi,t} + \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{ru}}_{g,\xi,t} = \begin{cases} \mathrm{ru}_{g,\xi,t} & \text{if } \mathrm{ru}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_p_nom_effective` +### `Generator_shut_down_rate` ```yaml -Process_p_nom_effective: - description: the build a process's limits are taken against — the chosen one where it is extendable, the given one otherwise - dims: [scenario, process] +Generator_shut_down_rate: + description: >- + the shut-down ramp a unit's down row reads — PyPSA's + `ramp_limit_shut_down`, or the full build where it has none + dims: [scenario, generator] cases: - extendable: { when: Process_p_nom_extendable, expression: Process_p_nom_ext } - otherwise: Process_p_nom + given: { when: Generator_ramp_limit_shut_down, expression: Generator_ramp_limit_shut_down } + otherwise: 1 ``` ```math -\widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} Z_{j} & \text{if } \mathrm{ext}^{z}_{j} \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} = \begin{cases} \mathrm{rd}^{\mathrm{dn}}_{g,\xi} & \text{if } \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -### `Process_previous_status` +### `Generator_start_up_rate` ```yaml -Process_previous_status: +Generator_start_up_rate: description: >- - the commitment state a process carries into a snapshot — off at the - first snapshot it stands in past the first of the horizon, as PyPSA - reads a status it did not build (`constraints.py:298`), and the state - carried over otherwise - dims: [scenario, snapshot, process] + the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, + or the full build where it has none + dims: [scenario, generator] cases: - opening_late: { when: "position(snapshot) > 0 AND NOT shift(Process_active, along=snapshot, offset=1)", expression: 0 } - otherwise: Process_status_carried_over + given: { when: Generator_ramp_limit_start_up, expression: Generator_ramp_limit_start_up } + otherwise: 1 ``` ```math -\overleftarrow{u}^{z}_{j,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{z}_{j,t - 1} \\ \overleftarrow{u}^{\circ z}_{j,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} = \begin{cases} \mathrm{ru}^{\mathrm{up}}_{g,\xi} & \text{if } \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -### `Process_status_carried_over` +### `Generator_status_carried_over` ```yaml -Process_status_carried_over: +Generator_status_carried_over: description: >- - the state a process carries over into a snapshot — the state it brought + the state a generator carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that - dims: [scenario, snapshot, process] + dims: [scenario, snapshot, generator] cases: - opening: { when: "position(snapshot) == 0", expression: Process_status_initial } - otherwise: shift(Process_status, along=snapshot, offset=1) + opening: { when: "position(snapshot) == 0", expression: Generator_status_initial } + otherwise: shift(Generator_status, along=snapshot, offset=1) ``` ```math -\overleftarrow{u}^{\circ z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{z}_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{u}^{\circ}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_previous_p` +### `Generator_tech_capacity_expansion` ```yaml -Process_previous_p: - description: >- - the internal power a process carries into a snapshot — at the first, the - `p_init` it brought in where it came in running and nothing where it - came in off; the previous snapshot's after that - dims: [scenario, snapshot, process] - cases: - opening: { when: "position(snapshot) == 0", expression: Process_status_initial * Process_p_init } - otherwise: shift(Process_p, along=snapshot, offset=1) +Generator_tech_capacity_expansion: + expression: sum(Generator_p_nom_ext * Generator_tech_capacity_weight, over=generator) ``` ```math -\overleftarrow{z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} \cdot \mathrm{z}^{0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ z_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_tech\_capacity\_expansion}_{l} = \sum_{g \in \mathcal{G}} P_{g} \cdot \mathrm{m}_{g,l} \qquad \forall\, l \in \mathcal{L} ``` -### `Process_ramp_up_rate` +### `GlobalConstraint_energy_weight` ```yaml -Process_ramp_up_rate: +GlobalConstraint_energy_weight: description: >- - the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the - full build where it has none, since a start-up ramp alone builds the row - dims: [scenario, snapshot, process] + what one unit of power at a snapshot counts for in a row — the + generator weighting times the years of the snapshot's period, where the + row counts the snapshot, and nothing where it does not + dims: [scenario, global_constraint, snapshot] cases: - given: { when: Process_ramp_limit_up, expression: Process_ramp_limit_up } - otherwise: 1 + counted: + when: GlobalConstraint_counts_snapshot + expression: snapshot_weightings_generators * at(period_weight_years, by=snapshot_period[period]) + otherwise: 0 ``` ```math -\widetilde{\mathrm{ru}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{ru}^{z}_{j,\xi,t} & \text{if } \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{w}^{\mathrm{gc}}_{l,\xi,t} = \begin{cases} \mathrm{w}^{\mathrm{gen}}_{t} \cdot \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{in}_{l,\xi,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_ramp_down_rate` +### `Line_additions` ```yaml -Process_ramp_down_rate: - description: >- - the ramp limit a process's down row reads — PyPSA's `ramp_limit_down`, or - the full build where it has none, since a shut-down ramp alone builds the row - dims: [scenario, snapshot, process] - cases: - given: { when: Process_ramp_limit_down, expression: Process_ramp_limit_down } - otherwise: 1 +Line_additions: + expression: >- + sum(Line_s_nom_ext * Line_first_active, over=line, by=Line_carrier[carrier]) ``` ```math -\widetilde{\mathrm{rd}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{rd}^{z}_{j,\xi,t} & \text{if } \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Line\_additions}_{i,y} = \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_carrier}(k) = i} S_{k} \cdot \mathrm{new}^{s}_{k,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Process_start_up_rate` +### `Line_angle_sum` ```yaml -Process_start_up_rate: - description: >- - the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, - or the full build where it has none - dims: [scenario, process] - cases: - given: { when: Process_ramp_limit_start_up, expression: Process_ramp_limit_start_up } - otherwise: 1 +Line_angle_sum: sum(Line_s * at(Line_cycle_weight, by=snapshot_period[period]), over=line) ``` ```math -\widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} = \begin{cases} \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} & \text{if } \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\mathit{Line\_angle\_sum}_{c,\xi,t} = \sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_shut_down_rate` +### `Line_capex` ```yaml -Process_shut_down_rate: - description: >- - the shut-down ramp a process's down row reads — PyPSA's - `ramp_limit_shut_down`, or the full build where it has none - dims: [scenario, process] - cases: - given: { when: Process_ramp_limit_shut_down, expression: Process_ramp_limit_shut_down } - otherwise: 1 +Line_capex: + expression: sum(scenario_weight * Line_s_nom_ext * Line_capital_cost * Line_capital_weight) ``` ```math -\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} = \begin{cases} \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} & \text{if } \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\mathit{Line\_capex} = \sum_{k \in \mathcal{K},\ \xi \in \Xi} \pi_{\xi} \cdot S_{k} \cdot \mathrm{c}^{\mathrm{cap},s}_{k,\xi} \cdot \mathrm{W}^{s}_{k} ``` -### `Process_p_nom_committed` +### `Line_injection` ```yaml -Process_p_nom_committed: - description: >- - the build a committed process's ramp rows are taken against — one module - where the build is extendable and modular, the given build otherwise - dims: [scenario, process] - cases: - modular_build: { when: Process_p_nom_extendable AND Process_p_nom_mod > 0, expression: Process_p_nom_mod } - otherwise: Process_p_nom +Line_injection: + expression: >- + -sum(Line_s, over=line, by=Line_bus0[bus]) + + sum(Line_s, over=line, by=Line_bus1[bus]) + - (0.5 * sum(Line_loss, over=line, by=Line_bus0[bus])) + - (0.5 * sum(Line_loss, over=line, by=Line_bus1[bus])) ``` ```math -\widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} \mathrm{z}^{\mathrm{mod}}_{j} & \text{if } \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\mathit{Line\_injection}_{n,\xi,t} = -\left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_ramp_up_allowance` +### `Line_s_monitored` ```yaml -Process_ramp_up_allowance: +Line_s_monitored: description: >- - how far a process may raise internal power between two snapshots — its ramp - limit of the build while it stays on, plus its start-up ramp in the - snapshot it turns on - dims: [scenario, snapshot, process] + the flow a line's post-contingency rows read — its flow where it stands, + nothing where it does not, since PyPSA builds those rows for every + branch of the sub-network in every snapshot + dims: [scenario, snapshot, line] cases: - committed: - when: Process_committable - expression: >- - Process_ramp_up_rate * Process_p_nom_committed * Process_previous_status - + Process_start_up_rate * Process_p_nom_committed - * (Process_status - Process_previous_status) - otherwise: Process_ramp_up_rate * Process_p_nom_effective + standing: { when: Line_active, expression: Line_s } + otherwise: 0 ``` ```math -\Delta^{z,+}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} + \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\check{s}_{k,\xi,t} = \begin{cases} s_{k,\xi,t} & \text{if } \mathrm{on}^{s}_{k,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_ramp_down_allowance` +### `Line_tech_capacity_expansion` ```yaml -Process_ramp_down_allowance: - description: >- - how far a process may lower internal power between two snapshots — its ramp - limit of the build while it stays on, plus its shut-down ramp in the - snapshot it turns off - dims: [scenario, snapshot, process] - cases: - committed: - when: Process_committable - expression: >- - Process_ramp_down_rate * Process_p_nom_committed * Process_status - + Process_shut_down_rate * Process_p_nom_committed - * (Process_previous_status - Process_status) - otherwise: Process_ramp_down_rate * Process_p_nom_effective +Line_tech_capacity_expansion: + expression: sum(Line_s_nom_ext * Line_tech_capacity_weight, over=line) ``` ```math -\Delta^{z,-}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot u^{z}_{j,\xi,t} + \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Line\_tech\_capacity\_expansion}_{l} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{m}^{l}_{l,k} \qquad \forall\, l \in \mathcal{L} ``` -### `StorageUnit_charge_carried_in` +### `Line_transmission_expansion_cost` ```yaml -StorageUnit_charge_carried_in: - description: >- - the charge a unit opens a snapshot with — at the first snapshot it - stands in, its last such snapshot's less standing loss where it is - cyclic and the given initial charge, which no standing loss has touched - yet, where it is not; the previous snapshot's less standing loss - otherwise. A unit built in a later period opens in that period, and a - cyclic one that retires closes on its own last snapshot. Per period, the - same holds with each investment period as the horizon - dims: [scenario, snapshot, storage_unit] - cases: - cyclic: - when: >- - StorageUnit_cyclic_state_of_charge AND NOT StorageUnit_cyclic_state_of_charge_per_period - AND NOT StorageUnit_state_of_charge_initial_per_period - AND (position(snapshot) == 0 OR StorageUnit_opens_late) - expression: >- - StorageUnit_retention - * shift(shift(StorageUnit_state_of_charge, along=snapshot, offset=1, edge='wrap'), along=snapshot, offset=StorageUnit_inactive_snapshots, edge='wrap') - opening: - when: >- - NOT StorageUnit_cyclic_state_of_charge AND NOT StorageUnit_cyclic_state_of_charge_per_period - AND NOT StorageUnit_state_of_charge_initial_per_period - AND (position(snapshot) == 0 OR StorageUnit_opens_late) - expression: StorageUnit_state_of_charge_initial - period_cyclic: - when: StorageUnit_cyclic_state_of_charge_per_period - expression: >- - StorageUnit_retention - * shift(StorageUnit_state_of_charge, along=snapshot, offset=1, edge='wrap', within=snapshot_period[period]) - period_opening: - when: >- - StorageUnit_state_of_charge_initial_per_period AND NOT StorageUnit_cyclic_state_of_charge_per_period - AND position(snapshot, within=snapshot_period[period]) == 0 - expression: StorageUnit_state_of_charge_initial - otherwise: StorageUnit_retention * shift(StorageUnit_state_of_charge, along=snapshot, offset=1) +Line_transmission_expansion_cost: + expression: sum(Line_s_nom_ext * Line_expansion_cost_weight, over=line) ``` ```math -\overleftarrow{\mathit{soc}}_{\xi,t,s} = \begin{cases} \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,\left( t \ominus \mathrm{idle} \right) \ominus 1,s} & \text{if } \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \neg \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,s} & \text{if } \mathrm{cyc}^{y}_{\xi,s} \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \mathrm{reset}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t - 1,s} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\mathit{Line\_transmission\_expansion\_cost}_{l,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{cc}_{l,k,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Store_energy_carried_in` +### `Line_transmission_volume_expansion` ```yaml -Store_energy_carried_in: - description: >- - the energy a store opens a snapshot with — at the first snapshot it - stands in, its last such snapshot's less standing loss where it is - cyclic and the given initial energy, which no standing loss has touched - yet, where it is not; the previous snapshot's less standing loss - otherwise. A store built in a later period opens in that period, and a - cyclic one that retires closes on its own last snapshot. Per period, the - same holds with each investment period as the horizon - dims: [scenario, snapshot, store] - cases: - cyclic: - when: >- - Store_e_cyclic AND NOT Store_e_cyclic_per_period AND NOT Store_e_initial_per_period - AND (position(snapshot) == 0 OR Store_opens_late) - expression: >- - Store_retention - * shift(shift(Store_e, along=snapshot, offset=1, edge='wrap'), along=snapshot, offset=Store_inactive_snapshots, edge='wrap') - opening: - when: >- - NOT Store_e_cyclic AND NOT Store_e_cyclic_per_period AND NOT Store_e_initial_per_period - AND (position(snapshot) == 0 OR Store_opens_late) - expression: Store_e_initial - period_cyclic: - when: Store_e_cyclic_per_period - expression: Store_retention * shift(Store_e, along=snapshot, offset=1, edge='wrap', within=snapshot_period[period]) - period_opening: - when: Store_e_initial_per_period AND NOT Store_e_cyclic_per_period AND position(snapshot, within=snapshot_period[period]) == 0 - expression: Store_e_initial - otherwise: Store_retention * shift(Store_e, along=snapshot, offset=1) +Line_transmission_volume_expansion: + expression: sum(Line_s_nom_ext * Line_volume_weight, over=line) ``` ```math -\overleftarrow{e}_{\xi,t,v} = \begin{cases} \rho^{e}_{\xi,t,v} \cdot e_{\xi,\left( t \ominus \mathrm{idle}^{e} \right) \ominus 1,v} & \text{if } \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \neg \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,v} & \text{if } \mathrm{cyc}^{e,y}_{\xi,v} \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t - 1,v} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\mathit{Line\_transmission\_volume\_expansion}_{l,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{len}_{l,k,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_output_arrival` +### `Link_additions` ```yaml -Link_output_arrival: - description: >- - what a link delivers to an output port at a snapshot — its flow delayed - by the port's `delay` within its investment period, times the port's - efficiency at the snapshot the flow arrives; where the port is - `cyclic_delay` the delayed flow wraps from the period's end, and where it - is not the flow still in transit at the period's first snapshots is - lost. A port that does not delay (`delay` - zero) delivers its flow unshifted, cyclic or not - dims: [scenario, snapshot, link_output] - cases: - wrapping: - when: Link_output_cyclic_delay - expression: shift(at(Link_p, by=Link_output_link[link]), along=snapshot, offset=Link_output_delay, edge='wrap', within=snapshot_period[period]) * Link_efficiency - otherwise: shift(at(Link_p, by=Link_output_link[link]), along=snapshot, offset=Link_output_delay, edge=0, within=snapshot_period[period]) * Link_efficiency +Link_additions: + expression: >- + sum(Link_p_nom_ext * Link_first_active, over=link, by=Link_carrier[carrier]) ``` ```math -\overrightarrow{f}_{o,\xi,t} = \begin{cases} f_{\mathrm{Link\_output\_link}(o),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{if } \mathrm{cyc}^{f}_{o} \\ f_{\mathrm{Link\_output\_link}(o),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, o \in \mathcal{O},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_additions}_{i,y} = \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_carrier}(l) = i} F_{l} \cdot \mathrm{new}^{f}_{l,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Process_output_arrival` +### `Link_capex` ```yaml -Process_output_arrival: - description: >- - what a process transfers at a port at a snapshot — its internal power - delayed by the port's `delay` within its investment period, times the - port's rate at the snapshot the transfer arrives; where the port is - `cyclic_delay` the delayed transfer wraps from the period's end, and - where it is not the energy still in transit at the period's first - snapshots is lost. A port that does not - delay (`delay` zero) transfers at once, cyclic or not - dims: [scenario, snapshot, process_output] - cases: - wrapping: - when: Process_output_cyclic_delay - expression: shift(at(Process_p, by=Process_output_process[process]), along=snapshot, offset=Process_output_delay, edge='wrap', within=snapshot_period[period]) * Process_rate - otherwise: shift(at(Process_p, by=Process_output_process[process]), along=snapshot, offset=Process_output_delay, edge=0, within=snapshot_period[period]) * Process_rate +Link_capex: + expression: sum(scenario_weight * Link_p_nom_ext * Link_capital_cost * Link_capital_weight) ``` ```math -\overrightarrow{z}_{r,\xi,t} = \begin{cases} z_{\mathrm{Process\_output\_process}(r),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{if } \mathrm{cyc}^{z}_{r} \\ z_{\mathrm{Process\_output\_process}(r),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, r \in \mathcal{R},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_capex} = \sum_{l \in \mathcal{L},\ \xi \in \Xi} \pi_{\xi} \cdot F_{l} \cdot \mathrm{c}^{\mathrm{cap},f}_{l,\xi} \cdot \mathrm{W}^{f}_{l} ``` -### `GlobalConstraint_energy_weight` +### `Link_commitment_opex` ```yaml -GlobalConstraint_energy_weight: - description: >- - what one unit of power at a snapshot counts for in a row — the - generator weighting times the years of the snapshot's period, where the - row counts the snapshot, and nothing where it does not - dims: [scenario, global_constraint, snapshot] - cases: - counted: - when: GlobalConstraint_counts_snapshot - expression: snapshot_weightings_generators * at(period_weight_years, by=snapshot_period[period]) - otherwise: 0 +Link_commitment_opex: + expression: >- + sum(sum(((Link_status * Link_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) + + sum(sum(Link_start_up * Link_start_up_cost, over=link), over=snapshot) + + sum(sum(Link_shut_down * Link_shut_down_cost, over=link), over=snapshot) ``` ```math -\mathit{w}^{\mathrm{gc}}_{i,\xi,t} = \begin{cases} \mathrm{w}^{\mathrm{gen}}_{t} \cdot \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{in}_{i,\xi,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} u^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{on}}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{up}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{up}}_{l,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{dn}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{dn}}_{l,\xi,t} \qquad \forall\, \xi \in \Xi ``` -### `StorageUnit_last_counted_active` +### `Link_injection` ```yaml -StorageUnit_last_counted_active: - description: >- - one at the last snapshot a row counts where a unit stands, and zero - elsewhere — a unit that retires before the last counted snapshot closes - on its last active level, as PyPSA forward-fills the level over the - counted snapshots (`global_constraints.py:455-458`) - dims: [scenario, global_constraint, snapshot, storage_unit] - cases: - last: - when: >- - GlobalConstraint_counts_snapshot AND StorageUnit_active - AND NOT shift(GlobalConstraint_counts_snapshot AND StorageUnit_active, along=snapshot, offset=-1) - expression: 1 - otherwise: 0 +Link_injection: + expression: >- + -sum(Link_p, over=link, by=Link_bus0[bus]) + + sum(Link_output_arrival, over=link_output, by=Link_output_bus[bus]) ``` ```math -\mathit{last}^{h}_{i,\xi,t,s} = \begin{cases} 1 & \text{if } \mathrm{in}_{i,\xi,t} \wedge \mathrm{on}^{h}_{t,s} \wedge \neg \left( \mathrm{in}_{i,\xi,t + 1} \wedge \mathrm{on}^{h}_{t + 1,s} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\mathit{Link\_injection}_{n,\xi,t} = -\left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `StorageUnit_closing_weight` +### `Link_opex` ```yaml -StorageUnit_closing_weight: - description: >- - what the charge a unit holds at a snapshot counts for in a row as its - closing level — the years of the period at the last snapshot of each - counted period where the unit reopens per period, one at the last - counted snapshot it stands in where it does not, and nothing elsewhere - dims: [scenario, global_constraint, snapshot, storage_unit] - cases: - per_period: - when: StorageUnit_state_of_charge_initial_per_period AND GlobalConstraint_counts_snapshot AND position(snapshot, within=snapshot_period[period]) == -1 - expression: at(period_weight_years, by=snapshot_period[period]) - carried_over: - when: NOT StorageUnit_state_of_charge_initial_per_period - expression: StorageUnit_last_counted_active - otherwise: 0 +Link_opex: + expression: >- + sum(sum(((Link_p * Link_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) + + sum(sum((((Link_p * Link_p) * Link_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) ``` ```math -\mathit{w}^{h}_{i,\xi,t,s} = \begin{cases} \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{i,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ \mathit{last}^{h}_{i,\xi,t,s} & \text{if } \neg \mathrm{reset}_{\xi,s} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\mathit{Link\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot \mathrm{c}^{f}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot f_{l,\xi,t} \cdot \mathrm{c}^{f,(2)}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -### `Store_last_counted_active` +### `Link_output_arrival` ```yaml -Store_last_counted_active: +Link_output_arrival: description: >- - one at the last snapshot a row counts where a store stands, and zero - elsewhere — a store that retires before the last counted snapshot closes - on its last active level, as PyPSA forward-fills the level over the - counted snapshots (`global_constraints.py:507-510`) - dims: [scenario, global_constraint, snapshot, store] + what a link delivers to an output port at a snapshot — its flow delayed + by the port's `delay` within its investment period, times the port's + efficiency at the snapshot the flow arrives; where the port is + `cyclic_delay` the delayed flow wraps from the period's end, and where it + is not the flow still in transit at the period's first snapshots is + lost. A port that does not delay (`delay` + zero) delivers its flow unshifted, cyclic or not + dims: [scenario, snapshot, link_output] cases: - last: - when: >- - GlobalConstraint_counts_snapshot AND Store_active - AND NOT shift(GlobalConstraint_counts_snapshot AND Store_active, along=snapshot, offset=-1) - expression: 1 - otherwise: 0 + wrapping: + when: Link_output_cyclic_delay + expression: shift(at(Link_p, by=Link_output_link[link]), along=snapshot, offset=Link_output_delay, edge='wrap', within=snapshot_period[period]) * Link_efficiency + otherwise: shift(at(Link_p, by=Link_output_link[link]), along=snapshot, offset=Link_output_delay, edge=0, within=snapshot_period[period]) * Link_efficiency ``` ```math -\mathit{last}^{e}_{i,\xi,t,v} = \begin{cases} 1 & \text{if } \mathrm{in}_{i,\xi,t} \wedge \mathrm{on}^{e}_{t,v} \wedge \neg \left( \mathrm{in}_{i,\xi,t + 1} \wedge \mathrm{on}^{e}_{t + 1,v} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\overrightarrow{f}_{o,\xi,t} = \begin{cases} f_{\mathrm{Link\_output\_link}(o),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{if } \mathrm{cyc}^{f}_{o} \\ f_{\mathrm{Link\_output\_link}(o),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, o \in \mathcal{O},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Store_closing_weight` +### `Link_p_nom_committed` ```yaml -Store_closing_weight: +Link_p_nom_committed: description: >- - what the energy a store holds at a snapshot counts for in a row as its - closing level — the years of the period at the last snapshot of each - counted period where the store reopens per period, one at the last - counted snapshot it stands in where it does not, and nothing elsewhere - dims: [scenario, global_constraint, snapshot, store] + the build a committed link's ramp rows are taken against — one module + where the build is extendable and modular, the given build otherwise + dims: [scenario, link] cases: - per_period: - when: Store_e_initial_per_period AND GlobalConstraint_counts_snapshot AND position(snapshot, within=snapshot_period[period]) == -1 - expression: at(period_weight_years, by=snapshot_period[period]) - carried_over: - when: NOT Store_e_initial_per_period - expression: Store_last_counted_active - otherwise: 0 + modular_build: { when: Link_p_nom_extendable AND Link_p_nom_mod > 0, expression: Link_p_nom_mod } + otherwise: Link_p_nom ``` ```math -\mathit{w}^{e}_{i,\xi,t,v} = \begin{cases} \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{i,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ \mathit{last}^{e}_{i,\xi,t,v} & \text{if } \neg \mathrm{reset}^{e}_{\xi,v} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} \mathrm{f}^{\mathrm{mod}}_{l} & \text{if } \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Generator_primary_energy` +### `Link_p_nom_effective` ```yaml -Generator_primary_energy: - expression: >- - sum(sum((Generator_p * GlobalConstraint_energy_weight) * Generator_primary_energy_weight, over=snapshot), over=generator) +Link_p_nom_effective: + description: the build a link's limits are taken against — the chosen one where it is extendable, the given one otherwise + dims: [scenario, link] + cases: + extendable: { when: Link_p_nom_extendable, expression: Link_p_nom_ext } + otherwise: Link_p_nom ``` ```math -\mathit{Generator\_primary\_energy}_{i,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{i,\xi,t} \cdot \mathrm{a}_{g,i,\xi,t} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} F_{l} & \text{if } \mathrm{ext}^{f}_{l} \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `StorageUnit_primary_energy` +### `Link_previous_p` ```yaml -StorageUnit_primary_energy: - expression: >- - -sum(sum((StorageUnit_state_of_charge * StorageUnit_closing_weight) * StorageUnit_primary_energy_weight, over=snapshot), over=storage_unit) +Link_previous_p: + description: >- + the flow a link carries into a snapshot — at the first, the + `p_init` it brought in where it came in running and nothing where it + came in off; the previous snapshot's after that + dims: [scenario, snapshot, link] + cases: + opening: { when: "position(snapshot) == 0", expression: Link_status_initial * Link_p_init } + otherwise: shift(Link_p, along=snapshot, offset=1) ``` ```math -\mathit{StorageUnit\_primary\_energy}_{i,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{i,\xi,t,s} \cdot \mathrm{a}^{h}_{i,\xi,s} \right) \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\overleftarrow{f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} \cdot \mathrm{f}^{0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ f_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Store_primary_energy` +### `Link_previous_status` ```yaml -Store_primary_energy: - expression: >- - -sum(sum((Store_e * Store_closing_weight) * Store_primary_energy_weight, over=snapshot), over=store) +Link_previous_status: + description: >- + the commitment state a link carries into a snapshot — off at the + first snapshot it stands in past the first of the horizon, as PyPSA + reads a status it did not build (`constraints.py:298`), and the state + carried over otherwise + dims: [scenario, snapshot, link] + cases: + opening_late: { when: "position(snapshot) > 0 AND NOT shift(Link_active, along=snapshot, offset=1)", expression: 0 } + otherwise: Link_status_carried_over ``` ```math -\mathit{Store\_primary\_energy}_{i,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{i,\xi,t,v} \cdot \mathrm{a}^{e}_{i,\xi,v} \right) \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\overleftarrow{u}^{f}_{l,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{f}_{l,t - 1} \\ \overleftarrow{u}^{\circ f}_{l,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `primary_energy` +### `Link_ramp_down_allowance` ```yaml -primary_energy: - dims: [scenario, global_constraint] - expression: Generator_primary_energy + StorageUnit_primary_energy + Store_primary_energy +Link_ramp_down_allowance: description: >- - what a `primary_energy` row totals — weighted generator energy over the - snapshots it counts, less the charge left in weighted storage at the - close; the initial charge it is compared against is folded into the - row's constant + how far a link may lower flow between two snapshots — its ramp + limit of the build while it stays on, plus its shut-down ramp in the + snapshot it turns off + dims: [scenario, snapshot, link] + cases: + committed: + when: Link_committable + expression: >- + Link_ramp_down_rate * Link_p_nom_committed * Link_status + + Link_shut_down_rate * Link_p_nom_committed + * (Link_previous_status - Link_status) + otherwise: Link_ramp_down_rate * Link_p_nom_effective ``` ```math -\mathit{primary\_energy}_{i,\xi} = \mathit{Generator\_primary\_energy}_{i,\xi} + \mathit{StorageUnit\_primary\_energy}_{i,\xi} + \mathit{Store\_primary\_energy}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\Delta^{f,-}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot u^{f}_{l,\xi,t} + \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_operational_limit` +### `Link_ramp_down_rate` ```yaml -Generator_operational_limit: - expression: >- - sum(sum((Generator_p * GlobalConstraint_energy_weight) * Generator_operational_limit_weight, over=snapshot), over=generator) +Link_ramp_down_rate: + description: >- + the ramp limit a link's down row reads — PyPSA's `ramp_limit_down`, or + the full build where it has none, since a shut-down ramp alone builds the row + dims: [scenario, snapshot, link] + cases: + given: { when: Link_ramp_limit_down, expression: Link_ramp_limit_down } + otherwise: 1 ``` ```math -\mathit{Generator\_operational\_limit}_{i,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{i,\xi,t} \cdot \mathrm{b}_{g,i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\widetilde{\mathrm{rd}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{rd}^{f}_{l,\xi,t} & \text{if } \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `StorageUnit_operational_limit` +### `Link_ramp_up_allowance` ```yaml -StorageUnit_operational_limit: - expression: >- - -sum(sum((StorageUnit_state_of_charge * StorageUnit_closing_weight) * StorageUnit_operational_limit_weight, over=snapshot), over=storage_unit) +Link_ramp_up_allowance: + description: >- + how far a link may raise flow between two snapshots — its ramp + limit of the build while it stays on, plus its start-up ramp in the + snapshot it turns on + dims: [scenario, snapshot, link] + cases: + committed: + when: Link_committable + expression: >- + Link_ramp_up_rate * Link_p_nom_committed * Link_previous_status + + Link_start_up_rate * Link_p_nom_committed + * (Link_status - Link_previous_status) + otherwise: Link_ramp_up_rate * Link_p_nom_effective ``` ```math -\mathit{StorageUnit\_operational\_limit}_{i,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{i,\xi,t,s} \cdot \mathrm{b}^{h}_{i,\xi,s} \right) \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\Delta^{f,+}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} + \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Store_operational_limit` +### `Link_ramp_up_rate` ```yaml -Store_operational_limit: - expression: >- - -sum(sum((Store_e * Store_closing_weight) * Store_operational_limit_weight, over=snapshot), over=store) +Link_ramp_up_rate: + description: >- + the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the + full build where it has none, since a start-up ramp alone builds the row + dims: [scenario, snapshot, link] + cases: + given: { when: Link_ramp_limit_up, expression: Link_ramp_limit_up } + otherwise: 1 ``` ```math -\mathit{Store\_operational\_limit}_{i,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{i,\xi,t,v} \cdot \mathrm{b}^{e}_{i,\xi,v} \right) \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\widetilde{\mathrm{ru}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{ru}^{f}_{l,\xi,t} & \text{if } \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `operational_limit` +### `Link_shut_down_rate` ```yaml -operational_limit: - dims: [scenario, global_constraint] - expression: >- - Generator_operational_limit - + StorageUnit_operational_limit - + Store_operational_limit +Link_shut_down_rate: description: >- - what an `operational_limit` row totals — the weighted energy its - generators deliver over the snapshots it counts, plus what its - non-cyclic storage draws down; the initial charge it draws from is - folded into the row's constant + the shut-down ramp a link's down row reads — PyPSA's + `ramp_limit_shut_down`, or the full build where it has none + dims: [scenario, link] + cases: + given: { when: Link_ramp_limit_shut_down, expression: Link_ramp_limit_shut_down } + otherwise: 1 ``` ```math -\mathit{operational\_limit}_{i,\xi} = \mathit{Generator\_operational\_limit}_{i,\xi} + \mathit{StorageUnit\_operational\_limit}_{i,\xi} + \mathit{Store\_operational\_limit}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} = \begin{cases} \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} & \text{if } \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Line_transmission_volume_expansion` +### `Link_start_up_rate` ```yaml -Line_transmission_volume_expansion: - expression: sum(Line_s_nom_ext * Line_volume_weight, over=line) +Link_start_up_rate: + description: >- + the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, + or the full build where it has none + dims: [scenario, link] + cases: + given: { when: Link_ramp_limit_start_up, expression: Link_ramp_limit_start_up } + otherwise: 1 ``` ```math -\mathit{Line\_transmission\_volume\_expansion}_{i,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{len}_{i,k,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} = \begin{cases} \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} & \text{if } \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_transmission_volume_expansion` +### `Link_status_carried_over` ```yaml -Link_transmission_volume_expansion: - expression: sum(Link_p_nom_ext * Link_volume_weight, over=link) +Link_status_carried_over: + description: >- + the state a link carries over into a snapshot — the state it brought + into the horizon at the first, the previous snapshot's after that + dims: [scenario, snapshot, link] + cases: + opening: { when: "position(snapshot) == 0", expression: Link_status_initial } + otherwise: shift(Link_status, along=snapshot, offset=1) ``` ```math -\mathit{Link\_transmission\_volume\_expansion}_{i,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{len}^{f}_{i,l,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\overleftarrow{u}^{\circ f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{f}_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `transmission_volume_expansion` +### `Link_tech_capacity_expansion` ```yaml -transmission_volume_expansion: - dims: [scenario, global_constraint] - expression: Line_transmission_volume_expansion + Link_transmission_volume_expansion - description: >- - what a `transmission_volume_expansion_limit` row totals — length times - the chosen build of the row's branches +Link_tech_capacity_expansion: + expression: sum(Link_p_nom_ext * Link_tech_capacity_weight, over=link) ``` ```math -\mathit{transmission\_volume\_expansion}_{i,\xi} = \mathit{Line\_transmission\_volume\_expansion}_{i,\xi} + \mathit{Link\_transmission\_volume\_expansion}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\mathit{Link\_tech\_capacity\_expansion}_{l} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{m}^{f}_{l,l} \qquad \forall\, l \in \mathcal{L} ``` -### `Line_transmission_expansion_cost` +### `Link_transmission_expansion_cost` ```yaml -Line_transmission_expansion_cost: - expression: sum(Line_s_nom_ext * Line_expansion_cost_weight, over=line) +Link_transmission_expansion_cost: + expression: sum(Link_p_nom_ext * Link_expansion_cost_weight, over=link) ``` ```math -\mathit{Line\_transmission\_expansion\_cost}_{i,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{cc}_{i,k,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\mathit{Link\_transmission\_expansion\_cost}_{l,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{cc}^{f}_{l,l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_transmission_expansion_cost` +### `Link_transmission_volume_expansion` ```yaml -Link_transmission_expansion_cost: - expression: sum(Link_p_nom_ext * Link_expansion_cost_weight, over=link) +Link_transmission_volume_expansion: + expression: sum(Link_p_nom_ext * Link_volume_weight, over=link) ``` ```math -\mathit{Link\_transmission\_expansion\_cost}_{i,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{cc}^{f}_{i,l,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\mathit{Link\_transmission\_volume\_expansion}_{l,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{len}^{f}_{l,l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `transmission_expansion_cost` +### `Load_demand` ```yaml -transmission_expansion_cost: - dims: [scenario, global_constraint] - expression: Line_transmission_expansion_cost + Link_transmission_expansion_cost +Load_demand: description: >- - what a `transmission_expansion_cost_limit` row totals — capital cost - times the chosen build of the row's branches + what a load draws from its bus's balance — its demand times its sign + where it is active, nothing where it is not, since PyPSA drops an + inactive load from the balance (`constraints.py:1513-1514`) + dims: [scenario, snapshot, load] + cases: + active: { when: Load_active, expression: Load_sign * Load_p_set } + otherwise: 0 ``` ```math -\mathit{transmission\_expansion\_cost}_{i,\xi} = \mathit{Line\_transmission\_expansion\_cost}_{i,\xi} + \mathit{Link\_transmission\_expansion\_cost}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi +\check{\mathrm{load}}_{d,\xi,t} = \begin{cases} \mathrm{sgn}^{\mathrm{load}}_{d} \cdot \mathrm{load}_{d,\xi,t} & \text{if } \mathrm{on}^{\mathrm{load}}_{d} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, d \in \mathcal{D},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_tech_capacity_expansion` +### `Load_injection` ```yaml -Generator_tech_capacity_expansion: - expression: sum(Generator_p_nom_ext * Generator_tech_capacity_weight, over=generator) +Load_injection: sum(Load_demand, over=load, by=Load_bus[bus]) ``` ```math -\mathit{Generator\_tech\_capacity\_expansion}_{i} = \sum_{g \in \mathcal{G}} P_{g} \cdot \mathrm{m}_{g,i} \qquad \forall\, i \in \mathcal{I} +\mathrm{Load\_injection}_{n,\xi,t} = \sum_{d \in \mathcal{D} \,:\, \mathrm{Load\_bus}(d) = n} \check{\mathrm{load}}_{d,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Line_tech_capacity_expansion` +### `Outage_s` ```yaml -Line_tech_capacity_expansion: - expression: sum(Line_s_nom_ext * Line_tech_capacity_weight, over=line) +Outage_s: + description: >- + the flow an outage takes off its branch — the outaged line's or + transformer's flow before it goes out + dims: [scenario, snapshot, outage] + cases: + line: { when: Outage_line, expression: "at(Line_s_monitored, by=Outage_line[line])" } + otherwise: at(Transformer_s_monitored, by=Outage_transformer[transformer]) ``` ```math -\mathit{Line\_tech\_capacity\_expansion}_{i} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{m}^{l}_{i,k} \qquad \forall\, i \in \mathcal{I} +\hat{s}_{\kappa,\xi,t} = \begin{cases} \check{s}_{\mathrm{Outage\_line}(\kappa),\xi,t} & \text{if } \mathrm{Outage\_line}(\kappa) \text{ is defined} \\ \check{\sigma}_{\xi,t,\mathrm{Outage\_transformer}(\kappa)} & \text{otherwise} \end{cases} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link_tech_capacity_expansion` +### `Process_additions` ```yaml -Link_tech_capacity_expansion: - expression: sum(Link_p_nom_ext * Link_tech_capacity_weight, over=link) +Process_additions: + expression: >- + sum(Process_p_nom_ext * Process_first_active, over=process, by=Process_carrier[carrier]) ``` ```math -\mathit{Link\_tech\_capacity\_expansion}_{i} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{m}^{f}_{i,l} \qquad \forall\, i \in \mathcal{I} +\mathit{Process\_additions}_{i,y} = \sum_{j \in \mathcal{J} \,:\, \mathrm{Process\_carrier}(j) = i} Z_{j} \cdot \mathrm{new}^{z}_{y,j} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Process_tech_capacity_expansion` +### `Process_capex` ```yaml -Process_tech_capacity_expansion: - expression: sum(Process_p_nom_ext * Process_tech_capacity_weight, over=process) +Process_capex: + expression: sum(scenario_weight * Process_p_nom_ext * Process_capital_cost * Process_capital_weight) ``` ```math -\mathit{Process\_tech\_capacity\_expansion}_{i} = \sum_{j \in \mathcal{J}} Z_{j} \cdot \mathrm{m}^{z}_{i,j} \qquad \forall\, i \in \mathcal{I} +\mathit{Process\_capex} = \sum_{j \in \mathcal{J},\ \xi \in \Xi} \pi_{\xi} \cdot Z_{j} \cdot \mathrm{c}^{\mathrm{cap},z}_{j,\xi} \cdot \mathrm{W}^{z}_{j} ``` -### `StorageUnit_tech_capacity_expansion` +### `Process_commitment_opex` ```yaml -StorageUnit_tech_capacity_expansion: - expression: sum(StorageUnit_p_nom_ext * StorageUnit_tech_capacity_weight, over=storage_unit) +Process_commitment_opex: + expression: >- + sum(sum(((Process_status * Process_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) + + sum(sum(Process_start_up * Process_start_up_cost, over=process), over=snapshot) + + sum(sum(Process_shut_down * Process_shut_down_cost, over=process), over=snapshot) ``` ```math -\mathit{StorageUnit\_tech\_capacity\_expansion}_{i} = \sum_{s \in \mathcal{S}} H_{s} \cdot \mathrm{m}^{h}_{i,s} \qquad \forall\, i \in \mathcal{I} +\mathit{Process\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} u^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{on}}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{up}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{up}}_{j,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{dn}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{dn}}_{j,\xi,t} \qquad \forall\, \xi \in \Xi ``` -### `Store_tech_capacity_expansion` +### `Process_injection` ```yaml -Store_tech_capacity_expansion: - expression: sum(Store_e_nom_ext * Store_tech_capacity_weight, over=store) +Process_injection: + expression: >- + sum(Process_output_arrival, over=process_output, by=Process_output_bus[bus]) ``` ```math -\mathit{Store\_tech\_capacity\_expansion}_{i} = \sum_{v \in \mathcal{V}} E_{v} \cdot \mathrm{m}^{e}_{i,v} \qquad \forall\, i \in \mathcal{I} +\mathit{Process\_injection}_{n,\xi,t} = \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `tech_capacity_expansion` +### `Process_opex` ```yaml -tech_capacity_expansion: - dims: [global_constraint] +Process_opex: expression: >- - Generator_tech_capacity_expansion - + Line_tech_capacity_expansion - + Link_tech_capacity_expansion - + Process_tech_capacity_expansion - + StorageUnit_tech_capacity_expansion - + Store_tech_capacity_expansion - description: >- - what a `tech_capacity_expansion_limit` row totals — the chosen build of - the row's carrier-and-bus set + sum(sum(((Process_p * Process_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) + + sum(sum((((Process_p * Process_p) * Process_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) ``` ```math -\mathit{tech\_capacity\_expansion}_{i} = \mathit{Generator\_tech\_capacity\_expansion}_{i} + \mathit{Line\_tech\_capacity\_expansion}_{i} + \mathit{Link\_tech\_capacity\_expansion}_{i} + \mathit{Process\_tech\_capacity\_expansion}_{i} + \mathit{StorageUnit\_tech\_capacity\_expansion}_{i} + \mathit{Store\_tech\_capacity\_expansion}_{i} \qquad \forall\, i \in \mathcal{I} +\mathit{Process\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot \mathrm{c}^{z}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot z_{j,\xi,t} \cdot \mathrm{c}^{z,(2)}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -### `Generator_opex` +### `Process_output_arrival` ```yaml -Generator_opex: - expression: >- - sum(sum(((Generator_p * Generator_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) - + sum(sum((((Generator_p * Generator_p) * Generator_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) +Process_output_arrival: + description: >- + what a process transfers at a port at a snapshot — its internal power + delayed by the port's `delay` within its investment period, times the + port's rate at the snapshot the transfer arrives; where the port is + `cyclic_delay` the delayed transfer wraps from the period's end, and + where it is not the energy still in transit at the period's first + snapshots is lost. A port that does not + delay (`delay` zero) transfers at once, cyclic or not + dims: [scenario, snapshot, process_output] + cases: + wrapping: + when: Process_output_cyclic_delay + expression: shift(at(Process_p, by=Process_output_process[process]), along=snapshot, offset=Process_output_delay, edge='wrap', within=snapshot_period[period]) * Process_rate + otherwise: shift(at(Process_p, by=Process_output_process[process]), along=snapshot, offset=Process_output_delay, edge=0, within=snapshot_period[period]) * Process_rate ``` ```math -\mathit{Generator\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot \mathrm{c}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot p_{g,\xi,t} \cdot \mathrm{c}^{(2)}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\overrightarrow{z}_{r,\xi,t} = \begin{cases} z_{\mathrm{Process\_output\_process}(r),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{if } \mathrm{cyc}^{z}_{r} \\ z_{\mathrm{Process\_output\_process}(r),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, r \in \mathcal{R},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_commitment_opex` +### `Process_p_nom_committed` ```yaml -Generator_commitment_opex: - expression: >- - sum(sum(((Generator_status * Generator_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=generator), over=snapshot) - + sum(sum(Generator_start_up * Generator_start_up_cost, over=generator), over=snapshot) - + sum(sum(Generator_shut_down * Generator_shut_down_cost, over=generator), over=snapshot) +Process_p_nom_committed: + description: >- + the build a committed process's ramp rows are taken against — one module + where the build is extendable and modular, the given build otherwise + dims: [scenario, process] + cases: + modular_build: { when: Process_p_nom_extendable AND Process_p_nom_mod > 0, expression: Process_p_nom_mod } + otherwise: Process_p_nom ``` ```math -\mathit{Generator\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} u_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{on}}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{up}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{up}}_{g,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{dn}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{dn}}_{g,\xi,t} \qquad \forall\, \xi \in \Xi +\widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} \mathrm{z}^{\mathrm{mod}}_{j} & \text{if } \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -### `Link_opex` +### `Process_p_nom_effective` ```yaml -Link_opex: - expression: >- - sum(sum(((Link_p * Link_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) - + sum(sum((((Link_p * Link_p) * Link_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) +Process_p_nom_effective: + description: the build a process's limits are taken against — the chosen one where it is extendable, the given one otherwise + dims: [scenario, process] + cases: + extendable: { when: Process_p_nom_extendable, expression: Process_p_nom_ext } + otherwise: Process_p_nom ``` ```math -\mathit{Link\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot \mathrm{c}^{f}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot f_{l,\xi,t} \cdot \mathrm{c}^{f,(2)}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} Z_{j} & \text{if } \mathrm{ext}^{z}_{j} \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -### `Link_commitment_opex` +### `Process_previous_p` ```yaml -Link_commitment_opex: - expression: >- - sum(sum(((Link_status * Link_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=link), over=snapshot) - + sum(sum(Link_start_up * Link_start_up_cost, over=link), over=snapshot) - + sum(sum(Link_shut_down * Link_shut_down_cost, over=link), over=snapshot) +Process_previous_p: + description: >- + the internal power a process carries into a snapshot — at the first, the + `p_init` it brought in where it came in running and nothing where it + came in off; the previous snapshot's after that + dims: [scenario, snapshot, process] + cases: + opening: { when: "position(snapshot) == 0", expression: Process_status_initial * Process_p_init } + otherwise: shift(Process_p, along=snapshot, offset=1) ``` ```math -\mathit{Link\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} u^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{on}}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{up}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{up}}_{l,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{dn}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{dn}}_{l,\xi,t} \qquad \forall\, \xi \in \Xi +\overleftarrow{z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} \cdot \mathrm{z}^{0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ z_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_opex` +### `Process_previous_status` ```yaml -Process_opex: - expression: >- - sum(sum(((Process_p * Process_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) - + sum(sum((((Process_p * Process_p) * Process_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) +Process_previous_status: + description: >- + the commitment state a process carries into a snapshot — off at the + first snapshot it stands in past the first of the horizon, as PyPSA + reads a status it did not build (`constraints.py:298`), and the state + carried over otherwise + dims: [scenario, snapshot, process] + cases: + opening_late: { when: "position(snapshot) > 0 AND NOT shift(Process_active, along=snapshot, offset=1)", expression: 0 } + otherwise: Process_status_carried_over ``` ```math -\mathit{Process\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot \mathrm{c}^{z}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot z_{j,\xi,t} \cdot \mathrm{c}^{z,(2)}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\overleftarrow{u}^{z}_{j,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{z}_{j,t - 1} \\ \overleftarrow{u}^{\circ z}_{j,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Process_commitment_opex` +### `Process_ramp_down_allowance` ```yaml -Process_commitment_opex: - expression: >- - sum(sum(((Process_status * Process_stand_by_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=process), over=snapshot) - + sum(sum(Process_start_up * Process_start_up_cost, over=process), over=snapshot) - + sum(sum(Process_shut_down * Process_shut_down_cost, over=process), over=snapshot) +Process_ramp_down_allowance: + description: >- + how far a process may lower internal power between two snapshots — its ramp + limit of the build while it stays on, plus its shut-down ramp in the + snapshot it turns off + dims: [scenario, snapshot, process] + cases: + committed: + when: Process_committable + expression: >- + Process_ramp_down_rate * Process_p_nom_committed * Process_status + + Process_shut_down_rate * Process_p_nom_committed + * (Process_previous_status - Process_status) + otherwise: Process_ramp_down_rate * Process_p_nom_effective ``` ```math -\mathit{Process\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} u^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{on}}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{up}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{up}}_{j,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{dn}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{dn}}_{j,\xi,t} \qquad \forall\, \xi \in \Xi +\Delta^{z,-}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot u^{z}_{j,\xi,t} + \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `StorageUnit_opex` +### `Process_ramp_down_rate` ```yaml -StorageUnit_opex: - expression: >- - sum(sum(((StorageUnit_p_dispatch * StorageUnit_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) - + sum(sum((((StorageUnit_p_dispatch * StorageUnit_p_dispatch) * StorageUnit_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) - + sum(sum(((StorageUnit_state_of_charge * StorageUnit_marginal_cost_storage) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) - + sum(sum(((StorageUnit_spill * StorageUnit_spill_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) +Process_ramp_down_rate: + description: >- + the ramp limit a process's down row reads — PyPSA's `ramp_limit_down`, or + the full build where it has none, since a shut-down ramp alone builds the row + dims: [scenario, snapshot, process] + cases: + given: { when: Process_ramp_limit_down, expression: Process_ramp_limit_down } + otherwise: 1 ``` ```math -\mathit{StorageUnit\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h,(2)}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{soc}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{soc}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{spill}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{spill}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\widetilde{\mathrm{rd}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{rd}^{z}_{j,\xi,t} & \text{if } \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Store_opex` +### `Process_ramp_up_allowance` ```yaml -Store_opex: - expression: >- - sum(sum(((Store_p * Store_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) - + sum(sum((((Store_p * Store_p) * Store_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) - + sum(sum(((Store_e * Store_marginal_cost_storage) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) +Process_ramp_up_allowance: + description: >- + how far a process may raise internal power between two snapshots — its ramp + limit of the build while it stays on, plus its start-up ramp in the + snapshot it turns on + dims: [scenario, snapshot, process] + cases: + committed: + when: Process_committable + expression: >- + Process_ramp_up_rate * Process_p_nom_committed * Process_previous_status + + Process_start_up_rate * Process_p_nom_committed + * (Process_status - Process_previous_status) + otherwise: Process_ramp_up_rate * Process_p_nom_effective ``` ```math -\mathit{Store\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot \mathrm{c}^{q}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot q_{\xi,t,v} \cdot \mathrm{c}^{q,(2)}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} e_{\xi,t,v} \cdot \mathrm{c}^{e}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\Delta^{z,+}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} + \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `scenario_opex` +### `Process_ramp_up_rate` ```yaml -scenario_opex: - dims: [scenario] - expression: >- - Generator_opex - + Generator_commitment_opex - + Link_opex - + Link_commitment_opex - + Process_opex - + Process_commitment_opex - + StorageUnit_opex - + Store_opex +Process_ramp_up_rate: description: >- - what a future costs to run — every operating term, weighted by the - snapshot's hours and its period, before the scenario's own weight; a - start and a stop cost what they cost, unweighted, as PyPSA adds them - (`optimize.py:415-432`) + the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the + full build where it has none, since a start-up ramp alone builds the row + dims: [scenario, snapshot, process] + cases: + given: { when: Process_ramp_limit_up, expression: Process_ramp_limit_up } + otherwise: 1 ``` ```math -\mathit{scenario\_opex}_{\xi} = \mathit{Generator\_opex}_{\xi} + \mathit{Generator\_commitment\_opex}_{\xi} + \mathit{Link\_opex}_{\xi} + \mathit{Link\_commitment\_opex}_{\xi} + \mathit{Process\_opex}_{\xi} + \mathit{Process\_commitment\_opex}_{\xi} + \mathit{StorageUnit\_opex}_{\xi} + \mathit{Store\_opex}_{\xi} \qquad \forall\, \xi \in \Xi +\widetilde{\mathrm{ru}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{ru}^{z}_{j,\xi,t} & \text{if } \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_capex` +### `Process_shut_down_rate` ```yaml -Generator_capex: - expression: sum(scenario_weight * Generator_p_nom_ext * Generator_capital_cost * Generator_capital_weight) +Process_shut_down_rate: + description: >- + the shut-down ramp a process's down row reads — PyPSA's + `ramp_limit_shut_down`, or the full build where it has none + dims: [scenario, process] + cases: + given: { when: Process_ramp_limit_shut_down, expression: Process_ramp_limit_shut_down } + otherwise: 1 ``` ```math -\mathit{Generator\_capex} = \sum_{g \in \mathcal{G},\ \xi \in \Xi} \pi_{\xi} \cdot P_{g} \cdot \mathrm{c}^{\mathrm{cap}}_{g,\xi} \cdot \mathrm{W}_{g} +\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} = \begin{cases} \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} & \text{if } \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -### `Link_capex` +### `Process_start_up_rate` ```yaml -Link_capex: - expression: sum(scenario_weight * Link_p_nom_ext * Link_capital_cost * Link_capital_weight) +Process_start_up_rate: + description: >- + the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, + or the full build where it has none + dims: [scenario, process] + cases: + given: { when: Process_ramp_limit_start_up, expression: Process_ramp_limit_start_up } + otherwise: 1 ``` ```math -\mathit{Link\_capex} = \sum_{l \in \mathcal{L},\ \xi \in \Xi} \pi_{\xi} \cdot F_{l} \cdot \mathrm{c}^{\mathrm{cap},f}_{l,\xi} \cdot \mathrm{W}^{f}_{l} +\widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} = \begin{cases} \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} & \text{if } \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -### `StorageUnit_capex` +### `Process_status_carried_over` ```yaml -StorageUnit_capex: - expression: sum(scenario_weight * StorageUnit_p_nom_ext * StorageUnit_capital_cost * StorageUnit_capital_weight) +Process_status_carried_over: + description: >- + the state a process carries over into a snapshot — the state it brought + into the horizon at the first, the previous snapshot's after that + dims: [scenario, snapshot, process] + cases: + opening: { when: "position(snapshot) == 0", expression: Process_status_initial } + otherwise: shift(Process_status, along=snapshot, offset=1) ``` ```math -\mathit{StorageUnit\_capex} = \sum_{\xi \in \Xi,\ s \in \mathcal{S}} \pi_{\xi} \cdot H_{s} \cdot \mathrm{c}^{\mathrm{cap},h}_{\xi,s} \cdot \mathrm{W}^{h}_{s} +\overleftarrow{u}^{\circ z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{z}_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Store_capex` +### `Process_tech_capacity_expansion` ```yaml -Store_capex: - expression: sum(scenario_weight * Store_e_nom_ext * Store_capital_cost * Store_capital_weight) +Process_tech_capacity_expansion: + expression: sum(Process_p_nom_ext * Process_tech_capacity_weight, over=process) ``` ```math -\mathit{Store\_capex} = \sum_{\xi \in \Xi,\ v \in \mathcal{V}} \pi_{\xi} \cdot E_{v} \cdot \mathrm{c}^{\mathrm{cap},e}_{\xi,v} \cdot \mathrm{W}^{e}_{v} +\mathit{Process\_tech\_capacity\_expansion}_{l} = \sum_{j \in \mathcal{J}} Z_{j} \cdot \mathrm{m}^{z}_{l,j} \qquad \forall\, l \in \mathcal{L} ``` -### `Line_capex` +### `StorageUnit_additions` ```yaml -Line_capex: - expression: sum(scenario_weight * Line_s_nom_ext * Line_capital_cost * Line_capital_weight) +StorageUnit_additions: + expression: >- + sum(StorageUnit_p_nom_ext * StorageUnit_first_active, over=storage_unit, by=StorageUnit_carrier[carrier]) ``` ```math -\mathit{Line\_capex} = \sum_{k \in \mathcal{K},\ \xi \in \Xi} \pi_{\xi} \cdot S_{k} \cdot \mathrm{c}^{\mathrm{cap},s}_{k,\xi} \cdot \mathrm{W}^{s}_{k} +\mathit{StorageUnit\_additions}_{i,y} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_carrier}(s) = i} H_{s} \cdot \mathrm{new}^{h}_{y,s} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Process_capex` +### `StorageUnit_capex` ```yaml -Process_capex: - expression: sum(scenario_weight * Process_p_nom_ext * Process_capital_cost * Process_capital_weight) +StorageUnit_capex: + expression: sum(scenario_weight * StorageUnit_p_nom_ext * StorageUnit_capital_cost * StorageUnit_capital_weight) ``` ```math -\mathit{Process\_capex} = \sum_{j \in \mathcal{J},\ \xi \in \Xi} \pi_{\xi} \cdot Z_{j} \cdot \mathrm{c}^{\mathrm{cap},z}_{j,\xi} \cdot \mathrm{W}^{z}_{j} +\mathit{StorageUnit\_capex} = \sum_{\xi \in \Xi,\ s \in \mathcal{S}} \pi_{\xi} \cdot H_{s} \cdot \mathrm{c}^{\mathrm{cap},h}_{\xi,s} \cdot \mathrm{W}^{h}_{s} ``` -### `Transformer_capex` +### `StorageUnit_charge_carried_in` ```yaml -Transformer_capex: - expression: sum(scenario_weight * Transformer_s_nom_ext * Transformer_capital_cost * Transformer_capital_weight) +StorageUnit_charge_carried_in: + description: >- + the charge a unit opens a snapshot with — at the first snapshot it + stands in, its last such snapshot's less standing loss where it is + cyclic and the given initial charge, which no standing loss has touched + yet, where it is not; the previous snapshot's less standing loss + otherwise. A unit built in a later period opens in that period, and a + cyclic one that retires closes on its own last snapshot. Per period, the + same holds with each investment period as the horizon + dims: [scenario, snapshot, storage_unit] + cases: + cyclic: + when: >- + StorageUnit_cyclic_state_of_charge AND NOT StorageUnit_cyclic_state_of_charge_per_period + AND NOT StorageUnit_state_of_charge_initial_per_period + AND (position(snapshot) == 0 OR StorageUnit_opens_late) + expression: >- + StorageUnit_retention + * shift(shift(StorageUnit_state_of_charge, along=snapshot, offset=1, edge='wrap'), along=snapshot, offset=StorageUnit_inactive_snapshots, edge='wrap') + opening: + when: >- + NOT StorageUnit_cyclic_state_of_charge AND NOT StorageUnit_cyclic_state_of_charge_per_period + AND NOT StorageUnit_state_of_charge_initial_per_period + AND (position(snapshot) == 0 OR StorageUnit_opens_late) + expression: StorageUnit_state_of_charge_initial + period_cyclic: + when: StorageUnit_cyclic_state_of_charge_per_period + expression: >- + StorageUnit_retention + * shift(StorageUnit_state_of_charge, along=snapshot, offset=1, edge='wrap', within=snapshot_period[period]) + period_opening: + when: >- + StorageUnit_state_of_charge_initial_per_period AND NOT StorageUnit_cyclic_state_of_charge_per_period + AND position(snapshot, within=snapshot_period[period]) == 0 + expression: StorageUnit_state_of_charge_initial + otherwise: StorageUnit_retention * shift(StorageUnit_state_of_charge, along=snapshot, offset=1) ``` ```math -\mathit{Transformer\_capex} = \sum_{\xi \in \Xi,\ m \in \mathcal{M}} \pi_{\xi} \cdot \Sigma_{m} \cdot \mathrm{c}^{\mathrm{cap},\sigma}_{\xi,m} \cdot \mathrm{W}^{\sigma}_{m} +\overleftarrow{\mathit{soc}}_{\xi,t,s} = \begin{cases} \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,\left( t \ominus \mathrm{idle} \right) \ominus 1,s} & \text{if } \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \neg \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,s} & \text{if } \mathrm{cyc}^{y}_{\xi,s} \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \mathrm{reset}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t - 1,s} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` -### `risk_weighted_opex` +### `StorageUnit_closing_weight` ```yaml -risk_weighted_opex: - expression: (1 - CVaR_omega) * sum(scenario_weight * scenario_opex, over=scenario) + CVaR_omega * CVaR +StorageUnit_closing_weight: + description: >- + what the charge a unit holds at a snapshot counts for in a row as its + closing level — the years of the period at the last snapshot of each + counted period where the unit reopens per period, one at the last + counted snapshot it stands in where it does not, and nothing elsewhere + dims: [scenario, global_constraint, snapshot, storage_unit] + cases: + per_period: + when: StorageUnit_state_of_charge_initial_per_period AND GlobalConstraint_counts_snapshot AND position(snapshot, within=snapshot_period[period]) == -1 + expression: at(period_weight_years, by=snapshot_period[period]) + carried_over: + when: NOT StorageUnit_state_of_charge_initial_per_period + expression: StorageUnit_last_counted_active + otherwise: 0 ``` ```math -\mathit{risk\_weighted\_opex} = \left( 1 - \omega \right) \cdot \left( \sum_{\xi \in \Xi} \pi_{\xi} \cdot \mathit{scenario\_opex}_{\xi} \right) + \omega \cdot CVaR +\mathit{w}^{h}_{l,\xi,t,s} = \begin{cases} \mathit{last}^{h}_{l,\xi,t,s} & \text{if } \neg \mathrm{reset}_{\xi,s} \\ \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{l,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` -### `total_cost` +### `StorageUnit_injection` ```yaml -total_cost: - dims: [] +StorageUnit_injection: expression: >- - Generator_capex - + Link_capex - + StorageUnit_capex - + Store_capex - + Line_capex - + Process_capex - + Transformer_capex - + risk_weighted_opex - description: >- - what the system costs — capacity once per active period at its - expected cost over the scenarios, operation in expectation over the - scenarios, and a share of it at the tail + sum(StorageUnit_sign * (StorageUnit_p_dispatch - StorageUnit_p_store), over=storage_unit, by=StorageUnit_bus[bus]) ``` ```math -\mathit{total\_cost} = \mathit{Generator\_capex} + \mathit{Link\_capex} + \mathit{StorageUnit\_capex} + \mathit{Store\_capex} + \mathit{Line\_capex} + \mathit{Process\_capex} + \mathit{Transformer\_capex} + \mathit{risk\_weighted\_opex} +\mathit{StorageUnit\_injection}_{n,\xi,t} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Generator_additions` +### `StorageUnit_last_counted_active` ```yaml -Generator_additions: - expression: >- - sum(Generator_p_nom_ext * Generator_first_active, over=generator, by=Generator_carrier[carrier]) +StorageUnit_last_counted_active: + description: >- + one at the last snapshot a row counts where a unit stands, and zero + elsewhere — a unit that retires before the last counted snapshot closes + on its last active level, as PyPSA forward-fills the level over the + counted snapshots (`global_constraints.py:455-458`) + dims: [scenario, global_constraint, snapshot, storage_unit] + cases: + last: + when: >- + GlobalConstraint_counts_snapshot AND StorageUnit_active + AND NOT shift(GlobalConstraint_counts_snapshot AND StorageUnit_active, along=snapshot, offset=-1) + expression: 1 + otherwise: 0 ``` ```math -\mathit{Generator\_additions}_{i,y} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_carrier}(g) = i} P_{g} \cdot \mathrm{new}_{g,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{last}^{h}_{l,\xi,t,s} = \begin{cases} 1 & \text{if } \mathrm{in}_{l,\xi,t} \wedge \mathrm{on}^{h}_{t,s} \wedge \neg \left( \mathrm{in}_{l,\xi,t + 1} \wedge \mathrm{on}^{h}_{t + 1,s} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` -### `Line_additions` +### `StorageUnit_operational_limit` ```yaml -Line_additions: +StorageUnit_operational_limit: expression: >- - sum(Line_s_nom_ext * Line_first_active, over=line, by=Line_carrier[carrier]) + -sum(sum((StorageUnit_state_of_charge * StorageUnit_closing_weight) * StorageUnit_operational_limit_weight, over=snapshot), over=storage_unit) ``` ```math -\mathit{Line\_additions}_{i,y} = \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_carrier}(k) = i} S_{k} \cdot \mathrm{new}^{s}_{k,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{StorageUnit\_operational\_limit}_{l,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{l,\xi,t,s} \cdot \mathrm{b}^{h}_{l,\xi,s} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Link_additions` +### `StorageUnit_opex` ```yaml -Link_additions: +StorageUnit_opex: expression: >- - sum(Link_p_nom_ext * Link_first_active, over=link, by=Link_carrier[carrier]) + sum(sum(((StorageUnit_p_dispatch * StorageUnit_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) + + sum(sum((((StorageUnit_p_dispatch * StorageUnit_p_dispatch) * StorageUnit_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) + + sum(sum(((StorageUnit_state_of_charge * StorageUnit_marginal_cost_storage) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) + + sum(sum(((StorageUnit_spill * StorageUnit_spill_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=storage_unit), over=snapshot) ``` ```math -\mathit{Link\_additions}_{i,y} = \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_carrier}(l) = i} F_{l} \cdot \mathrm{new}^{f}_{l,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{StorageUnit\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h,(2)}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{soc}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{soc}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{spill}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{spill}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -### `Process_additions` +### `StorageUnit_primary_energy` ```yaml -Process_additions: +StorageUnit_primary_energy: expression: >- - sum(Process_p_nom_ext * Process_first_active, over=process, by=Process_carrier[carrier]) + -sum(sum((StorageUnit_state_of_charge * StorageUnit_closing_weight) * StorageUnit_primary_energy_weight, over=snapshot), over=storage_unit) ``` ```math -\mathit{Process\_additions}_{i,y} = \sum_{j \in \mathcal{J} \,:\, \mathrm{Process\_carrier}(j) = i} Z_{j} \cdot \mathrm{new}^{z}_{y,j} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{StorageUnit\_primary\_energy}_{l,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{l,\xi,t,s} \cdot \mathrm{a}^{h}_{l,\xi,s} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `StorageUnit_additions` +### `StorageUnit_tech_capacity_expansion` ```yaml -StorageUnit_additions: - expression: >- - sum(StorageUnit_p_nom_ext * StorageUnit_first_active, over=storage_unit, by=StorageUnit_carrier[carrier]) +StorageUnit_tech_capacity_expansion: + expression: sum(StorageUnit_p_nom_ext * StorageUnit_tech_capacity_weight, over=storage_unit) ``` ```math -\mathit{StorageUnit\_additions}_{i,y} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_carrier}(s) = i} H_{s} \cdot \mathrm{new}^{h}_{y,s} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{StorageUnit\_tech\_capacity\_expansion}_{l} = \sum_{s \in \mathcal{S}} H_{s} \cdot \mathrm{m}^{h}_{l,s} \qquad \forall\, l \in \mathcal{L} ``` ### `Store_additions` @@ -7973,988 +7884,1044 @@ Store_additions: \mathit{Store\_additions}_{i,y} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_carrier}(v) = i} E_{v} \cdot \mathrm{new}^{e}_{y,v} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -### `Carrier_additions` +### `Store_capex` ```yaml -Carrier_additions: - dims: [period, carrier] - expression: >- - Generator_additions - + Line_additions - + Link_additions - + Process_additions - + StorageUnit_additions - + Store_additions - description: >- - what a carrier adds in a period — every extendable component of that - carrier, counting each build in the first period it stands in. Like - PyPSA, it sums only the components that carry a carrier attribute, so a - transformer, which has none, counts in no carrier +Store_capex: + expression: sum(scenario_weight * Store_e_nom_ext * Store_capital_cost * Store_capital_weight) ``` ```math -\mathit{Carrier\_additions}_{i,y} = \mathit{Generator\_additions}_{i,y} + \mathit{Line\_additions}_{i,y} + \mathit{Link\_additions}_{i,y} + \mathit{Process\_additions}_{i,y} + \mathit{StorageUnit\_additions}_{i,y} + \mathit{Store\_additions}_{i,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{Store\_capex} = \sum_{\xi \in \Xi,\ v \in \mathcal{V}} \pi_{\xi} \cdot E_{v} \cdot \mathrm{c}^{\mathrm{cap},e}_{\xi,v} \cdot \mathrm{W}^{e}_{v} ``` -### `Carrier_relative_growth` +### `Store_closing_weight` ```yaml -Carrier_relative_growth: +Store_closing_weight: description: >- - the share of the previous period's additions a carrier's growth limit - reads — PyPSA's `max_relative_growth` clipped at zero, so a negative - share adds nothing and never tightens the limit - dims: [carrier] + what the energy a store holds at a snapshot counts for in a row as its + closing level — the years of the period at the last snapshot of each + counted period where the store reopens per period, one at the last + counted snapshot it stands in where it does not, and nothing elsewhere + dims: [scenario, global_constraint, snapshot, store] cases: - positive: { when: Carrier_max_relative_growth > 0, expression: Carrier_max_relative_growth } + per_period: + when: Store_e_initial_per_period AND GlobalConstraint_counts_snapshot AND position(snapshot, within=snapshot_period[period]) == -1 + expression: at(period_weight_years, by=snapshot_period[period]) + carried_over: + when: NOT Store_e_initial_per_period + expression: Store_last_counted_active otherwise: 0 ``` ```math -\mathrm{r}^{+}_{i} = \begin{cases} \mathrm{r}_{i} & \text{if } \mathrm{r}_{i} > 0 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, i \in \mathcal{I} +\mathit{w}^{e}_{l,\xi,t,v} = \begin{cases} \mathit{last}^{e}_{l,\xi,t,v} & \text{if } \neg \mathrm{reset}^{e}_{\xi,v} \\ \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{l,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} ``` -### `Load_demand` +### `Store_energy_carried_in` ```yaml -Load_demand: +Store_energy_carried_in: description: >- - what a load draws from its bus's balance — its demand times its sign - where it is active, nothing where it is not, since PyPSA drops an - inactive load from the balance (`constraints.py:1513-1514`) - dims: [scenario, snapshot, load] + the energy a store opens a snapshot with — at the first snapshot it + stands in, its last such snapshot's less standing loss where it is + cyclic and the given initial energy, which no standing loss has touched + yet, where it is not; the previous snapshot's less standing loss + otherwise. A store built in a later period opens in that period, and a + cyclic one that retires closes on its own last snapshot. Per period, the + same holds with each investment period as the horizon + dims: [scenario, snapshot, store] cases: - active: { when: Load_active, expression: Load_sign * Load_p_set } - otherwise: 0 + cyclic: + when: >- + Store_e_cyclic AND NOT Store_e_cyclic_per_period AND NOT Store_e_initial_per_period + AND (position(snapshot) == 0 OR Store_opens_late) + expression: >- + Store_retention + * shift(shift(Store_e, along=snapshot, offset=1, edge='wrap'), along=snapshot, offset=Store_inactive_snapshots, edge='wrap') + opening: + when: >- + NOT Store_e_cyclic AND NOT Store_e_cyclic_per_period AND NOT Store_e_initial_per_period + AND (position(snapshot) == 0 OR Store_opens_late) + expression: Store_e_initial + period_cyclic: + when: Store_e_cyclic_per_period + expression: Store_retention * shift(Store_e, along=snapshot, offset=1, edge='wrap', within=snapshot_period[period]) + period_opening: + when: Store_e_initial_per_period AND NOT Store_e_cyclic_per_period AND position(snapshot, within=snapshot_period[period]) == 0 + expression: Store_e_initial + otherwise: Store_retention * shift(Store_e, along=snapshot, offset=1) +``` + +```math +\overleftarrow{e}_{\xi,t,v} = \begin{cases} \rho^{e}_{\xi,t,v} \cdot e_{\xi,\left( t \ominus \mathrm{idle}^{e} \right) \ominus 1,v} & \text{if } \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \neg \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,v} & \text{if } \mathrm{cyc}^{e,y}_{\xi,v} \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t - 1,v} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +``` + +### `Store_injection` + +```yaml +Store_injection: sum(Store_sign * Store_p, over=store, by=Store_bus[bus]) ``` ```math -\check{\mathrm{load}}_{d,\xi,t} = \begin{cases} \mathrm{sgn}^{\mathrm{load}}_{d} \cdot \mathrm{load}_{d,\xi,t} & \text{if } \mathrm{on}^{\mathrm{load}}_{d} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, d \in \mathcal{D},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Store\_injection}_{n,\xi,t} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Line_s_monitored` +### `Store_last_counted_active` ```yaml -Line_s_monitored: +Store_last_counted_active: description: >- - the flow a line's post-contingency rows read — its flow where it stands, - nothing where it does not, since PyPSA builds those rows for every - branch of the sub-network in every snapshot - dims: [scenario, snapshot, line] + one at the last snapshot a row counts where a store stands, and zero + elsewhere — a store that retires before the last counted snapshot closes + on its last active level, as PyPSA forward-fills the level over the + counted snapshots (`global_constraints.py:507-510`) + dims: [scenario, global_constraint, snapshot, store] cases: - standing: { when: Line_active, expression: Line_s } + last: + when: >- + GlobalConstraint_counts_snapshot AND Store_active + AND NOT shift(GlobalConstraint_counts_snapshot AND Store_active, along=snapshot, offset=-1) + expression: 1 otherwise: 0 ``` ```math -\check{s}_{k,\xi,t} = \begin{cases} s_{k,\xi,t} & \text{if } \mathrm{on}^{s}_{k,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{last}^{e}_{l,\xi,t,v} = \begin{cases} 1 & \text{if } \mathrm{in}_{l,\xi,t} \wedge \mathrm{on}^{e}_{t,v} \wedge \neg \left( \mathrm{in}_{l,\xi,t + 1} \wedge \mathrm{on}^{e}_{t + 1,v} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} ``` -### `Transformer_s_monitored` +### `Store_operational_limit` ```yaml -Transformer_s_monitored: - description: the flow a transformer's post-contingency rows read, as a line's - dims: [scenario, snapshot, transformer] - cases: - standing: { when: Transformer_active, expression: Transformer_s } - otherwise: 0 +Store_operational_limit: + expression: >- + -sum(sum((Store_e * Store_closing_weight) * Store_operational_limit_weight, over=snapshot), over=store) ``` ```math -\check{\sigma}_{\xi,t,m} = \begin{cases} \sigma_{\xi,t,m} & \text{if } \mathrm{on}^{\sigma}_{t,m} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} +\mathit{Store\_operational\_limit}_{l,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{l,\xi,t,v} \cdot \mathrm{b}^{e}_{l,\xi,v} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Outage_s` +### `Store_opex` ```yaml -Outage_s: - description: >- - the flow an outage takes off its branch — the outaged line's or - transformer's flow before it goes out - dims: [scenario, snapshot, outage] - cases: - line: { when: Outage_line, expression: "at(Line_s_monitored, by=Outage_line[line])" } - otherwise: at(Transformer_s_monitored, by=Outage_transformer[transformer]) +Store_opex: + expression: >- + sum(sum(((Store_p * Store_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) + + sum(sum((((Store_p * Store_p) * Store_marginal_cost_quadratic) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) + + sum(sum(((Store_e * Store_marginal_cost_storage) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot_period[period]), over=store), over=snapshot) ``` ```math -\hat{s}_{\kappa,\xi,t} = \begin{cases} \check{s}_{\mathrm{Outage\_line}(\kappa),\xi,t} & \text{if } \mathrm{Outage\_line}(\kappa) \text{ is defined} \\ \check{\sigma}_{\xi,t,\mathrm{Outage\_transformer}(\kappa)} & \text{otherwise} \end{cases} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Store\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot \mathrm{c}^{q}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot q_{\xi,t,v} \cdot \mathrm{c}^{q,(2)}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} e_{\xi,t,v} \cdot \mathrm{c}^{e}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -### `Generator_injection` +### `Store_primary_energy` ```yaml -Generator_injection: - expression: sum(Generator_sign * Generator_p, over=generator, by=Generator_bus[bus]) +Store_primary_energy: + expression: >- + -sum(sum((Store_e * Store_closing_weight) * Store_primary_energy_weight, over=snapshot), over=store) ``` ```math -\mathit{Generator\_injection}_{n,\xi,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Store\_primary\_energy}_{l,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{l,\xi,t,v} \cdot \mathrm{a}^{e}_{l,\xi,v} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Line_injection` +### `Store_tech_capacity_expansion` ```yaml -Line_injection: - expression: >- - -sum(Line_s, over=line, by=Line_bus0[bus]) - + sum(Line_s, over=line, by=Line_bus1[bus]) - - (0.5 * sum(Line_loss, over=line, by=Line_bus0[bus])) - - (0.5 * sum(Line_loss, over=line, by=Line_bus1[bus])) +Store_tech_capacity_expansion: + expression: sum(Store_e_nom_ext * Store_tech_capacity_weight, over=store) ``` ```math -\mathit{Line\_injection}_{n,\xi,t} = -\left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Store\_tech\_capacity\_expansion}_{l} = \sum_{v \in \mathcal{V}} E_{v} \cdot \mathrm{m}^{e}_{l,v} \qquad \forall\, l \in \mathcal{L} ``` -### `Link_injection` +### `Transformer_angle_sum` ```yaml -Link_injection: +Transformer_angle_sum: expression: >- - -sum(Link_p, over=link, by=Link_bus0[bus]) - + sum(Link_output_arrival, over=link_output, by=Link_output_bus[bus]) + sum(Transformer_s * at(Transformer_cycle_weight, by=snapshot_period[period]), over=transformer) + + sum(Transformer_phase_shift_weight, over=transformer) + + sum(Transformer_phase_shift * at(Transformer_phase_shift_cycle_weight, by=snapshot_period[period]), over=transformer) ``` ```math -\mathit{Link\_injection}_{n,\xi,t} = -\left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Transformer\_angle\_sum}_{c,\xi,t} = \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Load_injection` +### `Transformer_capex` ```yaml -Load_injection: sum(Load_demand, over=load, by=Load_bus[bus]) +Transformer_capex: + expression: sum(scenario_weight * Transformer_s_nom_ext * Transformer_capital_cost * Transformer_capital_weight) ``` ```math -\mathrm{Load\_injection}_{n,\xi,t} = \sum_{d \in \mathcal{D} \,:\, \mathrm{Load\_bus}(d) = n} \check{\mathrm{load}}_{d,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Transformer\_capex} = \sum_{\xi \in \Xi,\ m \in \mathcal{M}} \pi_{\xi} \cdot \Sigma_{m} \cdot \mathrm{c}^{\mathrm{cap},\sigma}_{\xi,m} \cdot \mathrm{W}^{\sigma}_{m} ``` -### `Process_injection` +### `Transformer_injection` ```yaml -Process_injection: +Transformer_injection: expression: >- - sum(Process_output_arrival, over=process_output, by=Process_output_bus[bus]) + -sum(Transformer_s, over=transformer, by=Transformer_bus0[bus]) + + sum(Transformer_s, over=transformer, by=Transformer_bus1[bus]) + - (0.5 * sum(Transformer_loss, over=transformer, by=Transformer_bus0[bus])) + - (0.5 * sum(Transformer_loss, over=transformer, by=Transformer_bus1[bus])) ``` ```math -\mathit{Process\_injection}_{n,\xi,t} = \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Transformer\_injection}_{n,\xi,t} = -\left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \sigma_{\xi,t,m} \right) + \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \sigma_{\xi,t,m} - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `StorageUnit_injection` +### `Transformer_s_monitored` ```yaml -StorageUnit_injection: - expression: >- - sum(StorageUnit_sign * (StorageUnit_p_dispatch - StorageUnit_p_store), over=storage_unit, by=StorageUnit_bus[bus]) +Transformer_s_monitored: + description: the flow a transformer's post-contingency rows read, as a line's + dims: [scenario, snapshot, transformer] + cases: + standing: { when: Transformer_active, expression: Transformer_s } + otherwise: 0 ``` ```math -\mathit{StorageUnit\_injection}_{n,\xi,t} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\check{\sigma}_{\xi,t,m} = \begin{cases} \sigma_{\xi,t,m} & \text{if } \mathrm{on}^{\sigma}_{t,m} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} ``` -### `Store_injection` +### `operational_limit` ```yaml -Store_injection: sum(Store_sign * Store_p, over=store, by=Store_bus[bus]) +operational_limit: + dims: [scenario, global_constraint] + expression: >- + Generator_operational_limit + + StorageUnit_operational_limit + + Store_operational_limit + description: >- + what an `operational_limit` row totals — the weighted energy its + generators deliver over the snapshots it counts, plus what its + non-cyclic storage draws down; the initial charge it draws from is + folded into the row's constant ``` ```math -\mathit{Store\_injection}_{n,\xi,t} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{operational\_limit}_{l,\xi} = \mathit{Generator\_operational\_limit}_{l,\xi} + \mathit{StorageUnit\_operational\_limit}_{l,\xi} + \mathit{Store\_operational\_limit}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Transformer_injection` +### `primary_energy` ```yaml -Transformer_injection: - expression: >- - -sum(Transformer_s, over=transformer, by=Transformer_bus0[bus]) - + sum(Transformer_s, over=transformer, by=Transformer_bus1[bus]) - - (0.5 * sum(Transformer_loss, over=transformer, by=Transformer_bus0[bus])) - - (0.5 * sum(Transformer_loss, over=transformer, by=Transformer_bus1[bus])) +primary_energy: + dims: [scenario, global_constraint] + expression: Generator_primary_energy + StorageUnit_primary_energy + Store_primary_energy + description: >- + what a `primary_energy` row totals — weighted generator energy over the + snapshots it counts, less the charge left in weighted storage at the + close; the initial charge it is compared against is folded into the + row's constant ``` ```math -\mathit{Transformer\_injection}_{n,\xi,t} = -\left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \sigma_{\xi,t,m} \right) + \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \sigma_{\xi,t,m} - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{primary\_energy}_{l,\xi} = \mathit{Generator\_primary\_energy}_{l,\xi} + \mathit{StorageUnit\_primary\_energy}_{l,\xi} + \mathit{Store\_primary\_energy}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Bus_injection` +### `risk_weighted_opex` ```yaml -Bus_injection: - dims: [scenario, snapshot, bus] - expression: >- - Generator_injection - + Line_injection - + Link_injection - + Load_injection - + Process_injection - + StorageUnit_injection - + Store_injection - + Transformer_injection - description: >- - what every component puts into a bus, less what it takes out of it; - PyPSA writes each term into the balance, and a load on its right-hand - side +risk_weighted_opex: + expression: (1 - CVaR_omega) * sum(scenario_weight * scenario_opex, over=scenario) + CVaR_omega * CVaR ``` ```math -\mathit{Bus\_injection}_{n,\xi,t} = \mathit{Generator\_injection}_{n,\xi,t} + \mathit{Line\_injection}_{n,\xi,t} + \mathit{Link\_injection}_{n,\xi,t} + \mathrm{Load\_injection}_{n,\xi,t} + \mathit{Process\_injection}_{n,\xi,t} + \mathit{StorageUnit\_injection}_{n,\xi,t} + \mathit{Store\_injection}_{n,\xi,t} + \mathit{Transformer\_injection}_{n,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{risk\_weighted\_opex} = \left( 1 - \omega \right) \cdot \left( \sum_{\xi \in \Xi} \pi_{\xi} \cdot \mathit{scenario\_opex}_{\xi} \right) + \omega \cdot CVaR ``` -### `Line_angle_sum` +### `scenario_opex` ```yaml -Line_angle_sum: sum(Line_s * at(Line_cycle_weight, by=snapshot_period[period]), over=line) +scenario_opex: + dims: [scenario] + expression: >- + Generator_opex + + Generator_commitment_opex + + Link_opex + + Link_commitment_opex + + Process_opex + + Process_commitment_opex + + StorageUnit_opex + + Store_opex + description: >- + what a future costs to run — every operating term, weighted by the + snapshot's hours and its period, before the scenario's own weight; a + start and a stop cost what they cost, unweighted, as PyPSA adds them + (`optimize.py:415-432`) ``` ```math -\mathit{Line\_angle\_sum}_{c,\xi,t} = \sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{scenario\_opex}_{\xi} = \mathit{Generator\_opex}_{\xi} + \mathit{Generator\_commitment\_opex}_{\xi} + \mathit{Link\_opex}_{\xi} + \mathit{Link\_commitment\_opex}_{\xi} + \mathit{Process\_opex}_{\xi} + \mathit{Process\_commitment\_opex}_{\xi} + \mathit{StorageUnit\_opex}_{\xi} + \mathit{Store\_opex}_{\xi} \qquad \forall\, \xi \in \Xi ``` -### `Transformer_angle_sum` +### `tech_capacity_expansion` ```yaml -Transformer_angle_sum: +tech_capacity_expansion: + dims: [global_constraint] expression: >- - sum(Transformer_s * at(Transformer_cycle_weight, by=snapshot_period[period]), over=transformer) - + sum(Transformer_phase_shift_weight, over=transformer) - + sum(Transformer_phase_shift * at(Transformer_phase_shift_cycle_weight, by=snapshot_period[period]), over=transformer) + Generator_tech_capacity_expansion + + Line_tech_capacity_expansion + + Link_tech_capacity_expansion + + Process_tech_capacity_expansion + + StorageUnit_tech_capacity_expansion + + Store_tech_capacity_expansion + description: >- + what a `tech_capacity_expansion_limit` row totals — the chosen build of + the row's carrier-and-bus set ``` ```math -\mathit{Transformer\_angle\_sum}_{c,\xi,t} = \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{tech\_capacity\_expansion}_{l} = \mathit{Generator\_tech\_capacity\_expansion}_{l} + \mathit{Line\_tech\_capacity\_expansion}_{l} + \mathit{Link\_tech\_capacity\_expansion}_{l} + \mathit{Process\_tech\_capacity\_expansion}_{l} + \mathit{StorageUnit\_tech\_capacity\_expansion}_{l} + \mathit{Store\_tech\_capacity\_expansion}_{l} \qquad \forall\, l \in \mathcal{L} ``` -### `Cycle_angle_sum` +### `total_cost` ```yaml -Cycle_angle_sum: - dims: [scenario, snapshot, cycle] - expression: Line_angle_sum + Transformer_angle_sum +total_cost: + dims: [] + expression: >- + Generator_capex + + Link_capex + + StorageUnit_capex + + Store_capex + + Line_capex + + Process_capex + + Transformer_capex + + risk_weighted_opex description: >- - the voltage angle differences around a cycle: every branch flow times - its cycle weight, and every transformer phase shift + what the system costs — capacity once per active period at its + expected cost over the scenarios, operation in expectation over the + scenarios, and a share of it at the tail ``` ```math -\mathit{Cycle\_angle\_sum}_{c,\xi,t} = \mathit{Line\_angle\_sum}_{c,\xi,t} + \mathit{Transformer\_angle\_sum}_{c,\xi,t} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{total\_cost} = \mathit{Generator\_capex} + \mathit{Link\_capex} + \mathit{StorageUnit\_capex} + \mathit{Store\_capex} + \mathit{Line\_capex} + \mathit{Process\_capex} + \mathit{Transformer\_capex} + \mathit{risk\_weighted\_opex} ``` -### Objective +### `transmission_expansion_cost` ```yaml -objective: - sense: minimize - expression: total_cost +transmission_expansion_cost: + dims: [scenario, global_constraint] + expression: Line_transmission_expansion_cost + Link_transmission_expansion_cost + description: >- + what a `transmission_expansion_cost_limit` row totals — capital cost + times the chosen build of the row's branches ``` ```math -\min \mathit{total\_cost} +\mathit{transmission\_expansion\_cost}_{l,\xi} = \mathit{Line\_transmission\_expansion\_cost}_{l,\xi} + \mathit{Link\_transmission\_expansion\_cost}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Generator-fix-p-lower` - -`Generator_fix_p_lower` +### `transmission_volume_expansion` ```yaml -Generator_fix_p_lower: - description: "`Generator-fix-p-lower` — a fixed generator outputs at least its minimum" - dims: [scenario, snapshot, generator] - where: not Generator_p_nom_extendable AND not Generator_committable AND Generator_active - expression: Generator_p >= Generator_p_min_pu * Generator_p_nom * (1 - Generator_maintenance_pu * Generator_maintenance) +transmission_volume_expansion: + dims: [scenario, global_constraint] + expression: Line_transmission_volume_expansion + Link_transmission_volume_expansion + description: >- + what a `transmission_volume_expansion_limit` row totals — length times + the chosen build of the row's branches ``` ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +\mathit{transmission\_volume\_expansion}_{l,\xi} = \mathit{Line\_transmission\_volume\_expansion}_{l,\xi} + \mathit{Link\_transmission\_volume\_expansion}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -### `Generator-fix-p-upper` - -`Generator_fix_p_upper` +### Objective ```yaml -Generator_fix_p_upper: - description: "`Generator-fix-p-upper` — a fixed generator outputs at most what is available" - dims: [scenario, snapshot, generator] - where: not Generator_p_nom_extendable AND not Generator_committable AND Generator_active - expression: Generator_p <= Generator_p_max_pu * Generator_p_nom * (1 - Generator_maintenance_pu * Generator_maintenance) +objective: + sense: minimize + expression: total_cost ``` ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +\min \mathit{total\_cost} ``` -### `Link-fix-p-lower` +### `Bus-nodal_balance` -`Link_fix_p_lower` +`Bus_nodal_balance` ```yaml -Link_fix_p_lower: - description: "`Link-fix-p-lower` — a fixed link carries at least its minimum, negative for the other way" - dims: [scenario, snapshot, link] - where: not Link_p_nom_extendable AND not Link_committable AND Link_active - expression: Link_p >= Link_p_min_pu * Link_p_nom * (1 - Link_maintenance_pu * Link_maintenance) +Bus_nodal_balance: + description: >- + `Bus-nodal_balance` — what is generated at a bus, storage dispatch and + stores included, less what the links take away, plus what arrives over + them after losses and any delay at every port they deliver to, each + process port drawing or delivering at its own rate and each passive branch + carrying its flow, meets the load there, less half of every incident + line's and transformer's loss — PyPSA dissipates a branch's loss half at + either end. Each generator, storage unit, store and load term enters + with its component's `sign` (`constraints.py:1404-1405`, `:1514`), and + an inactive load not at all. A bus nothing is attached to has no row; PyPSA refuses one that + carries load, and this file does not yet. + dims: [scenario, snapshot, bus] + expression: Bus_injection == 0 ``` ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +\sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} - \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) - \left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} + \sum_{d \in \mathcal{D} \,:\, \mathrm{Load\_bus}(d) = n} \check{\mathrm{load}}_{d,\xi,t} + \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} + \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) + \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} - \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \sigma_{\xi,t,m} \right) + \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \sigma_{\xi,t,m} - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) = 0 \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link-fix-p-upper` +### `CVaR-def` -`Link_fix_p_upper` +`CVaR_def` ```yaml -Link_fix_p_upper: - description: "`Link-fix-p-upper` — a fixed link carries at most its nominal power" - dims: [scenario, snapshot, link] - where: not Link_p_nom_extendable AND not Link_committable AND Link_active - expression: Link_p <= Link_p_max_pu * Link_p_nom * (1 - Link_maintenance_pu * Link_maintenance) +CVaR_def: + description: "`CVaR-def` — the tail's average is at least where it starts plus the expected excess over the tail's probability" + dims: [] + where: CVaR_omega + expression: CVaR_theta + 1 / (1 - CVaR_alpha) * sum(scenario_weight * CVaR_a, over=scenario) <= CVaR ``` ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +\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-ext-p-lower` +### `CVaR-excess-{s}` -`Generator_ext_p_lower` +`CVaR_excess` ```yaml -Generator_ext_p_lower: - description: "`Generator-ext-p-lower` — an extendable generator outputs at least its minimum of the chosen build" - dims: [scenario, snapshot, generator] - where: Generator_p_nom_extendable AND not Generator_committable AND Generator_active - expression: Generator_p >= Generator_p_min_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) +CVaR_excess: + description: "`CVaR-excess-{s}` — a scenario's operating cost beyond the tail's start is its excess; PyPSA names one row per scenario" + dims: [scenario] + where: CVaR_omega + expression: CVaR_a - scenario_opex + CVaR_theta >= 0 ``` ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +a_{\xi} - \mathit{scenario\_opex}_{\xi} + \theta \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} ``` -### `Generator-ext-p-upper` +### `Carrier-growth_limit` -`Generator_ext_p_upper` +`Carrier_growth_limit` ```yaml -Generator_ext_p_upper: - description: "`Generator-ext-p-upper` — an extendable generator outputs at most what is available of the chosen build" - dims: [scenario, snapshot, generator] - where: Generator_p_nom_extendable AND not Generator_committable AND Generator_active - expression: Generator_p <= Generator_p_max_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) +Carrier_growth_limit: + description: >- + `Carrier-growth_limit` — what a carrier adds across its extendable components in a period, + counting each build in the first period it stands in, is at most its allowance plus a share of + what it added the period before; the first period has no predecessor, so `edge=0` leaves it the + bare allowance + dims: [carrier, period] + where: Carrier_max_growth + expression: >- + Carrier_additions + - shift(Carrier_additions, along=period, offset=1, edge=0) * Carrier_relative_growth + <= Carrier_max_growth ``` ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +\mathit{Carrier\_additions}_{i,y} - \mathit{Carrier\_additions}_{i,y \boxminus_{0} 1} \cdot \mathrm{r}^{+}_{i} \le \overline{\Delta}_{i} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} \,:\, \overline{\Delta}_{i} \text{ is defined} ``` -### `Generator-ext-p_nom-lower` +### `Generator-com-down-time` -`Generator_ext_p_nom_lower` +`Generator_com_down_time` ```yaml -Generator_ext_p_nom_lower: - description: "`Generator-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, generator] - where: Generator_p_nom_extendable AND Generator_active_asset - expression: Generator_p_nom_ext >= Generator_p_nom_min +Generator_com_down_time: + description: >- + `Generator-com-down-time` — a unit stopped within its own minimum down + time is still off. The first snapshot's share of the window is the + brought-in down time's, which the must-stay-down mask carries + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_min_down_time > 0 AND position(snapshot) > 0 + expression: sum_back(Generator_shut_down, along=snapshot, window=Generator_min_down_time) <= 1 - Generator_status ``` ```math -P_{g} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}} \mathit{dn}_{g,\xi,t'} \le 1 - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{DT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Generator-ext-p_nom-upper` +### `Generator-com-ext-p-lower` -`Generator_ext_p_nom_upper` +`Generator_com_ext_p_lower` ```yaml -Generator_ext_p_nom_upper: - description: "`Generator-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, generator] - where: Generator_p_nom_extendable AND Generator_active_asset AND Generator_p_nom_max - expression: Generator_p_nom_ext <= Generator_p_nom_max +Generator_com_ext_p_lower: + description: >- + `Generator-com-ext-p-lower` — a committed extendable unit outputs at + least its minimum of the chosen build; off, the big M releases the row + dims: [scenario, snapshot, generator] + where: Generator_com_ext + expression: >- + Generator_p >= + Generator_p_min_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) + + Generator_big_m * Generator_status - Generator_big_m ``` ```math -P_{g} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \text{ is defined} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) + \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} - \mathrm{M}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -### `Generator-p_nom_set` +### `Generator-com-ext-p-lower-nonneg` -`Generator_p_nom_set` +`Generator_com_ext_p_lower_nonneg` ```yaml -Generator_p_nom_set: - description: "`Generator-p_nom_set` — the chosen build pinned, wherever a value is given" - dims: [generator] - where: Generator_p_nom_extendable AND Generator_active_asset AND Generator_p_nom_set - expression: Generator_p_nom_ext == Generator_p_nom_set +Generator_com_ext_p_lower_nonneg: + description: >- + `Generator-com-ext-p-lower-nonneg` — where no minimum-per-unit is + negative, output is also plainly non-negative, a row the big-M lower + cannot assert while the unit is off + dims: [scenario, snapshot, generator] + where: Generator_com_ext AND Generator_p_min_pu_nonneg + expression: Generator_p >= 0 ``` ```math -P_{g} = \mathrm{p}^{\mathrm{nom,set}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \mathrm{p}^{\mathrm{nom,set}}_{g} \text{ is defined} +p_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \mathrm{nonneg}_{g} ``` -### `Generator-e_sum_min` +### `Generator-com-ext-p-upper-bigM` -`Generator_e_sum_min` +`Generator_com_ext_p_upper_big_m` ```yaml -Generator_e_sum_min: - description: "`Generator-e_sum_min` — energy over the horizon is at least its floor; a floor of minus infinity is no row" - dims: [scenario, generator] - where: Generator_e_sum_min - expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) >= Generator_e_sum_min +Generator_com_ext_p_upper_big_m: + description: "`Generator-com-ext-p-upper-bigM` — off, a unit outputs nothing; on, the big M is no bound" + dims: [scenario, snapshot, generator] + where: Generator_com_ext + expression: Generator_p <= Generator_big_m * Generator_status ``` ```math -\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \ge \underline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \underline{\mathrm{E}}_{g,\xi} \text{ is defined} +p_{g,\xi,t} \le \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -### `Generator-e_sum_max` +### `Generator-com-ext-p-upper-cap` -`Generator_e_sum_max` +`Generator_com_ext_p_upper_cap` ```yaml -Generator_e_sum_max: - description: "`Generator-e_sum_max` — energy over the horizon is at most its budget; a budget of infinity is no row" - dims: [scenario, generator] - where: Generator_e_sum_max - expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) <= Generator_e_sum_max +Generator_com_ext_p_upper_cap: + description: >- + `Generator-com-ext-p-upper-cap` — a committed extendable unit outputs + at most what is available of the chosen build, whatever its status + dims: [scenario, snapshot, generator] + where: Generator_com_ext + expression: Generator_p <= Generator_p_max_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) ``` ```math -\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \le \overline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \overline{\mathrm{E}}_{g,\xi} \text{ is defined} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -### `Link-ext-p-lower` +### `Generator-com-mod-p-lower` -`Link_ext_p_lower` +`Generator_com_mod_p_lower` ```yaml -Link_ext_p_lower: - description: "`Link-ext-p-lower` — an extendable link carries at least its minimum of the chosen build, negative for the other way" - dims: [scenario, snapshot, link] - where: Link_p_nom_extendable AND not Link_committable AND Link_active - expression: Link_p >= Link_p_min_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) +Generator_com_mod_p_lower: + description: >- + `Generator-com-mod-p-lower` — a committed modular unit outputs at least + its minimum of one module, whether the build is fixed or a decision + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_p_nom_mod > 0 + expression: Generator_p >= Generator_p_min_pu * Generator_p_nom_mod * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) ``` ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Link-ext-p-upper` +### `Generator-com-mod-p-upper` -`Link_ext_p_upper` +`Generator_com_mod_p_upper` ```yaml -Link_ext_p_upper: - description: "`Link-ext-p-upper` — an extendable link carries at most the chosen build" - dims: [scenario, snapshot, link] - where: Link_p_nom_extendable AND not Link_committable AND Link_active - expression: Link_p <= Link_p_max_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) +Generator_com_mod_p_upper: + description: >- + `Generator-com-mod-p-upper` — a committed modular unit outputs at most + one module's share, whether the build is fixed or a decision + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_p_nom_mod > 0 + expression: Generator_p <= Generator_p_max_pu * Generator_p_nom_mod * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) ``` ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Link-ext-p_nom-lower` +### `Generator-com-p-lower` -`Link_ext_p_nom_lower` +`Generator_com_p_lower` ```yaml -Link_ext_p_nom_lower: - description: "`Link-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, link] - where: Link_p_nom_extendable AND Link_active_asset - expression: Link_p_nom_ext >= Link_p_nom_min +Generator_com_p_lower: + description: "`Generator-com-p-lower` — a committed unit outputs at least its minimum; off, at least nothing" + dims: [scenario, snapshot, generator] + where: Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) + expression: Generator_p >= Generator_p_min_pu * Generator_p_nom * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) ``` ```math -F_{l} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Link-ext-p_nom-upper` +### `Generator-com-p-upper` -`Link_ext_p_nom_upper` +`Generator_com_p_upper` ```yaml -Link_ext_p_nom_upper: - description: "`Link-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, link] - where: Link_p_nom_extendable AND Link_active_asset AND Link_p_nom_max - expression: Link_p_nom_ext <= Link_p_nom_max +Generator_com_p_upper: + description: "`Generator-com-p-upper` — a committed unit outputs at most what is available; off, at most nothing" + dims: [scenario, snapshot, generator] + where: Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) + expression: Generator_p <= Generator_p_max_pu * Generator_p_nom * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) ``` ```math -F_{l} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \text{ is defined} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Link-p_nom_set` +### `Generator-com-status-min_down_time_must_stay_up` -`Link_p_nom_set` +`Generator_com_status_must_stay_down` ```yaml -Link_p_nom_set: - description: "`Link-p_nom_set` — the chosen build pinned, wherever a value is given" - dims: [link] - where: Link_p_nom_extendable AND Link_active_asset AND Link_p_nom_set - expression: Link_p_nom_ext == Link_p_nom_set +Generator_com_status_must_stay_down: + description: >- + `Generator-com-status-min_down_time_must_stay_up` — a unit still serving + the down time it brought in stays off; PyPSA names the row `_must_stay_up` + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_must_stay_down + expression: Generator_status == 0 ``` ```math -F_{l} = \mathrm{f}^{\mathrm{nom,set}}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \mathrm{f}^{\mathrm{nom,set}}_{l} \text{ is defined} +u_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{rest}_{g,\xi,t} ``` -### `Process-fix-p-lower` +### `Generator-com-status-min_up_time_must_stay_up` -`Process_fix_p_lower` +`Generator_com_status_must_stay_up` ```yaml -Process_fix_p_lower: - description: "`Process-fix-p-lower` — a fixed process runs at least its minimum, negative for the other way" - dims: [scenario, snapshot, process] - where: not Process_p_nom_extendable AND not Process_committable AND Process_active - expression: Process_p >= Process_p_min_pu * Process_p_nom * (1 - Process_maintenance_pu * Process_maintenance) +Generator_com_status_must_stay_up: + description: "`Generator-com-status-min_up_time_must_stay_up` — a unit still serving the up time it brought in stays on" + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_must_stay_up + expression: Generator_status == 1 ``` ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +u_{g,\xi,t} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{hold}_{g,\xi,t} ``` -### `Process-fix-p-upper` +### `Generator-com-transition-shut-down` -`Process_fix_p_upper` +`Generator_com_transition_shut_down` ```yaml -Process_fix_p_upper: - description: "`Process-fix-p-upper` — a fixed process runs at most its nominal power" - dims: [scenario, snapshot, process] - where: not Process_p_nom_extendable AND not Process_committable AND Process_active - expression: Process_p <= Process_p_max_pu * Process_p_nom * (1 - Process_maintenance_pu * Process_maintenance) +Generator_com_transition_shut_down: + description: "`Generator-com-transition-shut-down` — turning off is a stop, counted against the state the unit carried into the snapshot" + dims: [scenario, snapshot, generator] + where: Generator_committed + expression: Generator_shut_down >= Generator_previous_status - Generator_status ``` ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +\mathit{dn}_{g,\xi,t} \ge \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -### `Process-ext-p-lower` +### `Generator-com-transition-start-up` -`Process_ext_p_lower` +`Generator_com_transition_start_up` ```yaml -Process_ext_p_lower: - description: "`Process-ext-p-lower` — an extendable process runs at least its minimum of the chosen build, negative for the other way" - dims: [scenario, snapshot, process] - where: Process_p_nom_extendable AND not Process_committable AND Process_active - expression: Process_p >= Process_p_min_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) +Generator_com_transition_start_up: + description: "`Generator-com-transition-start-up` — turning on is a start, counted against the state the unit carried into the snapshot" + dims: [scenario, snapshot, generator] + where: Generator_committed + expression: Generator_start_up >= Generator_status - Generator_previous_status ``` ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +\mathit{up}_{g,\xi,t} \ge u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -### `Process-ext-p-upper` +### `Generator-com-up-time` -`Process_ext_p_upper` +`Generator_com_up_time` ```yaml -Process_ext_p_upper: - description: "`Process-ext-p-upper` — an extendable process runs at most the chosen build" - dims: [scenario, snapshot, process] - where: Process_p_nom_extendable AND not Process_committable AND Process_active - expression: Process_p <= Process_p_max_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) +Generator_com_up_time: + description: >- + `Generator-com-up-time` — a unit started within its own minimum up time + is still on. The first snapshot's share of the window is the brought-in + up time's, which the must-stay-up mask carries + dims: [scenario, snapshot, generator] + where: Generator_committed AND Generator_min_up_time > 0 AND position(snapshot) > 0 + expression: sum_back(Generator_start_up, along=snapshot, window=Generator_min_up_time) <= Generator_status ``` ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}} \mathit{up}_{g,\xi,t'} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{UT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Process-ext-p_nom-lower` +### `Generator-e_sum_max` -`Process_ext_p_nom_lower` +`Generator_e_sum_max` ```yaml -Process_ext_p_nom_lower: - description: "`Process-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, process] - where: Process_p_nom_extendable AND Process_active_asset - expression: Process_p_nom_ext >= Process_p_nom_min +Generator_e_sum_max: + description: "`Generator-e_sum_max` — energy over the horizon is at most its budget; a budget of infinity is no row" + dims: [scenario, generator] + where: Generator_e_sum_max + expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) <= Generator_e_sum_max ``` ```math -Z_{j} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} +\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \le \overline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \overline{\mathrm{E}}_{g,\xi} \text{ is defined} ``` -### `Process-ext-p_nom-upper` +### `Generator-e_sum_min` -`Process_ext_p_nom_upper` +`Generator_e_sum_min` ```yaml -Process_ext_p_nom_upper: - description: "`Process-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, process] - where: Process_p_nom_extendable AND Process_active_asset AND Process_p_nom_max - expression: Process_p_nom_ext <= Process_p_nom_max +Generator_e_sum_min: + description: "`Generator-e_sum_min` — energy over the horizon is at least its floor; a floor of minus infinity is no row" + dims: [scenario, generator] + where: Generator_e_sum_min + expression: sum(Generator_p * snapshot_weightings_generators, over=snapshot) >= Generator_e_sum_min ``` ```math -Z_{j} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \text{ is defined} +\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \ge \underline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \underline{\mathrm{E}}_{g,\xi} \text{ is defined} ``` -### `Process-p_nom_set` +### `Generator-ext-p-lower` -`Process_p_nom_set` +`Generator_ext_p_lower` ```yaml -Process_p_nom_set: - description: "`Process-p_nom_set` — the chosen build pinned, wherever a value is given" - dims: [process] - where: Process_p_nom_extendable AND Process_active_asset AND Process_p_nom_set - expression: Process_p_nom_ext == Process_p_nom_set +Generator_ext_p_lower: + description: "`Generator-ext-p-lower` — an extendable generator outputs at least its minimum of the chosen build" + dims: [scenario, snapshot, generator] + where: Generator_p_nom_extendable AND not Generator_committable AND Generator_active + expression: Generator_p >= Generator_p_min_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) ``` ```math -Z_{j} = \mathrm{z}^{\mathrm{nom,set}}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \mathrm{z}^{\mathrm{nom,set}}_{j} \text{ is defined} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -### `StorageUnit-fix-p_dispatch-lower` +### `Generator-ext-p_nom-lower` -`StorageUnit_fix_p_dispatch_lower` +`Generator_ext_p_nom_lower` ```yaml -StorageUnit_fix_p_dispatch_lower: - description: "`StorageUnit-fix-p_dispatch-lower` — dispatch is non-negative" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_p_dispatch >= 0 +Generator_ext_p_nom_lower: + description: "`Generator-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, generator] + where: Generator_p_nom_extendable AND Generator_active_asset + expression: Generator_p_nom_ext >= Generator_p_nom_min ``` ```math -h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +P_{g} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} ``` -### `StorageUnit-fix-p_dispatch-upper` +### `Generator-ext-p_nom-upper` -`StorageUnit_fix_p_dispatch_upper` +`Generator_ext_p_nom_upper` ```yaml -StorageUnit_fix_p_dispatch_upper: - description: "`StorageUnit-fix-p_dispatch-upper` — a fixed unit dispatches at most its nominal power" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_p_dispatch <= StorageUnit_p_max_pu * StorageUnit_p_nom +Generator_ext_p_nom_upper: + description: "`Generator-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, generator] + where: Generator_p_nom_extendable AND Generator_active_asset AND Generator_p_nom_max + expression: Generator_p_nom_ext <= Generator_p_nom_max ``` ```math -h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +P_{g} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \text{ is defined} ``` -### `StorageUnit-fix-p_store-lower` +### `Generator-ext-p-upper` -`StorageUnit_fix_p_store_lower` +`Generator_ext_p_upper` ```yaml -StorageUnit_fix_p_store_lower: - description: "`StorageUnit-fix-p_store-lower` — storing is non-negative" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_p_store >= 0 +Generator_ext_p_upper: + description: "`Generator-ext-p-upper` — an extendable generator outputs at most what is available of the chosen build" + dims: [scenario, snapshot, generator] + where: Generator_p_nom_extendable AND not Generator_committable AND Generator_active + expression: Generator_p <= Generator_p_max_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) ``` ```math -h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -### `StorageUnit-fix-p_store-upper` +### `Generator-fix-p-lower` -`StorageUnit_fix_p_store_upper` +`Generator_fix_p_lower` ```yaml -StorageUnit_fix_p_store_upper: - description: >- - `StorageUnit-fix-p_store-upper` — a fixed unit stores at most its - nominal power, the minimum-per-unit column carrying that cap negated - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_p_store <= -StorageUnit_p_min_pu * StorageUnit_p_nom +Generator_fix_p_lower: + description: "`Generator-fix-p-lower` — a fixed generator outputs at least its minimum" + dims: [scenario, snapshot, generator] + where: not Generator_p_nom_extendable AND not Generator_committable AND Generator_active + expression: Generator_p >= Generator_p_min_pu * Generator_p_nom * (1 - Generator_maintenance_pu * Generator_maintenance) ``` ```math -h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -### `StorageUnit-fix-state_of_charge-lower` +### `Generator-fix-p-upper` -`StorageUnit_fix_state_of_charge_lower` +`Generator_fix_p_upper` ```yaml -StorageUnit_fix_state_of_charge_lower: - description: "`StorageUnit-fix-state_of_charge-lower` — charge is non-negative" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_state_of_charge >= 0 +Generator_fix_p_upper: + description: "`Generator-fix-p-upper` — a fixed generator outputs at most what is available" + dims: [scenario, snapshot, generator] + where: not Generator_p_nom_extendable AND not Generator_committable AND Generator_active + expression: Generator_p <= Generator_p_max_pu * Generator_p_nom * (1 - Generator_maintenance_pu * Generator_maintenance) ``` ```math -\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -### `StorageUnit-fix-state_of_charge-upper` +### `Generator-maint-event-count` -`StorageUnit_fix_state_of_charge_upper` +`Generator_maint_event_count` ```yaml -StorageUnit_fix_state_of_charge_upper: - description: "`StorageUnit-fix-state_of_charge-upper` — a fixed unit holds at most its hours at nominal power" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_fix - expression: StorageUnit_state_of_charge <= StorageUnit_max_hours * StorageUnit_p_nom +Generator_maint_event_count: + description: "`Generator-maint-event-count` — a maintainable generator holds its number of maintenance events over the horizon" + dims: [scenario, generator] + where: Generator_maintainable + expression: sum(Generator_maintenance_start, over=snapshot) == Generator_maintenance_events ``` ```math -\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +\sum_{t \in \mathcal{T}} \mu^{\mathrm{up}}_{g,\xi,t} = \mathrm{n}^{\mathrm{mnt}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` -### `Generator-com-p-lower` +### `Generator-maint-modstatus-lb` -`Generator_com_p_lower` +`Generator_maint_modstatus_lb` ```yaml -Generator_com_p_lower: - description: "`Generator-com-p-lower` — a committed unit outputs at least its minimum; off, at least nothing" +Generator_maint_modstatus_lb: + description: "`Generator-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" dims: [scenario, snapshot, generator] - where: Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) - expression: Generator_p >= Generator_p_min_pu * Generator_p_nom * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) + where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 + expression: Generator_maintenance_status >= Generator_status - Generator_p_nom_max / Generator_p_nom_mod * (1 - Generator_maintenance) ``` ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} - \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-com-p-upper` +### `Generator-maint-modstatus-le-maint` -`Generator_com_p_upper` +`Generator_maint_modstatus_le_maint` ```yaml -Generator_com_p_upper: - description: "`Generator-com-p-upper` — a committed unit outputs at most what is available; off, at most nothing" +Generator_maint_modstatus_le_maint: + description: >- + `Generator-maint-modstatus-le-maint` — out of maintenance, no module is on in + maintenance; in it, at most the modules the build cap holds dims: [scenario, snapshot, generator] - where: Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) - expression: Generator_p <= Generator_p_max_pu * Generator_p_nom * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) + where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 + expression: Generator_maintenance_status <= Generator_p_nom_max / Generator_p_nom_mod * Generator_maintenance ``` ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mu^{u}_{g,\xi,t} \le \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-com-transition-start-up` +### `Generator-maint-modstatus-le-status` -`Generator_com_transition_start_up` +`Generator_maint_modstatus_le_status` ```yaml -Generator_com_transition_start_up: - description: "`Generator-com-transition-start-up` — turning on is a start, counted against the state the unit carried into the snapshot" +Generator_maint_modstatus_le_status: + description: "`Generator-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" dims: [scenario, snapshot, generator] - where: Generator_committed - expression: Generator_start_up >= Generator_status - Generator_previous_status + where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 + expression: Generator_maintenance_status <= Generator_status ``` ```math -\mathit{up}_{g,\xi,t} \ge u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-com-transition-shut-down` +### `Generator-maint-start-horizon` -`Generator_com_transition_shut_down` +`Generator_maint_start_horizon` ```yaml -Generator_com_transition_shut_down: - description: "`Generator-com-transition-shut-down` — turning off is a stop, counted against the state the unit carried into the snapshot" +Generator_maint_start_horizon: + description: "`Generator-maint-start-horizon` — no event starts where it could not run its whole duration" dims: [scenario, snapshot, generator] - where: Generator_committed - expression: Generator_shut_down >= Generator_previous_status - Generator_status + where: Generator_maintainable AND Generator_active AND Generator_maintenance_start_blocked + expression: Generator_maintenance_start == 0 ``` ```math -\mathit{dn}_{g,\xi,t} \ge \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +\mu^{\mathrm{up}}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} \wedge \mathrm{blk}_{g,\xi,t} ``` -### `Generator-com-up-time` +### `Generator-maint-status-lb` -`Generator_com_up_time` +`Generator_maint_status_lb` ```yaml -Generator_com_up_time: - description: >- - `Generator-com-up-time` — a unit started within its own minimum up time - is still on. The first snapshot's share of the window is the brought-in - up time's, which the must-stay-up mask carries +Generator_maint_status_lb: + description: "`Generator-maint-status-lb` — on and in maintenance, the status in maintenance is one" dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_min_up_time > 0 AND position(snapshot) > 0 - expression: sum_back(Generator_start_up, along=snapshot, window=Generator_min_up_time) <= Generator_status + where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) + expression: Generator_maintenance_status >= Generator_status + Generator_maintenance - 1 ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}} \mathit{up}_{g,\xi,t'} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{UT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} + \mu_{g,\xi,t} - 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-com-down-time` +### `Generator-maint-status-le-maint` -`Generator_com_down_time` +`Generator_maint_status_le_maint` ```yaml -Generator_com_down_time: - description: >- - `Generator-com-down-time` — a unit stopped within its own minimum down - time is still off. The first snapshot's share of the window is the - brought-in down time's, which the must-stay-down mask carries +Generator_maint_status_le_maint: + description: "`Generator-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_min_down_time > 0 AND position(snapshot) > 0 - expression: sum_back(Generator_shut_down, along=snapshot, window=Generator_min_down_time) <= 1 - Generator_status + where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) + expression: Generator_maintenance_status <= Generator_maintenance ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}} \mathit{dn}_{g,\xi,t'} \le 1 - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{DT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +\mu^{u}_{g,\xi,t} \le \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-com-status-min_up_time_must_stay_up` +### `Generator-maint-status-le-status` -`Generator_com_status_must_stay_up` +`Generator_maint_status_le_status` ```yaml -Generator_com_status_must_stay_up: - description: "`Generator-com-status-min_up_time_must_stay_up` — a unit still serving the up time it brought in stays on" +Generator_maint_status_le_status: + description: "`Generator-maint-status-le-status` — the status in maintenance is at most the status" dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_must_stay_up - expression: Generator_status == 1 + where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) + expression: Generator_maintenance_status <= Generator_status ``` ```math -u_{g,\xi,t} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{hold}_{g,\xi,t} +\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-com-status-min_down_time_must_stay_up` +### `Generator-maint-window` -`Generator_com_status_must_stay_down` +`Generator_maint_window` ```yaml -Generator_com_status_must_stay_down: +Generator_maint_window: description: >- - `Generator-com-status-min_down_time_must_stay_up` — a unit still serving - the down time it brought in stays off; PyPSA names the row `_must_stay_up` + `Generator-maint-window` — a generator is in maintenance exactly where an event it + started covers the snapshot; two events do not overlap, since the + maintenance status is at most one dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_must_stay_down - expression: Generator_status == 0 + where: Generator_maintainable AND Generator_active + expression: Generator_maintenance == sum(Generator_maintenance_start, over=start, by=Generator_maintenance_cover[covered]) ``` ```math -u_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{rest}_{g,\xi,t} +\mu_{g,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ g,\ \xi,\ t' \right) \in \mathrm{Generator\_maintenance\_cover}} \mu^{\mathrm{up}}_{g,\xi,t'} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` -### `Generator-p-ramp_limit_up-run-bigM` +### `Generator-maintcap_lower_nommax` -`Generator_p_ramp_limit_up_run_big_m` +`Generator_maintcap_lower_nommax` ```yaml -Generator_p_ramp_limit_up_run_big_m: - description: >- - `Generator-p-ramp_limit_up-run-bigM` — a committed extendable unit - raises output no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns on +Generator_maintcap_lower_nommax: + description: "`Generator-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" dims: [scenario, snapshot, generator] - where: >- - Generator_com_ext - AND (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) - AND Generator_ramps_from_previous - expression: >- - Generator_p - Generator_previous_p <= - Generator_ramp_up_rate * Generator_p_nom_ext - + Generator_big_m - Generator_big_m * Generator_previous_status + where: Generator_maint_ext + expression: Generator_maintenance_capacity >= Generator_p_nom_ext - Generator_p_nom_max * (1 - Generator_maintenance) ``` ```math -p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +\mu^{\mathrm{nom}}_{g,\xi,t} \ge P_{g} - \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -### `Generator-p-ramp_limit_up-start-bigM` +### `Generator-maintcap_lower_nommin` -`Generator_p_ramp_limit_up_start_big_m` +`Generator_maintcap_lower_nommin` ```yaml -Generator_p_ramp_limit_up_start_big_m: - description: >- - `Generator-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a - committed extendable unit ramps no further than its start-up ramp of - the chosen build; the big M releases the row everywhere else +Generator_maintcap_lower_nommin: + description: "`Generator-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" dims: [scenario, snapshot, generator] - where: >- - Generator_com_ext - AND (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) - AND Generator_ramps_from_previous - expression: >- - Generator_p - Generator_previous_p <= - Generator_start_up_rate * Generator_p_nom_ext - + Generator_big_m - Generator_big_m * Generator_start_up + where: Generator_maint_ext AND Generator_p_nom_min > 0 + expression: Generator_maintenance_capacity >= Generator_p_nom_min * Generator_maintenance ``` ```math -p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{up}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +\mu^{\mathrm{nom}}_{g,\xi,t} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} \wedge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} > 0 ``` -### `Generator-p-ramp_limit_down-run-bigM` +### `Generator-maintcap_upper` -`Generator_p_ramp_limit_down_run_big_m` +`Generator_maintcap_upper` ```yaml -Generator_p_ramp_limit_down_run_big_m: +Generator_maintcap_upper: description: >- - `Generator-p-ramp_limit_down-run-bigM` — a committed extendable unit - lowers output no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns off + `Generator-maintcap_upper` — the build taken off is at most the chosen build in + maintenance, and at most the build less its floor out of it dims: [scenario, snapshot, generator] - where: >- - Generator_com_ext - AND (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) - AND Generator_ramps_from_previous - expression: >- - Generator_previous_p - Generator_p <= - Generator_ramp_down_rate * Generator_p_nom_ext - + Generator_big_m - Generator_big_m * Generator_status + where: Generator_maint_ext + expression: Generator_maintenance_capacity <= Generator_p_nom_ext - Generator_p_nom_min * (1 - Generator_maintenance) ``` ```math -\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +\mu^{\mathrm{nom}}_{g,\xi,t} \le P_{g} - \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -### `Generator-p-ramp_limit_down-shut-bigM` +### `Generator-maintcap_upper_nommax` -`Generator_p_ramp_limit_down_shut_big_m` +`Generator_maintcap_upper_nommax` ```yaml -Generator_p_ramp_limit_down_shut_big_m: - description: >- - `Generator-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, - a committed extendable unit ramps no further than its shut-down ramp of - the chosen build; the big M releases the row everywhere else +Generator_maintcap_upper_nommax: + description: "`Generator-maintcap_upper_nommax` — out of maintenance, no build is taken off" dims: [scenario, snapshot, generator] - where: >- - Generator_com_ext - AND (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) - AND Generator_ramps_from_previous - expression: >- - Generator_previous_p - Generator_p <= - Generator_shut_down_rate * Generator_p_nom_ext - + Generator_big_m - Generator_big_m * Generator_shut_down + where: Generator_maint_ext + expression: Generator_maintenance_capacity <= Generator_p_nom_max * Generator_maintenance ``` ```math -\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{dn}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +\mu^{\mathrm{nom}}_{g,\xi,t} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` ### `Generator-p_nom_modularity` @@ -8973,152 +8940,188 @@ Generator_p_nom_modularity: P_{g} = \mathrm{p}^{\mathrm{mod}}_{g} \cdot N_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \wedge \mathrm{act}_{g} ``` -### `Generator-com-ext-p-upper-cap` +### `Generator-p_nom_set` -`Generator_com_ext_p_upper_cap` +`Generator_p_nom_set` ```yaml -Generator_com_ext_p_upper_cap: - description: >- - `Generator-com-ext-p-upper-cap` — a committed extendable unit outputs - at most what is available of the chosen build, whatever its status - dims: [scenario, snapshot, generator] - where: Generator_com_ext - expression: Generator_p <= Generator_p_max_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) +Generator_p_nom_set: + description: "`Generator-p_nom_set` — the chosen build pinned, wherever a value is given" + dims: [generator] + where: Generator_p_nom_extendable AND Generator_active_asset AND Generator_p_nom_set + expression: Generator_p_nom_ext == Generator_p_nom_set ``` ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +P_{g} = \mathrm{p}^{\mathrm{nom,set}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \mathrm{p}^{\mathrm{nom,set}}_{g} \text{ is defined} ``` -### `Generator-com-ext-p-upper-bigM` +### `Generator-p-ramp_limit_down` -`Generator_com_ext_p_upper_big_m` +`Generator_p_ramp_limit_down` ```yaml -Generator_com_ext_p_upper_big_m: - description: "`Generator-com-ext-p-upper-bigM` — off, a unit outputs nothing; on, the big M is no bound" +Generator_p_ramp_limit_down: + description: >- + `Generator-p-ramp_limit_down` — a generator lowers output no faster than + its ramp limit of the build, and a committed one no further than its + shut-down ramp in the snapshot it turns off. A unit that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the output it brought in, and no unit carries one at + the start of a later investment period — nor does any unit a big M releases instead dims: [scenario, snapshot, generator] - where: Generator_com_ext - expression: Generator_p <= Generator_big_m * Generator_status + where: >- + (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) + AND NOT (Generator_committable AND Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0)) + AND Generator_ramps_from_previous + AND Generator_active + expression: Generator_previous_p - Generator_p <= Generator_ramp_down_allowance ``` ```math -p_{g,\xi,t} \le \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \Delta^{-}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} ``` -### `Generator-com-ext-p-lower` +### `Generator-p-ramp_limit_down-run-bigM` -`Generator_com_ext_p_lower` +`Generator_p_ramp_limit_down_run_big_m` ```yaml -Generator_com_ext_p_lower: +Generator_p_ramp_limit_down_run_big_m: description: >- - `Generator-com-ext-p-lower` — a committed extendable unit outputs at - least its minimum of the chosen build; off, the big M releases the row + `Generator-p-ramp_limit_down-run-bigM` — a committed extendable unit + lowers output no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns off dims: [scenario, snapshot, generator] - where: Generator_com_ext + where: >- + Generator_com_ext + AND (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) + AND Generator_ramps_from_previous expression: >- - Generator_p >= - Generator_p_min_pu * (Generator_p_nom_ext - Generator_maintenance_pu * Generator_maintenance_capacity) - + Generator_big_m * Generator_status - Generator_big_m + Generator_previous_p - Generator_p <= + Generator_ramp_down_rate * Generator_p_nom_ext + + Generator_big_m - Generator_big_m * Generator_status ``` ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) + \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} - \mathrm{M}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} ``` -### `Generator-com-ext-p-lower-nonneg` +### `Generator-p-ramp_limit_down-shut-bigM` -`Generator_com_ext_p_lower_nonneg` +`Generator_p_ramp_limit_down_shut_big_m` ```yaml -Generator_com_ext_p_lower_nonneg: +Generator_p_ramp_limit_down_shut_big_m: description: >- - `Generator-com-ext-p-lower-nonneg` — where no minimum-per-unit is - negative, output is also plainly non-negative, a row the big-M lower - cannot assert while the unit is off + `Generator-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, + a committed extendable unit ramps no further than its shut-down ramp of + the chosen build; the big M releases the row everywhere else dims: [scenario, snapshot, generator] - where: Generator_com_ext AND Generator_p_min_pu_nonneg - expression: Generator_p >= 0 + where: >- + Generator_com_ext + AND (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) + AND Generator_ramps_from_previous + expression: >- + Generator_previous_p - Generator_p <= + Generator_shut_down_rate * Generator_p_nom_ext + + Generator_big_m - Generator_big_m * Generator_shut_down ``` ```math -p_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \mathrm{nonneg}_{g} +\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{dn}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} ``` -### `Generator-com-mod-p-lower` +### `Generator-p-ramp_limit_up` -`Generator_com_mod_p_lower` +`Generator_p_ramp_limit_up` ```yaml -Generator_com_mod_p_lower: +Generator_p_ramp_limit_up: description: >- - `Generator-com-mod-p-lower` — a committed modular unit outputs at least - its minimum of one module, whether the build is fixed or a decision + `Generator-p-ramp_limit_up` — a generator raises output no faster than + its ramp limit of the build, and a committed one no further than its + start-up ramp in the snapshot it turns on. A unit that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the output it brought in, and no unit carries one at + the start of a later investment period — nor does any unit a big M releases instead dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_p_nom_mod > 0 - expression: Generator_p >= Generator_p_min_pu * Generator_p_nom_mod * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) + where: >- + (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) + AND NOT (Generator_committable AND Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0)) + AND Generator_ramps_from_previous + AND Generator_active + expression: Generator_p - Generator_previous_p <= Generator_ramp_up_allowance ``` ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \Delta^{+}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} ``` -### `Generator-com-mod-p-upper` +### `Generator-p-ramp_limit_up-run-bigM` -`Generator_com_mod_p_upper` +`Generator_p_ramp_limit_up_run_big_m` ```yaml -Generator_com_mod_p_upper: +Generator_p_ramp_limit_up_run_big_m: description: >- - `Generator-com-mod-p-upper` — a committed modular unit outputs at most - one module's share, whether the build is fixed or a decision + `Generator-p-ramp_limit_up-run-bigM` — a committed extendable unit + raises output no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns on dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_p_nom_mod > 0 - expression: Generator_p <= Generator_p_max_pu * Generator_p_nom_mod * (Generator_status - Generator_maintenance_pu * Generator_maintenance_status) + where: >- + Generator_com_ext + AND (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) + AND Generator_ramps_from_previous + expression: >- + Generator_p - Generator_previous_p <= + Generator_ramp_up_rate * Generator_p_nom_ext + + Generator_big_m - Generator_big_m * Generator_previous_status ``` ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} ``` -### `Generator-status-p-fixed-upper` +### `Generator-p-ramp_limit_up-start-bigM` -`Generator_status_p_fixed_upper` +`Generator_p_ramp_limit_up_start_big_m` ```yaml -Generator_status_p_fixed_upper: +Generator_p_ramp_limit_up_start_big_m: description: >- - `Generator-status-p-fixed-upper` — a status is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is + `Generator-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a + committed extendable unit ramps no further than its start-up ramp of + the chosen build; the big M releases the row everywhere else dims: [scenario, snapshot, generator] - where: Generator_committed AND NOT (Generator_p_nom_extendable AND Generator_p_nom_mod > 0) - expression: Generator_status <= Generator_modules_installed + where: >- + Generator_com_ext + AND (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) + AND Generator_ramps_from_previous + expression: >- + Generator_p - Generator_previous_p <= + Generator_start_up_rate * Generator_p_nom_ext + + Generator_big_m - Generator_big_m * Generator_start_up ``` ```math -u_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{up}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} ``` -### `Generator-start_up-p-fixed-upper` +### `Generator-p_set` -`Generator_start_up_p_fixed_upper` +`Generator_p_set` ```yaml -Generator_start_up_p_fixed_upper: - description: >- - `Generator-start_up-p-fixed-upper` — a start is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is +Generator_p_set: + description: "`Generator-p_set` — output pinned to the given schedule, wherever one is given" dims: [scenario, snapshot, generator] - where: Generator_committed AND NOT (Generator_p_nom_extendable AND Generator_p_nom_mod > 0) - expression: Generator_start_up <= Generator_modules_installed + where: Generator_p_set AND Generator_active + expression: Generator_p == Generator_p_set ``` ```math -\mathit{up}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +p_{g,\xi,t} = \mathrm{p}^{\mathrm{set}}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{set}}_{g,\xi,t} \text{ is defined} \wedge \mathrm{on}_{g,t} ``` ### `Generator-shut_down-p-fixed-upper` @@ -9140,38 +9143,6 @@ Generator_shut_down_p_fixed_upper: \mathit{dn}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-status-p_nom-variable-upper` - -`Generator_status_p_nom_variable_upper` - -```yaml -Generator_status_p_nom_variable_upper: - description: "`Generator-status-p_nom-variable-upper` — a modular unit is on only where a module is built" - dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 - expression: Generator_status <= Generator_n_mod -``` - -```math -u_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 -``` - -### `Generator-start_up-p_nom-variable-upper` - -`Generator_start_up_p_nom_variable_upper` - -```yaml -Generator_start_up_p_nom_variable_upper: - description: "`Generator-start_up-p_nom-variable-upper` — a modular unit starts only where a module is built" - dims: [scenario, snapshot, generator] - where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 - expression: Generator_start_up <= Generator_n_mod -``` - -```math -\mathit{up}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 -``` - ### `Generator-shut_down-p_nom-variable-upper` `Generator_shut_down_p_nom_variable_upper` @@ -9188,2440 +9159,2396 @@ Generator_shut_down_p_nom_variable_upper: \mathit{dn}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-maint-event-count` +### `Generator-start_up-p-fixed-upper` -`Generator_maint_event_count` +`Generator_start_up_p_fixed_upper` ```yaml -Generator_maint_event_count: - description: "`Generator-maint-event-count` — a maintainable generator holds its number of maintenance events over the horizon" - dims: [scenario, generator] - where: Generator_maintainable - expression: sum(Generator_maintenance_start, over=snapshot) == Generator_maintenance_events +Generator_start_up_p_fixed_upper: + description: >- + `Generator-start_up-p-fixed-upper` — a start is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, generator] + where: Generator_committed AND NOT (Generator_p_nom_extendable AND Generator_p_nom_mod > 0) + expression: Generator_start_up <= Generator_modules_installed ``` ```math -\sum_{t \in \mathcal{T}} \mu^{\mathrm{up}}_{g,\xi,t} = \mathrm{n}^{\mathrm{mnt}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\mathit{up}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-maint-window` +### `Generator-start_up-p_nom-variable-upper` -`Generator_maint_window` +`Generator_start_up_p_nom_variable_upper` ```yaml -Generator_maint_window: - description: >- - `Generator-maint-window` — a generator is in maintenance exactly where an event it - started covers the snapshot; two events do not overlap, since the - maintenance status is at most one +Generator_start_up_p_nom_variable_upper: + description: "`Generator-start_up-p_nom-variable-upper` — a modular unit starts only where a module is built" dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_active - expression: Generator_maintenance == sum(Generator_maintenance_start, over=start, by=Generator_maintenance_cover[covered]) + where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 + expression: Generator_start_up <= Generator_n_mod ``` ```math -\mu_{g,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ g,\ \xi,\ t' \right) \in \mathrm{Generator\_maintenance\_cover}} \mu^{\mathrm{up}}_{g,\xi,t'} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} +\mathit{up}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-maint-start-horizon` +### `Generator-status-p-fixed-upper` -`Generator_maint_start_horizon` +`Generator_status_p_fixed_upper` ```yaml -Generator_maint_start_horizon: - description: "`Generator-maint-start-horizon` — no event starts where it could not run its whole duration" +Generator_status_p_fixed_upper: + description: >- + `Generator-status-p-fixed-upper` — a status is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_active AND Generator_maintenance_start_blocked - expression: Generator_maintenance_start == 0 + where: Generator_committed AND NOT (Generator_p_nom_extendable AND Generator_p_nom_mod > 0) + expression: Generator_status <= Generator_modules_installed ``` ```math -\mu^{\mathrm{up}}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} \wedge \mathrm{blk}_{g,\xi,t} +u_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -### `Generator-maintcap_upper` +### `Generator-status-p_nom-variable-upper` -`Generator_maintcap_upper` +`Generator_status_p_nom_variable_upper` ```yaml -Generator_maintcap_upper: - description: >- - `Generator-maintcap_upper` — the build taken off is at most the chosen build in - maintenance, and at most the build less its floor out of it +Generator_status_p_nom_variable_upper: + description: "`Generator-status-p_nom-variable-upper` — a modular unit is on only where a module is built" dims: [scenario, snapshot, generator] - where: Generator_maint_ext - expression: Generator_maintenance_capacity <= Generator_p_nom_ext - Generator_p_nom_min * (1 - Generator_maintenance) + where: Generator_committed AND Generator_p_nom_extendable AND Generator_p_nom_mod > 0 + expression: Generator_status <= Generator_n_mod ``` ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \le P_{g} - \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +u_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -### `Generator-maintcap_upper_nommax` +### `operational_limit` -`Generator_maintcap_upper_nommax` +`GlobalConstraint_operational_limit_eq` ```yaml -Generator_maintcap_upper_nommax: - description: "`Generator-maintcap_upper_nommax` — out of maintenance, no build is taken off" - dims: [scenario, snapshot, generator] - where: Generator_maint_ext - expression: Generator_maintenance_capacity <= Generator_p_nom_max * Generator_maintenance +GlobalConstraint_operational_limit_eq: + description: "`operational_limit` — its total, at its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '==' + expression: operational_limit == GlobalConstraint_constant ``` ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mathit{operational\_limit}_{l,\xi} = \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{==}\text{'} ``` -### `Generator-maintcap_lower_nommax` +### `operational_limit` -`Generator_maintcap_lower_nommax` +`GlobalConstraint_operational_limit_lb` ```yaml -Generator_maintcap_lower_nommax: - description: "`Generator-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" - dims: [scenario, snapshot, generator] - where: Generator_maint_ext - expression: Generator_maintenance_capacity >= Generator_p_nom_ext - Generator_p_nom_max * (1 - Generator_maintenance) +GlobalConstraint_operational_limit_lb: + description: "`operational_limit` — its total, at least its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '>=' + expression: operational_limit >= GlobalConstraint_constant ``` ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge P_{g} - \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mathit{operational\_limit}_{l,\xi} \ge \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{>=}\text{'} ``` -### `Generator-maintcap_lower_nommin` - -`Generator_maintcap_lower_nommin` +### `operational_limit` -```yaml -Generator_maintcap_lower_nommin: - description: "`Generator-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" - dims: [scenario, snapshot, generator] - where: Generator_maint_ext AND Generator_p_nom_min > 0 - expression: Generator_maintenance_capacity >= Generator_p_nom_min * Generator_maintenance +`GlobalConstraint_operational_limit_ub` + +```yaml +GlobalConstraint_operational_limit_ub: + description: "`operational_limit` — its total, at most its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '<=' + expression: operational_limit <= GlobalConstraint_constant ``` ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} \wedge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} > 0 +\mathit{operational\_limit}_{l,\xi} \le \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{<=}\text{'} ``` -### `Generator-maint-status-le-status` +### `primary_energy` -`Generator_maint_status_le_status` +`GlobalConstraint_primary_energy_eq` ```yaml -Generator_maint_status_le_status: - description: "`Generator-maint-status-le-status` — the status in maintenance is at most the status" - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) - expression: Generator_maintenance_status <= Generator_status +GlobalConstraint_primary_energy_eq: + description: "`primary_energy` — its total, at its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '==' + expression: primary_energy == GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{primary\_energy}_{l,\xi} = \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{==}\text{'} ``` -### `Generator-maint-status-le-maint` +### `primary_energy` -`Generator_maint_status_le_maint` +`GlobalConstraint_primary_energy_lb` ```yaml -Generator_maint_status_le_maint: - description: "`Generator-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) - expression: Generator_maintenance_status <= Generator_maintenance +GlobalConstraint_primary_energy_lb: + description: "`primary_energy` — its total, at least its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '>=' + expression: primary_energy >= GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \le \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{primary\_energy}_{l,\xi} \ge \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{>=}\text{'} ``` -### `Generator-maint-status-lb` +### `primary_energy` -`Generator_maint_status_lb` +`GlobalConstraint_primary_energy_ub` ```yaml -Generator_maint_status_lb: - description: "`Generator-maint-status-lb` — on and in maintenance, the status in maintenance is one" - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND NOT Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0) - expression: Generator_maintenance_status >= Generator_status + Generator_maintenance - 1 +GlobalConstraint_primary_energy_ub: + description: "`primary_energy` — its total, at most its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '<=' + expression: primary_energy <= GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} + \mu_{g,\xi,t} - 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{primary\_energy}_{l,\xi} \le \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{<=}\text{'} ``` -### `Generator-maint-modstatus-le-status` +### `tech_capacity_expansion_limit` -`Generator_maint_modstatus_le_status` +`GlobalConstraint_tech_capacity_expansion_limit_eq` ```yaml -Generator_maint_modstatus_le_status: - description: "`Generator-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 - expression: Generator_maintenance_status <= Generator_status +GlobalConstraint_tech_capacity_expansion_limit_eq: + description: "`tech_capacity_expansion_limit` — its total, at its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '==' + expression: tech_capacity_expansion == GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mathit{tech\_capacity\_expansion}_{l} = \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{==}\text{'} ``` -### `Generator-maint-modstatus-le-maint` +### `tech_capacity_expansion_limit` -`Generator_maint_modstatus_le_maint` +`GlobalConstraint_tech_capacity_expansion_limit_lb` ```yaml -Generator_maint_modstatus_le_maint: - description: >- - `Generator-maint-modstatus-le-maint` — out of maintenance, no module is on in - maintenance; in it, at most the modules the build cap holds - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 - expression: Generator_maintenance_status <= Generator_p_nom_max / Generator_p_nom_mod * Generator_maintenance +GlobalConstraint_tech_capacity_expansion_limit_lb: + description: "`tech_capacity_expansion_limit` — its total, at least its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '>=' + expression: tech_capacity_expansion >= GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \le \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mathit{tech\_capacity\_expansion}_{l} \ge \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{>=}\text{'} ``` -### `Generator-maint-modstatus-lb` +### `tech_capacity_expansion_limit` -`Generator_maint_modstatus_lb` +`GlobalConstraint_tech_capacity_expansion_limit_ub` ```yaml -Generator_maint_modstatus_lb: - description: "`Generator-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" - dims: [scenario, snapshot, generator] - where: Generator_maintainable AND Generator_committed AND Generator_p_nom_mod > 0 - expression: Generator_maintenance_status >= Generator_status - Generator_p_nom_max / Generator_p_nom_mod * (1 - Generator_maintenance) +GlobalConstraint_tech_capacity_expansion_limit_ub: + description: "`tech_capacity_expansion_limit` — its total, at most its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '<=' + expression: tech_capacity_expansion <= GlobalConstraint_constant ``` ```math -\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} - \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mathit{tech\_capacity\_expansion}_{l} \le \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{<=}\text{'} ``` -### `Link-com-p-lower` +### `transmission_expansion_cost_limit` -`Link_com_p_lower` +`GlobalConstraint_transmission_expansion_cost_limit_eq` ```yaml -Link_com_p_lower: - description: "`Link-com-p-lower` — a committed link flows at least its minimum; off, at least nothing" - dims: [scenario, snapshot, link] - where: Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) - expression: Link_p >= Link_p_min_pu * Link_p_nom * (Link_status - Link_maintenance_pu * Link_maintenance_status) +GlobalConstraint_transmission_expansion_cost_limit_eq: + description: "`transmission_expansion_cost_limit` — its total, at its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '==' + expression: transmission_expansion_cost == GlobalConstraint_constant ``` ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mathit{transmission\_expansion\_cost}_{l,\xi} = \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{==}\text{'} ``` -### `Link-com-p-upper` +### `transmission_expansion_cost_limit` -`Link_com_p_upper` +`GlobalConstraint_transmission_expansion_cost_limit_lb` ```yaml -Link_com_p_upper: - description: "`Link-com-p-upper` — a committed link flows at most what is available; off, at most nothing" - dims: [scenario, snapshot, link] - where: Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) - expression: Link_p <= Link_p_max_pu * Link_p_nom * (Link_status - Link_maintenance_pu * Link_maintenance_status) +GlobalConstraint_transmission_expansion_cost_limit_lb: + description: "`transmission_expansion_cost_limit` — its total, at least its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '>=' + expression: transmission_expansion_cost >= GlobalConstraint_constant ``` ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mathit{transmission\_expansion\_cost}_{l,\xi} \ge \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{>=}\text{'} ``` -### `Link-com-transition-start-up` +### `transmission_expansion_cost_limit` -`Link_com_transition_start_up` +`GlobalConstraint_transmission_expansion_cost_limit_ub` ```yaml -Link_com_transition_start_up: - description: "`Link-com-transition-start-up` — turning on is a start, counted against the state the link carried into the snapshot" - dims: [scenario, snapshot, link] - where: Link_committed - expression: Link_start_up >= Link_status - Link_previous_status +GlobalConstraint_transmission_expansion_cost_limit_ub: + description: "`transmission_expansion_cost_limit` — its total, at most its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '<=' + expression: transmission_expansion_cost <= GlobalConstraint_constant ``` ```math -\mathit{up}^{f}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +\mathit{transmission\_expansion\_cost}_{l,\xi} \le \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{<=}\text{'} ``` -### `Link-com-transition-shut-down` +### `transmission_volume_expansion_limit` -`Link_com_transition_shut_down` +`GlobalConstraint_transmission_volume_expansion_limit_eq` ```yaml -Link_com_transition_shut_down: - description: "`Link-com-transition-shut-down` — turning off is a stop, counted against the state the link carried into the snapshot" - dims: [scenario, snapshot, link] - where: Link_committed - expression: Link_shut_down >= Link_previous_status - Link_status +GlobalConstraint_transmission_volume_expansion_limit_eq: + description: "`transmission_volume_expansion_limit` — its total, at its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '==' + expression: transmission_volume_expansion == GlobalConstraint_constant ``` ```math -\mathit{dn}^{f}_{l,\xi,t} \ge \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +\mathit{transmission\_volume\_expansion}_{l,\xi} = \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{==}\text{'} ``` -### `Link-com-up-time` +### `transmission_volume_expansion_limit` -`Link_com_up_time` +`GlobalConstraint_transmission_volume_expansion_limit_lb` ```yaml -Link_com_up_time: - description: >- - `Link-com-up-time` — a link started within its own minimum up time - is still on. The first snapshot's share of the window is the brought-in - up time's, which the must-stay-up mask carries - dims: [scenario, snapshot, link] - where: Link_committed AND Link_min_up_time > 0 AND position(snapshot) > 0 - expression: sum_back(Link_start_up, along=snapshot, window=Link_min_up_time) <= Link_status +GlobalConstraint_transmission_volume_expansion_limit_lb: + description: "`transmission_volume_expansion_limit` — its total, at least its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '>=' + expression: transmission_volume_expansion >= GlobalConstraint_constant ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{f}} \mathit{up}^{f}_{l,\xi,t'} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{UT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +\mathit{transmission\_volume\_expansion}_{l,\xi} \ge \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{>=}\text{'} ``` -### `Link-com-down-time` +### `transmission_volume_expansion_limit` -`Link_com_down_time` +`GlobalConstraint_transmission_volume_expansion_limit_ub` ```yaml -Link_com_down_time: - description: >- - `Link-com-down-time` — a link stopped within its own minimum down - time is still off. The first snapshot's share of the window is the - brought-in down time's, which the must-stay-down mask carries - dims: [scenario, snapshot, link] - where: Link_committed AND Link_min_down_time > 0 AND position(snapshot) > 0 - expression: sum_back(Link_shut_down, along=snapshot, window=Link_min_down_time) <= 1 - Link_status +GlobalConstraint_transmission_volume_expansion_limit_ub: + description: "`transmission_volume_expansion_limit` — its total, at most its constant" + dims: [scenario, global_constraint] + where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '<=' + expression: transmission_volume_expansion <= GlobalConstraint_constant ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{f}} \mathit{dn}^{f}_{l,\xi,t'} \le 1 - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{DT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +\mathit{transmission\_volume\_expansion}_{l,\xi} \le \mathrm{K}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{type}_{l} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{l,\xi} = \text{'}\mathrm{<=}\text{'} ``` -### `Link-com-status-min_up_time_must_stay_up` +### `Kirchhoff-Voltage-Law` -`Link_com_status_must_stay_up` +`Kirchhoff_Voltage_Law` ```yaml -Link_com_status_must_stay_up: - description: "`Link-com-status-min_up_time_must_stay_up` — a link still serving the up time it brought in stays on" - dims: [scenario, snapshot, link] - where: Link_committed AND Link_must_stay_up - expression: Link_status == 1 +Kirchhoff_Voltage_Law: + description: >- + `Kirchhoff-Voltage-Law` — around every independent cycle the + impedance-weighted flows sum to nothing, which is what makes the linear + power flow physical rather than transport. A transformer's flow weighs its + effective reactance, and its phase shift enters the cycle sum too: a + constant where the shift is fixed, or the shift decision times its cycle + weight where the shift is a phase-shifting transformer's to choose. A + snapshot reads the cycles of its own period, of the branches that stand + in it (`constraints.py:1622-1638`); a cycle label that period's basis + does not reach has no row + dims: [scenario, snapshot, cycle] + expression: Cycle_angle_sum == 0 ``` ```math -u^{f}_{l,\xi,t} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{hold}^{f}_{l,\xi,t} +\sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} + \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} = 0 \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -### `Link-com-status-min_down_time_must_stay_up` +### `Line-ext-s-lower` -`Link_com_status_must_stay_down` +`Line_ext_s_lower` ```yaml -Link_com_status_must_stay_down: - description: >- - `Link-com-status-min_down_time_must_stay_up` — a link still serving - the down time it brought in stays off; PyPSA names the row `_must_stay_up` - dims: [scenario, snapshot, link] - where: Link_committed AND Link_must_stay_down - expression: Link_status == 0 +Line_ext_s_lower: + description: "`Line-ext-s-lower` — an extendable line carries at least the negative of its rating of the chosen build, the loss counted against it" + dims: [scenario, snapshot, line] + where: Line_s_nom_extendable AND Line_active + expression: Line_s - Line_loss >= -Line_s_max_pu * Line_s_nom_ext ``` ```math -u^{f}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{rest}^{f}_{l,\xi,t} +s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-p-ramp_limit_up-run-bigM` +### `Line-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` -`Link_p_ramp_limit_up_run_big_m` +`Line_ext_s_lower_security` ```yaml -Link_p_ramp_limit_up_run_big_m: +Line_ext_s_lower_security: description: >- - `Link-p-ramp_limit_up-run-bigM` — a committed extendable link - raises flow no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns on - dims: [scenario, snapshot, link] - where: Link_com_ext AND (Link_ramp_limit_up OR Link_ramp_limit_start_up) AND Link_ramps_from_previous - expression: >- - Link_p - Link_previous_p <= - Link_ramp_up_rate * Link_p_nom_ext - + Link_big_m - Link_big_m * Link_previous_status + `Line-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` — + after any one outage, an extendable line carries at least the + negative of its rating of the chosen build: its flow takes on its + share of the outaged branch's flow. PyPSA names one row per + outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, line, outage] + where: Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) + expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s >= -Line_s_max_pu * Line_s_nom_ext ``` ```math -f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -### `Link-p-ramp_limit_up-start-bigM` +### `Line-ext-s_nom-lower` -`Link_p_ramp_limit_up_start_big_m` +`Line_ext_s_nom_lower` ```yaml -Link_p_ramp_limit_up_start_big_m: - description: >- - `Link-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a - committed extendable link ramps no further than its start-up ramp of - the chosen build; the big M releases the row everywhere else - dims: [scenario, snapshot, link] - where: Link_com_ext AND (Link_ramp_limit_up OR Link_ramp_limit_start_up) AND Link_ramps_from_previous - expression: >- - Link_p - Link_previous_p <= - Link_start_up_rate * Link_p_nom_ext - + Link_big_m - Link_big_m * Link_start_up +Line_ext_s_nom_lower: + description: "`Line-ext-s_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, line] + where: Line_s_nom_extendable AND Line_active_asset + expression: Line_s_nom_ext >= Line_s_nom_min ``` ```math -f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{up}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +S_{k} \ge \underline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} ``` -### `Link-p-ramp_limit_down-run-bigM` +### `Line-ext-s_nom-upper` -`Link_p_ramp_limit_down_run_big_m` +`Line_ext_s_nom_upper` ```yaml -Link_p_ramp_limit_down_run_big_m: - description: >- - `Link-p-ramp_limit_down-run-bigM` — a committed extendable link - lowers flow no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns off - dims: [scenario, snapshot, link] - where: Link_com_ext AND (Link_ramp_limit_down OR Link_ramp_limit_shut_down) AND Link_ramps_from_previous - expression: >- - Link_previous_p - Link_p <= - Link_ramp_down_rate * Link_p_nom_ext - + Link_big_m - Link_big_m * Link_status +Line_ext_s_nom_upper: + description: "`Line-ext-s_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, line] + where: Line_s_nom_extendable AND Line_active_asset AND Line_s_nom_max + expression: Line_s_nom_ext <= Line_s_nom_max ``` ```math -\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +S_{k} \le \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \text{ is defined} ``` -### `Link-p-ramp_limit_down-shut-bigM` +### `Line-ext-s-upper` -`Link_p_ramp_limit_down_shut_big_m` +`Line_ext_s_upper` ```yaml -Link_p_ramp_limit_down_shut_big_m: - description: >- - `Link-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, - a committed extendable link ramps no further than its shut-down ramp of - the chosen build; the big M releases the row everywhere else - dims: [scenario, snapshot, link] - where: Link_com_ext AND (Link_ramp_limit_down OR Link_ramp_limit_shut_down) AND Link_ramps_from_previous - expression: >- - Link_previous_p - Link_p <= - Link_shut_down_rate * Link_p_nom_ext - + Link_big_m - Link_big_m * Link_shut_down +Line_ext_s_upper: + description: "`Line-ext-s-upper` — an extendable line carries at most its rating of the chosen build, the loss included" + dims: [scenario, snapshot, line] + where: Line_s_nom_extendable AND Line_active + expression: Line_s + Line_loss <= Line_s_max_pu * Line_s_nom_ext ``` ```math -\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{dn}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-p_nom_modularity` +### `Line-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` -`Link_p_nom_modularity` +`Line_ext_s_upper_security` ```yaml -Link_p_nom_modularity: - description: "`Link-p_nom_modularity` — the chosen build is a whole number of modules" - dims: [link] - where: Link_p_nom_extendable AND Link_p_nom_mod > 0 AND Link_active_asset - expression: Link_p_nom_ext == Link_p_nom_mod * Link_n_mod +Line_ext_s_upper_security: + description: >- + `Line-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` — + after any one outage, an extendable line carries at most its rating + of the chosen build: its flow takes on its share of the outaged + branch's flow. PyPSA names one row per outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, line, outage] + where: Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) + expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s <= Line_s_max_pu * Line_s_nom_ext ``` ```math -F_{l} = \mathrm{f}^{\mathrm{mod}}_{l} \cdot N^{f}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -### `Link-com-ext-p-upper-cap` +### `Line-fix-s-lower` -`Link_com_ext_p_upper_cap` +`Line_fix_s_lower` ```yaml -Link_com_ext_p_upper_cap: - description: >- - `Link-com-ext-p-upper-cap` — a committed extendable link flows - at most what is available of the chosen build, whatever its status - dims: [scenario, snapshot, link] - where: Link_com_ext - expression: Link_p <= Link_p_max_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) +Line_fix_s_lower: + description: "`Line-fix-s-lower` — a fixed line carries at least the negative of its rating, the loss counted against it" + dims: [scenario, snapshot, line] + where: not Line_s_nom_extendable AND Line_active + expression: Line_s - Line_loss >= -Line_s_max_pu * Line_s_nom ``` ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-com-ext-p-upper-bigM` +### `Line-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` -`Link_com_ext_p_upper_big_m` +`Line_fix_s_lower_security` ```yaml -Link_com_ext_p_upper_big_m: - description: "`Link-com-ext-p-upper-bigM` — off, a link flows nothing; on, the big M is no bound" - dims: [scenario, snapshot, link] - where: Link_com_ext - expression: Link_p <= Link_big_m * Link_status +Line_fix_s_lower_security: + description: >- + `Line-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` — + after any one outage, a fixed line carries at least the negative + of its rating: its flow takes on its share of the outaged branch's + flow. PyPSA names one row per outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, line, outage] + where: not Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) + expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s >= -Line_s_max_pu * Line_s_nom ``` ```math -f_{l,\xi,t} \le \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -### `Link-com-ext-p-lower` +### `Line-fix-s-upper` -`Link_com_ext_p_lower` +`Line_fix_s_upper` ```yaml -Link_com_ext_p_lower: - description: >- - `Link-com-ext-p-lower` — a committed extendable link flows at - least its minimum of the chosen build; off, the big M releases the row - dims: [scenario, snapshot, link] - where: Link_com_ext - expression: >- - Link_p >= - Link_p_min_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) - + Link_big_m * Link_status - Link_big_m +Line_fix_s_upper: + description: "`Line-fix-s-upper` — a fixed line carries at most its rating, the loss included" + dims: [scenario, snapshot, line] + where: not Line_s_nom_extendable AND Line_active + expression: Line_s + Line_loss <= Line_s_max_pu * Line_s_nom ``` ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) + \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} - \mathrm{M}^{f}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-com-ext-p-lower-nonneg` +### `Line-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` -`Link_com_ext_p_lower_nonneg` +`Line_fix_s_upper_security` ```yaml -Link_com_ext_p_lower_nonneg: +Line_fix_s_upper_security: description: >- - `Link-com-ext-p-lower-nonneg` — where no minimum-per-unit is - negative, flow is also plainly non-negative, a row the big-M lower - cannot assert while the link is off - dims: [scenario, snapshot, link] - where: Link_com_ext AND Link_p_min_pu_nonneg - expression: Link_p >= 0 + `Line-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` — + after any one outage, a fixed line carries at most its rating: its + flow takes on its share of the outaged branch's flow. PyPSA names + one row per outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, line, outage] + where: not Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) + expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s <= Line_s_max_pu * Line_s_nom ``` ```math -f_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \mathrm{nonneg}^{f}_{l} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -### `Link-com-mod-p-lower` +### `Line-loss_tangents-{k}-1` -`Link_com_mod_p_lower` +`Line_loss_tangents_forward` ```yaml -Link_com_mod_p_lower: +Line_loss_tangents_forward: description: >- - `Link-com-mod-p-lower` — a committed modular link flows at least - its minimum of one module, whether the build is fixed or a decision - dims: [scenario, snapshot, link] - where: Link_committed AND Link_p_nom_mod > 0 - expression: Link_p >= Link_p_min_pu * Link_p_nom_mod * (Link_status - Link_maintenance_pu * Link_maintenance_status) + `Line-loss_tangents-{k}-1`, `Line-loss_secants-pos` — the loss sits above + every cut to its curve for flow one way; PyPSA names one row per tangent + `k`, or one row stacked over its `secant` axis, and this entry states them + all over the segment dimension + dims: [scenario, snapshot, line, segment] + where: Line_lossy + expression: Line_loss + Line_loss_slope * Line_s >= Line_loss_offset ``` ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\ell_{k,\xi,t} + \mathrm{a}_{k,\xi,m,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,m,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ m \in \mathcal{M},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -### `Link-com-mod-p-upper` +### `Line-loss_tangents-{k}--1` -`Link_com_mod_p_upper` +`Line_loss_tangents_reverse` ```yaml -Link_com_mod_p_upper: +Line_loss_tangents_reverse: description: >- - `Link-com-mod-p-upper` — a committed modular link flows at most - one module's share, whether the build is fixed or a decision - dims: [scenario, snapshot, link] - where: Link_committed AND Link_p_nom_mod > 0 - expression: Link_p <= Link_p_max_pu * Link_p_nom_mod * (Link_status - Link_maintenance_pu * Link_maintenance_status) + `Line-loss_tangents-{k}--1`, `Line-loss_secants-neg` — the same fan + mirrored, the loss depending on the flow's magnitude + dims: [scenario, snapshot, line, segment] + where: Line_lossy + expression: Line_loss - Line_loss_slope * Line_s >= Line_loss_offset ``` ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\ell_{k,\xi,t} - \mathrm{a}_{k,\xi,m,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,m,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ m \in \mathcal{M},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -### `Link-status-p-fixed-upper` +### `Line-loss_upper` -`Link_status_p_fixed_upper` +`Line_loss_upper` ```yaml -Link_status_p_fixed_upper: - description: >- - `Link-status-p-fixed-upper` — a status is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, link] - where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) - expression: Link_status <= Link_modules_installed +Line_loss_upper: + description: "`Line-loss_upper` — a line dissipates at most the loss at its rating" + dims: [scenario, snapshot, line] + where: Line_lossy + expression: Line_loss <= Line_loss_max ``` ```math -u^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\ell_{k,\xi,t} \le \overline{\ell}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -### `Link-start_up-p-fixed-upper` +### `Line-s_nom_modularity` -`Link_start_up_p_fixed_upper` +`Line_s_nom_modularity` ```yaml -Link_start_up_p_fixed_upper: - description: >- - `Link-start_up-p-fixed-upper` — a start is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, link] - where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) - expression: Link_start_up <= Link_modules_installed +Line_s_nom_modularity: + description: "`Line-s_nom_modularity` — the chosen build is a whole number of modules" + dims: [line] + where: Line_s_nom_extendable AND Line_s_nom_mod > 0 AND Line_active_asset + expression: Line_s_nom_ext == Line_s_nom_mod * Line_n_mod ``` ```math -\mathit{up}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +S_{k} = \mathrm{s}^{\mathrm{mod}}_{k} \cdot N^{s}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} ``` -### `Link-shut_down-p-fixed-upper` +### `Line-s_nom_set` -`Link_shut_down_p_fixed_upper` +`Line_s_nom_set` ```yaml -Link_shut_down_p_fixed_upper: - description: >- - `Link-shut_down-p-fixed-upper` — a stop is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, link] - where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) - expression: Link_shut_down <= Link_modules_installed +Line_s_nom_set: + description: "`Line-s_nom_set` — the chosen build pinned, wherever a value is given" + dims: [line] + where: Line_s_nom_extendable AND Line_active_asset AND Line_s_nom_set + expression: Line_s_nom_ext == Line_s_nom_set ``` ```math -\mathit{dn}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +S_{k} = \mathrm{s}^{\mathrm{nom,set}}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \mathrm{s}^{\mathrm{nom,set}}_{k} \text{ is defined} ``` -### `Link-status-p_nom-variable-upper` +### `Line-s_set` -`Link_status_p_nom_variable_upper` +`Line_s_set` ```yaml -Link_status_p_nom_variable_upper: - description: "`Link-status-p_nom-variable-upper` — a modular link is on only where a module is built" - dims: [scenario, snapshot, link] - where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 - expression: Link_status <= Link_n_mod +Line_s_set: + description: "`Line-s_set` — flow pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, line] + where: Line_s_set AND Line_active + expression: Line_s == Line_s_set ``` ```math -u^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +s_{k,\xi,t} = \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \text{ is defined} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-start_up-p_nom-variable-upper` +### `Line-v_ang-lower` -`Link_start_up_p_nom_variable_upper` +`Line_v_ang_lower` ```yaml -Link_start_up_p_nom_variable_upper: - description: "`Link-start_up-p_nom-variable-upper` — a modular link starts only where a module is built" - dims: [scenario, snapshot, link] - where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 - expression: Link_start_up <= Link_n_mod +Line_v_ang_lower: + description: >- + `Line-v_ang-lower` — an AC line carries at least the flow at which the + voltage angle difference across it, `x_pu_eff` times the flow in + radians, is the negative of its limit + dims: [scenario, snapshot, line] + where: Line_v_ang_max AND Line_carrier == 'AC' AND Line_active + expression: Line_s >= -Line_v_ang_max * (3.141592653589793 / 180) / Line_x_pu_eff ``` ```math -\mathit{up}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +s_{k,\xi,t} \ge \frac{-\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-shut_down-p_nom-variable-upper` +### `Line-v_ang-upper` -`Link_shut_down_p_nom_variable_upper` +`Line_v_ang_upper` ```yaml -Link_shut_down_p_nom_variable_upper: - description: "`Link-shut_down-p_nom-variable-upper` — a modular link stops only where a module is built" - 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 +Line_v_ang_upper: + description: >- + `Line-v_ang-upper` — an AC line carries at most the flow at which the + voltage angle difference across it reaches its limit + dims: [scenario, snapshot, line] + where: Line_v_ang_max AND Line_carrier == 'AC' AND Line_active + expression: Line_s <= Line_v_ang_max * (3.141592653589793 / 180) / Line_x_pu_eff ``` ```math -\mathit{dn}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +s_{k,\xi,t} \le \frac{\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} ``` -### `Link-maint-event-count` +### `Link-com-down-time` -`Link_maint_event_count` +`Link_com_down_time` ```yaml -Link_maint_event_count: - description: "`Link-maint-event-count` — a maintainable link holds its number of maintenance events over the horizon" - dims: [scenario, link] - where: Link_maintainable - expression: sum(Link_maintenance_start, over=snapshot) == Link_maintenance_events +Link_com_down_time: + description: >- + `Link-com-down-time` — a link stopped within its own minimum down + time is still off. The first snapshot's share of the window is the + brought-in down time's, which the must-stay-down mask carries + dims: [scenario, snapshot, link] + where: Link_committed AND Link_min_down_time > 0 AND position(snapshot) > 0 + expression: sum_back(Link_shut_down, along=snapshot, window=Link_min_down_time) <= 1 - Link_status ``` ```math -\sum_{t \in \mathcal{T}} \mu^{f,\mathrm{up}}_{l,\xi,t} = \mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{f}} \mathit{dn}^{f}_{l,\xi,t'} \le 1 - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{DT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Link-maint-window` +### `Link-com-ext-p-lower` -`Link_maint_window` +`Link_com_ext_p_lower` ```yaml -Link_maint_window: +Link_com_ext_p_lower: description: >- - `Link-maint-window` — a link is in maintenance exactly where an event it - started covers the snapshot; two events do not overlap, since the - maintenance status is at most one + `Link-com-ext-p-lower` — a committed extendable link flows at + least its minimum of the chosen build; off, the big M releases the row dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_active - expression: Link_maintenance == sum(Link_maintenance_start, over=start, by=Link_maintenance_cover[covered]) + where: Link_com_ext + expression: >- + Link_p >= + Link_p_min_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) + + Link_big_m * Link_status - Link_big_m ``` ```math -\mu^{f}_{l,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ l,\ \xi,\ t' \right) \in \mathrm{Link\_maintenance\_cover}} \mu^{f,\mathrm{up}}_{l,\xi,t'} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) + \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} - \mathrm{M}^{f}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -### `Link-maint-start-horizon` +### `Link-com-ext-p-lower-nonneg` -`Link_maint_start_horizon` +`Link_com_ext_p_lower_nonneg` ```yaml -Link_maint_start_horizon: - description: "`Link-maint-start-horizon` — no event starts where it could not run its whole duration" +Link_com_ext_p_lower_nonneg: + description: >- + `Link-com-ext-p-lower-nonneg` — where no minimum-per-unit is + negative, flow is also plainly non-negative, a row the big-M lower + cannot assert while the link is off dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_active AND Link_maintenance_start_blocked - expression: Link_maintenance_start == 0 + where: Link_com_ext AND Link_p_min_pu_nonneg + expression: Link_p >= 0 ``` ```math -\mu^{f,\mathrm{up}}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \wedge \mathrm{blk}^{f}_{l,\xi,t} +f_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \mathrm{nonneg}^{f}_{l} ``` -### `Link-maintcap_upper` +### `Link-com-ext-p-upper-bigM` -`Link_maintcap_upper` +`Link_com_ext_p_upper_big_m` ```yaml -Link_maintcap_upper: - description: >- - `Link-maintcap_upper` — the build taken off is at most the chosen build in - maintenance, and at most the build less its floor out of it +Link_com_ext_p_upper_big_m: + description: "`Link-com-ext-p-upper-bigM` — off, a link flows nothing; on, the big M is no bound" dims: [scenario, snapshot, link] - where: Link_maint_ext - expression: Link_maintenance_capacity <= Link_p_nom_ext - Link_p_nom_min * (1 - Link_maintenance) + where: Link_com_ext + expression: Link_p <= Link_big_m * Link_status ``` ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \le F_{l} - \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +f_{l,\xi,t} \le \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -### `Link-maintcap_upper_nommax` +### `Link-com-ext-p-upper-cap` -`Link_maintcap_upper_nommax` +`Link_com_ext_p_upper_cap` ```yaml -Link_maintcap_upper_nommax: - description: "`Link-maintcap_upper_nommax` — out of maintenance, no build is taken off" +Link_com_ext_p_upper_cap: + description: >- + `Link-com-ext-p-upper-cap` — a committed extendable link flows + at most what is available of the chosen build, whatever its status dims: [scenario, snapshot, link] - where: Link_maint_ext - expression: Link_maintenance_capacity <= Link_p_nom_max * Link_maintenance + where: Link_com_ext + expression: Link_p <= Link_p_max_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) ``` ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -### `Link-maintcap_lower_nommax` +### `Link-com-mod-p-lower` -`Link_maintcap_lower_nommax` +`Link_com_mod_p_lower` ```yaml -Link_maintcap_lower_nommax: - description: "`Link-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" +Link_com_mod_p_lower: + description: >- + `Link-com-mod-p-lower` — a committed modular link flows at least + its minimum of one module, whether the build is fixed or a decision dims: [scenario, snapshot, link] - where: Link_maint_ext - expression: Link_maintenance_capacity >= Link_p_nom_ext - Link_p_nom_max * (1 - Link_maintenance) + where: Link_committed AND Link_p_nom_mod > 0 + expression: Link_p >= Link_p_min_pu * Link_p_nom_mod * (Link_status - Link_maintenance_pu * Link_maintenance_status) ``` ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge F_{l} - \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Link-maintcap_lower_nommin` +### `Link-com-mod-p-upper` -`Link_maintcap_lower_nommin` +`Link_com_mod_p_upper` ```yaml -Link_maintcap_lower_nommin: - description: "`Link-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" +Link_com_mod_p_upper: + description: >- + `Link-com-mod-p-upper` — a committed modular link flows at most + one module's share, whether the build is fixed or a decision dims: [scenario, snapshot, link] - where: Link_maint_ext AND Link_p_nom_min > 0 - expression: Link_maintenance_capacity >= Link_p_nom_min * Link_maintenance + where: Link_committed AND Link_p_nom_mod > 0 + expression: Link_p <= Link_p_max_pu * Link_p_nom_mod * (Link_status - Link_maintenance_pu * Link_maintenance_status) ``` ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} \wedge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} > 0 +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Link-maint-status-le-status` +### `Link-com-p-lower` -`Link_maint_status_le_status` +`Link_com_p_lower` ```yaml -Link_maint_status_le_status: - description: "`Link-maint-status-le-status` — the status in maintenance is at most the status" +Link_com_p_lower: + description: "`Link-com-p-lower` — a committed link flows at least its minimum; off, at least nothing" dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) - expression: Link_maintenance_status <= Link_status + where: Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) + expression: Link_p >= Link_p_min_pu * Link_p_nom * (Link_status - Link_maintenance_pu * Link_maintenance_status) ``` ```math -\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Link-maint-status-le-maint` +### `Link-com-p-upper` -`Link_maint_status_le_maint` +`Link_com_p_upper` ```yaml -Link_maint_status_le_maint: - description: "`Link-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" +Link_com_p_upper: + description: "`Link-com-p-upper` — a committed link flows at most what is available; off, at most nothing" dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) - expression: Link_maintenance_status <= Link_maintenance + where: Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) + expression: Link_p <= Link_p_max_pu * Link_p_nom * (Link_status - Link_maintenance_pu * Link_maintenance_status) ``` ```math -\mu^{f,u}_{l,\xi,t} \le \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Link-maint-status-lb` +### `Link-com-status-min_down_time_must_stay_up` -`Link_maint_status_lb` +`Link_com_status_must_stay_down` ```yaml -Link_maint_status_lb: - description: "`Link-maint-status-lb` — on and in maintenance, the status in maintenance is one" +Link_com_status_must_stay_down: + description: >- + `Link-com-status-min_down_time_must_stay_up` — a link still serving + the down time it brought in stays off; PyPSA names the row `_must_stay_up` dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) - expression: Link_maintenance_status >= Link_status + Link_maintenance - 1 + where: Link_committed AND Link_must_stay_down + expression: Link_status == 0 ``` ```math -\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} + \mu^{f}_{l,\xi,t} - 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +u^{f}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{rest}^{f}_{l,\xi,t} ``` -### `Link-maint-modstatus-le-status` +### `Link-com-status-min_up_time_must_stay_up` -`Link_maint_modstatus_le_status` +`Link_com_status_must_stay_up` ```yaml -Link_maint_modstatus_le_status: - description: "`Link-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" +Link_com_status_must_stay_up: + description: "`Link-com-status-min_up_time_must_stay_up` — a link still serving the up time it brought in stays on" dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 - expression: Link_maintenance_status <= Link_status + where: Link_committed AND Link_must_stay_up + expression: Link_status == 1 ``` ```math -\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +u^{f}_{l,\xi,t} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{hold}^{f}_{l,\xi,t} ``` -### `Link-maint-modstatus-le-maint` +### `Link-com-transition-shut-down` -`Link_maint_modstatus_le_maint` +`Link_com_transition_shut_down` ```yaml -Link_maint_modstatus_le_maint: - description: >- - `Link-maint-modstatus-le-maint` — out of maintenance, no module is on in - maintenance; in it, at most the modules the build cap holds +Link_com_transition_shut_down: + description: "`Link-com-transition-shut-down` — turning off is a stop, counted against the state the link carried into the snapshot" dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 - expression: Link_maintenance_status <= Link_p_nom_max / Link_p_nom_mod * Link_maintenance + where: Link_committed + expression: Link_shut_down >= Link_previous_status - Link_status ``` ```math -\mu^{f,u}_{l,\xi,t} \le \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mathit{dn}^{f}_{l,\xi,t} \ge \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -### `Link-maint-modstatus-lb` +### `Link-com-transition-start-up` -`Link_maint_modstatus_lb` +`Link_com_transition_start_up` ```yaml -Link_maint_modstatus_lb: - description: "`Link-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" +Link_com_transition_start_up: + description: "`Link-com-transition-start-up` — turning on is a start, counted against the state the link carried into the snapshot" dims: [scenario, snapshot, link] - where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 - expression: Link_maintenance_status >= Link_status - Link_p_nom_max / Link_p_nom_mod * (1 - Link_maintenance) + where: Link_committed + expression: Link_start_up >= Link_status - Link_previous_status ``` ```math -\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mathit{up}^{f}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -### `Process-com-p-lower` +### `Link-com-up-time` -`Process_com_p_lower` +`Link_com_up_time` ```yaml -Process_com_p_lower: - description: "`Process-com-p-lower` — a committed process runs at least its minimum; off, at least nothing" - dims: [scenario, snapshot, process] - where: Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) - expression: Process_p >= Process_p_min_pu * Process_p_nom * (Process_status - Process_maintenance_pu * Process_maintenance_status) +Link_com_up_time: + description: >- + `Link-com-up-time` — a link started within its own minimum up time + is still on. The first snapshot's share of the window is the brought-in + up time's, which the must-stay-up mask carries + dims: [scenario, snapshot, link] + where: Link_committed AND Link_min_up_time > 0 AND position(snapshot) > 0 + expression: sum_back(Link_start_up, along=snapshot, window=Link_min_up_time) <= Link_status ``` ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{f}} \mathit{up}^{f}_{l,\xi,t'} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{UT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Process-com-p-upper` +### `Link-ext-p-lower` -`Process_com_p_upper` +`Link_ext_p_lower` ```yaml -Process_com_p_upper: - description: "`Process-com-p-upper` — a committed process runs at most what is available; off, at most nothing" - dims: [scenario, snapshot, process] - where: Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) - expression: Process_p <= Process_p_max_pu * Process_p_nom * (Process_status - Process_maintenance_pu * Process_maintenance_status) +Link_ext_p_lower: + description: "`Link-ext-p-lower` — an extendable link carries at least its minimum of the chosen build, negative for the other way" + dims: [scenario, snapshot, link] + where: Link_p_nom_extendable AND not Link_committable AND Link_active + expression: Link_p >= Link_p_min_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) ``` ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-com-transition-start-up` +### `Link-ext-p_nom-lower` -`Process_com_transition_start_up` +`Link_ext_p_nom_lower` ```yaml -Process_com_transition_start_up: - description: "`Process-com-transition-start-up` — turning on is a start, counted against the state the process carried into the snapshot" - dims: [scenario, snapshot, process] - where: Process_committed - expression: Process_start_up >= Process_status - Process_previous_status +Link_ext_p_nom_lower: + description: "`Link-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, link] + where: Link_p_nom_extendable AND Link_active_asset + expression: Link_p_nom_ext >= Link_p_nom_min ``` ```math -\mathit{up}^{z}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +F_{l} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} ``` -### `Process-com-transition-shut-down` +### `Link-ext-p_nom-upper` -`Process_com_transition_shut_down` +`Link_ext_p_nom_upper` ```yaml -Process_com_transition_shut_down: - description: "`Process-com-transition-shut-down` — turning off is a stop, counted against the state the process carried into the snapshot" - dims: [scenario, snapshot, process] - where: Process_committed - expression: Process_shut_down >= Process_previous_status - Process_status +Link_ext_p_nom_upper: + description: "`Link-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, link] + where: Link_p_nom_extendable AND Link_active_asset AND Link_p_nom_max + expression: Link_p_nom_ext <= Link_p_nom_max ``` ```math -\mathit{dn}^{z}_{j,\xi,t} \ge \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +F_{l} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \text{ is defined} ``` -### `Process-com-up-time` +### `Link-ext-p-upper` -`Process_com_up_time` +`Link_ext_p_upper` ```yaml -Process_com_up_time: - description: >- - `Process-com-up-time` — a process started within its own minimum up time - is still on. The first snapshot's share of the window is the brought-in - up time's, which the must-stay-up mask carries - dims: [scenario, snapshot, process] - where: Process_committed AND Process_min_up_time > 0 AND position(snapshot) > 0 - expression: sum_back(Process_start_up, along=snapshot, window=Process_min_up_time) <= Process_status +Link_ext_p_upper: + description: "`Link-ext-p-upper` — an extendable link carries at most the chosen build" + dims: [scenario, snapshot, link] + where: Link_p_nom_extendable AND not Link_committable AND Link_active + expression: Link_p <= Link_p_max_pu * (Link_p_nom_ext - Link_maintenance_pu * Link_maintenance_capacity) ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{z}} \mathit{up}^{z}_{j,\xi,t'} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{UT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-com-down-time` +### `Link-fix-p-lower` -`Process_com_down_time` +`Link_fix_p_lower` ```yaml -Process_com_down_time: - description: >- - `Process-com-down-time` — a process stopped within its own minimum down - time is still off. The first snapshot's share of the window is the - brought-in down time's, which the must-stay-down mask carries - dims: [scenario, snapshot, process] - where: Process_committed AND Process_min_down_time > 0 AND position(snapshot) > 0 - expression: sum_back(Process_shut_down, along=snapshot, window=Process_min_down_time) <= 1 - Process_status +Link_fix_p_lower: + description: "`Link-fix-p-lower` — a fixed link carries at least its minimum, negative for the other way" + dims: [scenario, snapshot, link] + where: not Link_p_nom_extendable AND not Link_committable AND Link_active + expression: Link_p >= Link_p_min_pu * Link_p_nom * (1 - Link_maintenance_pu * Link_maintenance) ``` ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{z}} \mathit{dn}^{z}_{j,\xi,t'} \le 1 - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{DT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-com-status-min_up_time_must_stay_up` +### `Link-fix-p-upper` -`Process_com_status_must_stay_up` +`Link_fix_p_upper` ```yaml -Process_com_status_must_stay_up: - description: "`Process-com-status-min_up_time_must_stay_up` — a process still serving the up time it brought in stays on" - dims: [scenario, snapshot, process] - where: Process_committed AND Process_must_stay_up - expression: Process_status == 1 +Link_fix_p_upper: + description: "`Link-fix-p-upper` — a fixed link carries at most its nominal power" + dims: [scenario, snapshot, link] + where: not Link_p_nom_extendable AND not Link_committable AND Link_active + expression: Link_p <= Link_p_max_pu * Link_p_nom * (1 - Link_maintenance_pu * Link_maintenance) ``` ```math -u^{z}_{j,\xi,t} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{hold}^{z}_{j,\xi,t} +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-com-status-min_down_time_must_stay_up` +### `Link-maint-event-count` -`Process_com_status_must_stay_down` +`Link_maint_event_count` ```yaml -Process_com_status_must_stay_down: - description: >- - `Process-com-status-min_down_time_must_stay_up` — a process still serving - the down time it brought in stays off; PyPSA names the row `_must_stay_up` - dims: [scenario, snapshot, process] - where: Process_committed AND Process_must_stay_down - expression: Process_status == 0 +Link_maint_event_count: + description: "`Link-maint-event-count` — a maintainable link holds its number of maintenance events over the horizon" + dims: [scenario, link] + where: Link_maintainable + expression: sum(Link_maintenance_start, over=snapshot) == Link_maintenance_events ``` ```math -u^{z}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{rest}^{z}_{j,\xi,t} +\sum_{t \in \mathcal{T}} \mu^{f,\mathrm{up}}_{l,\xi,t} = \mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` -### `Process-p-ramp_limit_up-run-bigM` +### `Link-maint-modstatus-lb` -`Process_p_ramp_limit_up_run_big_m` +`Link_maint_modstatus_lb` ```yaml -Process_p_ramp_limit_up_run_big_m: - description: >- - `Process-p-ramp_limit_up-run-bigM` — a committed extendable process - raises internal power no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns on - dims: [scenario, snapshot, process] - where: Process_com_ext AND (Process_ramp_limit_up OR Process_ramp_limit_start_up) AND Process_ramps_from_previous - expression: >- - Process_p - Process_previous_p <= - Process_ramp_up_rate * Process_p_nom_ext - + Process_big_m - Process_big_m * Process_previous_status +Link_maint_modstatus_lb: + description: "`Link-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 + expression: Link_maintenance_status >= Link_status - Link_p_nom_max / Link_p_nom_mod * (1 - Link_maintenance) ``` ```math -z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-p-ramp_limit_up-start-bigM` +### `Link-maint-modstatus-le-maint` -`Process_p_ramp_limit_up_start_big_m` +`Link_maint_modstatus_le_maint` ```yaml -Process_p_ramp_limit_up_start_big_m: +Link_maint_modstatus_le_maint: description: >- - `Process-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a - committed extendable process ramps no further than its start-up ramp of - the chosen build; the big M releases the row everywhere else - dims: [scenario, snapshot, process] - where: Process_com_ext AND (Process_ramp_limit_up OR Process_ramp_limit_start_up) AND Process_ramps_from_previous - expression: >- - Process_p - Process_previous_p <= - Process_start_up_rate * Process_p_nom_ext - + Process_big_m - Process_big_m * Process_start_up + `Link-maint-modstatus-le-maint` — out of maintenance, no module is on in + maintenance; in it, at most the modules the build cap holds + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 + expression: Link_maintenance_status <= Link_p_nom_max / Link_p_nom_mod * Link_maintenance ``` ```math -z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{up}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +\mu^{f,u}_{l,\xi,t} \le \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-p-ramp_limit_down-run-bigM` +### `Link-maint-modstatus-le-status` -`Process_p_ramp_limit_down_run_big_m` +`Link_maint_modstatus_le_status` ```yaml -Process_p_ramp_limit_down_run_big_m: - description: >- - `Process-p-ramp_limit_down-run-bigM` — a committed extendable process - lowers internal power no faster than its limit of the chosen build; the big M - releases the row in the snapshot it turns off - dims: [scenario, snapshot, process] - where: >- - Process_com_ext - AND (Process_ramp_limit_down OR Process_ramp_limit_shut_down) - AND Process_ramps_from_previous - expression: >- - Process_previous_p - Process_p <= - Process_ramp_down_rate * Process_p_nom_ext - + Process_big_m - Process_big_m * Process_status +Link_maint_modstatus_le_status: + description: "`Link-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND Link_p_nom_mod > 0 + expression: Link_maintenance_status <= Link_status ``` ```math -\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-p-ramp_limit_down-shut-bigM` +### `Link-maint-start-horizon` -`Process_p_ramp_limit_down_shut_big_m` +`Link_maint_start_horizon` ```yaml -Process_p_ramp_limit_down_shut_big_m: - description: >- - `Process-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, - a committed extendable process ramps no further than its shut-down ramp of - the chosen build; the big M releases the row everywhere else - dims: [scenario, snapshot, process] - where: >- - Process_com_ext - AND (Process_ramp_limit_down OR Process_ramp_limit_shut_down) - AND Process_ramps_from_previous - expression: >- - Process_previous_p - Process_p <= - Process_shut_down_rate * Process_p_nom_ext - + Process_big_m - Process_big_m * Process_shut_down +Link_maint_start_horizon: + description: "`Link-maint-start-horizon` — no event starts where it could not run its whole duration" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_active AND Link_maintenance_start_blocked + expression: Link_maintenance_start == 0 ``` ```math -\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{dn}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +\mu^{f,\mathrm{up}}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \wedge \mathrm{blk}^{f}_{l,\xi,t} ``` -### `Process-p_nom_modularity` +### `Link-maint-status-lb` -`Process_p_nom_modularity` +`Link_maint_status_lb` ```yaml -Process_p_nom_modularity: - description: "`Process-p_nom_modularity` — the chosen build is a whole number of modules" - dims: [process] - where: Process_p_nom_extendable AND Process_p_nom_mod > 0 AND Process_active_asset - expression: Process_p_nom_ext == Process_p_nom_mod * Process_n_mod +Link_maint_status_lb: + description: "`Link-maint-status-lb` — on and in maintenance, the status in maintenance is one" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) + expression: Link_maintenance_status >= Link_status + Link_maintenance - 1 ``` ```math -Z_{j} = \mathrm{z}^{\mathrm{mod}}_{j} \cdot N^{z}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} +\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} + \mu^{f}_{l,\xi,t} - 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-com-ext-p-upper-cap` +### `Link-maint-status-le-maint` -`Process_com_ext_p_upper_cap` +`Link_maint_status_le_maint` ```yaml -Process_com_ext_p_upper_cap: - description: >- - `Process-com-ext-p-upper-cap` — a committed extendable process runs - at most what is available of the chosen build, whatever its status - dims: [scenario, snapshot, process] - where: Process_com_ext - expression: Process_p <= Process_p_max_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) +Link_maint_status_le_maint: + description: "`Link-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) + expression: Link_maintenance_status <= Link_maintenance ``` ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +\mu^{f,u}_{l,\xi,t} \le \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-com-ext-p-upper-bigM` +### `Link-maint-status-le-status` -`Process_com_ext_p_upper_big_m` +`Link_maint_status_le_status` ```yaml -Process_com_ext_p_upper_big_m: - description: "`Process-com-ext-p-upper-bigM` — off, a process does not run; on, the big M is no bound" - dims: [scenario, snapshot, process] - where: Process_com_ext - expression: Process_p <= Process_big_m * Process_status +Link_maint_status_le_status: + description: "`Link-maint-status-le-status` — the status in maintenance is at most the status" + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_committed AND NOT Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0) + expression: Link_maintenance_status <= Link_status ``` ```math -z_{j,\xi,t} \le \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-com-ext-p-lower` +### `Link-maint-window` -`Process_com_ext_p_lower` +`Link_maint_window` ```yaml -Process_com_ext_p_lower: +Link_maint_window: description: >- - `Process-com-ext-p-lower` — a committed extendable process runs at - least its minimum of the chosen build; off, the big M releases the row - dims: [scenario, snapshot, process] - where: Process_com_ext - expression: >- - Process_p >= - Process_p_min_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) - + Process_big_m * Process_status - Process_big_m + `Link-maint-window` — a link is in maintenance exactly where an event it + started covers the snapshot; two events do not overlap, since the + maintenance status is at most one + dims: [scenario, snapshot, link] + where: Link_maintainable AND Link_active + expression: Link_maintenance == sum(Link_maintenance_start, over=start, by=Link_maintenance_cover[covered]) ``` ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) + \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} - \mathrm{M}^{z}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +\mu^{f}_{l,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ l,\ \xi,\ t' \right) \in \mathrm{Link\_maintenance\_cover}} \mu^{f,\mathrm{up}}_{l,\xi,t'} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-com-ext-p-lower-nonneg` +### `Link-maintcap_lower_nommax` -`Process_com_ext_p_lower_nonneg` +`Link_maintcap_lower_nommax` ```yaml -Process_com_ext_p_lower_nonneg: - description: >- - `Process-com-ext-p-lower-nonneg` — where no minimum-per-unit is - negative, internal power is also plainly non-negative, a row the big-M lower - cannot assert while the process is off - dims: [scenario, snapshot, process] - where: Process_com_ext AND Process_p_min_pu_nonneg - expression: Process_p >= 0 +Link_maintcap_lower_nommax: + description: "`Link-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" + dims: [scenario, snapshot, link] + where: Link_maint_ext + expression: Link_maintenance_capacity >= Link_p_nom_ext - Link_p_nom_max * (1 - Link_maintenance) ``` ```math -z_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \mathrm{nonneg}^{z}_{j} +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge F_{l} - \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -### `Process-com-mod-p-lower` +### `Link-maintcap_lower_nommin` -`Process_com_mod_p_lower` +`Link_maintcap_lower_nommin` ```yaml -Process_com_mod_p_lower: - description: >- - `Process-com-mod-p-lower` — a committed modular process runs at least - its minimum of one module, whether the build is fixed or a decision - dims: [scenario, snapshot, process] - where: Process_committed AND Process_p_nom_mod > 0 - expression: Process_p >= Process_p_min_pu * Process_p_nom_mod * (Process_status - Process_maintenance_pu * Process_maintenance_status) +Link_maintcap_lower_nommin: + description: "`Link-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" + dims: [scenario, snapshot, link] + where: Link_maint_ext AND Link_p_nom_min > 0 + expression: Link_maintenance_capacity >= Link_p_nom_min * Link_maintenance ``` ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} \wedge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} > 0 ``` -### `Process-com-mod-p-upper` +### `Link-maintcap_upper` -`Process_com_mod_p_upper` +`Link_maintcap_upper` ```yaml -Process_com_mod_p_upper: +Link_maintcap_upper: description: >- - `Process-com-mod-p-upper` — a committed modular process runs at most - one module's share, whether the build is fixed or a decision - dims: [scenario, snapshot, process] - where: Process_committed AND Process_p_nom_mod > 0 - expression: Process_p <= Process_p_max_pu * Process_p_nom_mod * (Process_status - Process_maintenance_pu * Process_maintenance_status) + `Link-maintcap_upper` — the build taken off is at most the chosen build in + maintenance, and at most the build less its floor out of it + dims: [scenario, snapshot, link] + where: Link_maint_ext + expression: Link_maintenance_capacity <= Link_p_nom_ext - Link_p_nom_min * (1 - Link_maintenance) ``` ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mu^{f,\mathrm{nom}}_{l,\xi,t} \le F_{l} - \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -### `Process-status-p-fixed-upper` +### `Link-maintcap_upper_nommax` -`Process_status_p_fixed_upper` +`Link_maintcap_upper_nommax` ```yaml -Process_status_p_fixed_upper: - description: >- - `Process-status-p-fixed-upper` — a status is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, process] - where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) - expression: Process_status <= Process_modules_installed +Link_maintcap_upper_nommax: + description: "`Link-maintcap_upper_nommax` — out of maintenance, no build is taken off" + dims: [scenario, snapshot, link] + where: Link_maint_ext + expression: Link_maintenance_capacity <= Link_p_nom_max * Link_maintenance ``` ```math -u^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mu^{f,\mathrm{nom}}_{l,\xi,t} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -### `Process-start_up-p-fixed-upper` +### `Link-p_nom_modularity` -`Process_start_up_p_fixed_upper` +`Link_p_nom_modularity` ```yaml -Process_start_up_p_fixed_upper: - description: >- - `Process-start_up-p-fixed-upper` — a start is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, process] - where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) - expression: Process_start_up <= Process_modules_installed +Link_p_nom_modularity: + description: "`Link-p_nom_modularity` — the chosen build is a whole number of modules" + dims: [link] + where: Link_p_nom_extendable AND Link_p_nom_mod > 0 AND Link_active_asset + expression: Link_p_nom_ext == Link_p_nom_mod * Link_n_mod ``` ```math -\mathit{up}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +F_{l} = \mathrm{f}^{\mathrm{mod}}_{l} \cdot N^{f}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} ``` -### `Process-shut_down-p-fixed-upper` +### `Link-p_nom_set` -`Process_shut_down_p_fixed_upper` +`Link_p_nom_set` ```yaml -Process_shut_down_p_fixed_upper: +Link_p_nom_set: + description: "`Link-p_nom_set` — the chosen build pinned, wherever a value is given" + dims: [link] + where: Link_p_nom_extendable AND Link_active_asset AND Link_p_nom_set + expression: Link_p_nom_ext == Link_p_nom_set +``` + +```math +F_{l} = \mathrm{f}^{\mathrm{nom,set}}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \mathrm{f}^{\mathrm{nom,set}}_{l} \text{ is defined} +``` + +### `Link-p-ramp_limit_down` + +`Link_p_ramp_limit_down` + +```yaml +Link_p_ramp_limit_down: description: >- - `Process-shut_down-p-fixed-upper` — a stop is at most the modules in - place, an explicit row as PyPSA writes it: one where the build is not - modular, and the fixed build's whole count of modules where it is - dims: [scenario, snapshot, process] - where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) - expression: Process_shut_down <= Process_modules_installed + `Link-p-ramp_limit_down` — a link lowers flow no faster than + its ramp limit of the build, and a committed one no further than its + shut-down ramp in the snapshot it turns off. A link that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the flow it brought in, and no link carries one at + the start of a later investment period — nor does any link a big M releases instead + dims: [scenario, snapshot, link] + where: >- + (Link_ramp_limit_down OR Link_ramp_limit_shut_down) + AND NOT (Link_committable AND Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)) + AND Link_ramps_from_previous + AND Link_active + expression: Link_previous_p - Link_p <= Link_ramp_down_allowance ``` ```math -\mathit{dn}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \Delta^{f,-}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-status-p_nom-variable-upper` +### `Link-p-ramp_limit_down-run-bigM` -`Process_status_p_nom_variable_upper` +`Link_p_ramp_limit_down_run_big_m` ```yaml -Process_status_p_nom_variable_upper: - description: "`Process-status-p_nom-variable-upper` — a modular process is on only where a module is built" - dims: [scenario, snapshot, process] - where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 - expression: Process_status <= Process_n_mod +Link_p_ramp_limit_down_run_big_m: + description: >- + `Link-p-ramp_limit_down-run-bigM` — a committed extendable link + lowers flow no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns off + dims: [scenario, snapshot, link] + where: Link_com_ext AND (Link_ramp_limit_down OR Link_ramp_limit_shut_down) AND Link_ramps_from_previous + expression: >- + Link_previous_p - Link_p <= + Link_ramp_down_rate * Link_p_nom_ext + + Link_big_m - Link_big_m * Link_status ``` ```math -u^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} ``` -### `Process-start_up-p_nom-variable-upper` +### `Link-p-ramp_limit_down-shut-bigM` -`Process_start_up_p_nom_variable_upper` +`Link_p_ramp_limit_down_shut_big_m` ```yaml -Process_start_up_p_nom_variable_upper: - description: "`Process-start_up-p_nom-variable-upper` — a modular process starts only where a module is built" - dims: [scenario, snapshot, process] - where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 - expression: Process_start_up <= Process_n_mod +Link_p_ramp_limit_down_shut_big_m: + description: >- + `Link-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, + a committed extendable link ramps no further than its shut-down ramp of + the chosen build; the big M releases the row everywhere else + dims: [scenario, snapshot, link] + where: Link_com_ext AND (Link_ramp_limit_down OR Link_ramp_limit_shut_down) AND Link_ramps_from_previous + expression: >- + Link_previous_p - Link_p <= + Link_shut_down_rate * Link_p_nom_ext + + Link_big_m - Link_big_m * Link_shut_down ``` ```math -\mathit{up}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{dn}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} ``` -### `Process-shut_down-p_nom-variable-upper` +### `Link-p-ramp_limit_up` -`Process_shut_down_p_nom_variable_upper` +`Link_p_ramp_limit_up` ```yaml -Process_shut_down_p_nom_variable_upper: - description: "`Process-shut_down-p_nom-variable-upper` — a modular process stops only where a module is built" - 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 +Link_p_ramp_limit_up: + description: >- + `Link-p-ramp_limit_up` — a link raises flow no faster than + its ramp limit of the build, and a committed one no further than its + start-up ramp in the snapshot it turns on. A link that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the flow it brought in, and no link carries one at + the start of a later investment period — nor does any link a big M releases instead + dims: [scenario, snapshot, link] + where: >- + (Link_ramp_limit_up OR Link_ramp_limit_start_up) + AND NOT (Link_committable AND Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)) + AND Link_ramps_from_previous + AND Link_active + expression: Link_p - Link_previous_p <= Link_ramp_up_allowance ``` ```math -\mathit{dn}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \Delta^{f,+}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-maint-event-count` +### `Link-p-ramp_limit_up-run-bigM` -`Process_maint_event_count` +`Link_p_ramp_limit_up_run_big_m` ```yaml -Process_maint_event_count: - description: "`Process-maint-event-count` — a maintainable process holds its number of maintenance events over the horizon" - dims: [scenario, process] - where: Process_maintainable - expression: sum(Process_maintenance_start, over=snapshot) == Process_maintenance_events +Link_p_ramp_limit_up_run_big_m: + description: >- + `Link-p-ramp_limit_up-run-bigM` — a committed extendable link + raises flow no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns on + dims: [scenario, snapshot, link] + where: Link_com_ext AND (Link_ramp_limit_up OR Link_ramp_limit_start_up) AND Link_ramps_from_previous + expression: >- + Link_p - Link_previous_p <= + Link_ramp_up_rate * Link_p_nom_ext + + Link_big_m - Link_big_m * Link_previous_status ``` ```math -\sum_{t \in \mathcal{T}} \mu^{z,\mathrm{up}}_{j,\xi,t} = \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} ``` -### `Process-maint-window` +### `Link-p-ramp_limit_up-start-bigM` -`Process_maint_window` +`Link_p_ramp_limit_up_start_big_m` ```yaml -Process_maint_window: +Link_p_ramp_limit_up_start_big_m: description: >- - `Process-maint-window` — a process is in maintenance exactly where an event it - started covers the snapshot; two events do not overlap, since the - maintenance status is at most one - dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_active - expression: Process_maintenance == sum(Process_maintenance_start, over=start, by=Process_maintenance_cover[covered]) + `Link-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a + committed extendable link ramps no further than its start-up ramp of + the chosen build; the big M releases the row everywhere else + dims: [scenario, snapshot, link] + where: Link_com_ext AND (Link_ramp_limit_up OR Link_ramp_limit_start_up) AND Link_ramps_from_previous + expression: >- + Link_p - Link_previous_p <= + Link_start_up_rate * Link_p_nom_ext + + Link_big_m - Link_big_m * Link_start_up ``` ```math -\mu^{z}_{j,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ j,\ \xi,\ t' \right) \in \mathrm{Process\_maintenance\_cover}} \mu^{z,\mathrm{up}}_{j,\xi,t'} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{up}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} ``` -### `Process-maint-start-horizon` +### `Link-p_set` -`Process_maint_start_horizon` +`Link_p_set` ```yaml -Process_maint_start_horizon: - description: "`Process-maint-start-horizon` — no event starts where it could not run its whole duration" - dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_active AND Process_maintenance_start_blocked - expression: Process_maintenance_start == 0 +Link_p_set: + description: "`Link-p_set` — flow pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, link] + where: Link_p_set AND Link_active + expression: Link_p == Link_p_set ``` ```math -\mu^{z,\mathrm{up}}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \wedge \mathrm{blk}^{z}_{j,\xi,t} +f_{l,\xi,t} = \mathrm{f}^{\mathrm{set}}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{f}^{\mathrm{set}}_{l,\xi,t} \text{ is defined} \wedge \mathrm{on}^{f}_{l,t} ``` -### `Process-maintcap_upper` +### `Link-shut_down-p-fixed-upper` -`Process_maintcap_upper` +`Link_shut_down_p_fixed_upper` ```yaml -Process_maintcap_upper: +Link_shut_down_p_fixed_upper: description: >- - `Process-maintcap_upper` — the build taken off is at most the chosen build in - maintenance, and at most the build less its floor out of it - dims: [scenario, snapshot, process] - where: Process_maint_ext - expression: Process_maintenance_capacity <= Process_p_nom_ext - Process_p_nom_min * (1 - Process_maintenance) + `Link-shut_down-p-fixed-upper` — a stop is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, link] + where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) + expression: Link_shut_down <= Link_modules_installed ``` ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \le Z_{j} - \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mathit{dn}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-maintcap_upper_nommax` +### `Link-shut_down-p_nom-variable-upper` -`Process_maintcap_upper_nommax` +`Link_shut_down_p_nom_variable_upper` ```yaml -Process_maintcap_upper_nommax: - description: "`Process-maintcap_upper_nommax` — out of maintenance, no build is taken off" - dims: [scenario, snapshot, process] - where: Process_maint_ext - expression: Process_maintenance_capacity <= Process_p_nom_max * Process_maintenance +Link_shut_down_p_nom_variable_upper: + description: "`Link-shut_down-p_nom-variable-upper` — a modular link stops only where a module is built" + 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 ``` ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mathit{dn}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-maintcap_lower_nommax` +### `Link-start_up-p-fixed-upper` -`Process_maintcap_lower_nommax` +`Link_start_up_p_fixed_upper` ```yaml -Process_maintcap_lower_nommax: - description: "`Process-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" - dims: [scenario, snapshot, process] - where: Process_maint_ext - expression: Process_maintenance_capacity >= Process_p_nom_ext - Process_p_nom_max * (1 - Process_maintenance) +Link_start_up_p_fixed_upper: + description: >- + `Link-start_up-p-fixed-upper` — a start is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, link] + where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) + expression: Link_start_up <= Link_modules_installed ``` ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge Z_{j} - \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mathit{up}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-maintcap_lower_nommin` +### `Link-start_up-p_nom-variable-upper` -`Process_maintcap_lower_nommin` +`Link_start_up_p_nom_variable_upper` ```yaml -Process_maintcap_lower_nommin: - description: "`Process-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" - dims: [scenario, snapshot, process] - where: Process_maint_ext AND Process_p_nom_min > 0 - expression: Process_maintenance_capacity >= Process_p_nom_min * Process_maintenance +Link_start_up_p_nom_variable_upper: + description: "`Link-start_up-p_nom-variable-upper` — a modular link starts only where a module is built" + dims: [scenario, snapshot, link] + where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 + expression: Link_start_up <= Link_n_mod ``` ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} \wedge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} > 0 +\mathit{up}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-maint-status-le-status` +### `Link-status-p-fixed-upper` -`Process_maint_status_le_status` +`Link_status_p_fixed_upper` ```yaml -Process_maint_status_le_status: - description: "`Process-maint-status-le-status` — the status in maintenance is at most the status" - dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) - expression: Process_maintenance_status <= Process_status +Link_status_p_fixed_upper: + description: >- + `Link-status-p-fixed-upper` — a status is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, link] + where: Link_committed AND NOT (Link_p_nom_extendable AND Link_p_nom_mod > 0) + expression: Link_status <= Link_modules_installed ``` ```math -\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +u^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -### `Process-maint-status-le-maint` +### `Link-status-p_nom-variable-upper` -`Process_maint_status_le_maint` +`Link_status_p_nom_variable_upper` ```yaml -Process_maint_status_le_maint: - description: "`Process-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" - dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) - expression: Process_maintenance_status <= Process_maintenance +Link_status_p_nom_variable_upper: + description: "`Link-status-p_nom-variable-upper` — a modular link is on only where a module is built" + dims: [scenario, snapshot, link] + where: Link_committed AND Link_p_nom_extendable AND Link_p_nom_mod > 0 + expression: Link_status <= Link_n_mod ``` ```math -\mu^{z,u}_{j,\xi,t} \le \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +u^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process-maint-status-lb` +### `Process-com-down-time` -`Process_maint_status_lb` +`Process_com_down_time` ```yaml -Process_maint_status_lb: - description: "`Process-maint-status-lb` — on and in maintenance, the status in maintenance is one" +Process_com_down_time: + description: >- + `Process-com-down-time` — a process stopped within its own minimum down + time is still off. The first snapshot's share of the window is the + brought-in down time's, which the must-stay-down mask carries dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) - expression: Process_maintenance_status >= Process_status + Process_maintenance - 1 + where: Process_committed AND Process_min_down_time > 0 AND position(snapshot) > 0 + expression: sum_back(Process_shut_down, along=snapshot, window=Process_min_down_time) <= 1 - Process_status ``` ```math -\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} + \mu^{z}_{j,\xi,t} - 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{z}} \mathit{dn}^{z}_{j,\xi,t'} \le 1 - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{DT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Process-maint-modstatus-le-status` +### `Process-com-ext-p-lower` -`Process_maint_modstatus_le_status` +`Process_com_ext_p_lower` ```yaml -Process_maint_modstatus_le_status: - description: "`Process-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" +Process_com_ext_p_lower: + description: >- + `Process-com-ext-p-lower` — a committed extendable process runs at + least its minimum of the chosen build; off, the big M releases the row dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 - expression: Process_maintenance_status <= Process_status + where: Process_com_ext + expression: >- + Process_p >= + Process_p_min_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) + + Process_big_m * Process_status - Process_big_m ``` ```math -\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) + \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} - \mathrm{M}^{z}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -### `Process-maint-modstatus-le-maint` +### `Process-com-ext-p-lower-nonneg` -`Process_maint_modstatus_le_maint` +`Process_com_ext_p_lower_nonneg` ```yaml -Process_maint_modstatus_le_maint: +Process_com_ext_p_lower_nonneg: description: >- - `Process-maint-modstatus-le-maint` — out of maintenance, no module is on in - maintenance; in it, at most the modules the build cap holds + `Process-com-ext-p-lower-nonneg` — where no minimum-per-unit is + negative, internal power is also plainly non-negative, a row the big-M lower + cannot assert while the process is off dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 - expression: Process_maintenance_status <= Process_p_nom_max / Process_p_nom_mod * Process_maintenance + where: Process_com_ext AND Process_p_min_pu_nonneg + expression: Process_p >= 0 ``` ```math -\mu^{z,u}_{j,\xi,t} \le \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +z_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \mathrm{nonneg}^{z}_{j} ``` -### `Process-maint-modstatus-lb` +### `Process-com-ext-p-upper-bigM` -`Process_maint_modstatus_lb` +`Process_com_ext_p_upper_big_m` ```yaml -Process_maint_modstatus_lb: - description: "`Process-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" +Process_com_ext_p_upper_big_m: + description: "`Process-com-ext-p-upper-bigM` — off, a process does not run; on, the big M is no bound" dims: [scenario, snapshot, process] - where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 - expression: Process_maintenance_status >= Process_status - Process_p_nom_max / Process_p_nom_mod * (1 - Process_maintenance) + where: Process_com_ext + expression: Process_p <= Process_big_m * Process_status ``` ```math -\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +z_{j,\xi,t} \le \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -### `Line-fix-s-lower` +### `Process-com-ext-p-upper-cap` -`Line_fix_s_lower` +`Process_com_ext_p_upper_cap` ```yaml -Line_fix_s_lower: - description: "`Line-fix-s-lower` — a fixed line carries at least the negative of its rating, the loss counted against it" - dims: [scenario, snapshot, line] - where: not Line_s_nom_extendable AND Line_active - expression: Line_s - Line_loss >= -Line_s_max_pu * Line_s_nom +Process_com_ext_p_upper_cap: + description: >- + `Process-com-ext-p-upper-cap` — a committed extendable process runs + at most what is available of the chosen build, whatever its status + dims: [scenario, snapshot, process] + where: Process_com_ext + expression: Process_p <= Process_p_max_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) ``` ```math -s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -### `Line-fix-s-upper` +### `Process-com-mod-p-lower` -`Line_fix_s_upper` +`Process_com_mod_p_lower` ```yaml -Line_fix_s_upper: - description: "`Line-fix-s-upper` — a fixed line carries at most its rating, the loss included" - dims: [scenario, snapshot, line] - where: not Line_s_nom_extendable AND Line_active - expression: Line_s + Line_loss <= Line_s_max_pu * Line_s_nom +Process_com_mod_p_lower: + description: >- + `Process-com-mod-p-lower` — a committed modular process runs at least + its minimum of one module, whether the build is fixed or a decision + dims: [scenario, snapshot, process] + where: Process_committed AND Process_p_nom_mod > 0 + expression: Process_p >= Process_p_min_pu * Process_p_nom_mod * (Process_status - Process_maintenance_pu * Process_maintenance_status) ``` ```math -s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Line-ext-s-lower` +### `Process-com-mod-p-upper` -`Line_ext_s_lower` +`Process_com_mod_p_upper` ```yaml -Line_ext_s_lower: - description: "`Line-ext-s-lower` — an extendable line carries at least the negative of its rating of the chosen build, the loss counted against it" - dims: [scenario, snapshot, line] - where: Line_s_nom_extendable AND Line_active - expression: Line_s - Line_loss >= -Line_s_max_pu * Line_s_nom_ext +Process_com_mod_p_upper: + description: >- + `Process-com-mod-p-upper` — a committed modular process runs at most + one module's share, whether the build is fixed or a decision + dims: [scenario, snapshot, process] + where: Process_committed AND Process_p_nom_mod > 0 + expression: Process_p <= Process_p_max_pu * Process_p_nom_mod * (Process_status - Process_maintenance_pu * Process_maintenance_status) ``` ```math -s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Line-ext-s-upper` +### `Process-com-p-lower` -`Line_ext_s_upper` +`Process_com_p_lower` ```yaml -Line_ext_s_upper: - description: "`Line-ext-s-upper` — an extendable line carries at most its rating of the chosen build, the loss included" - dims: [scenario, snapshot, line] - where: Line_s_nom_extendable AND Line_active - expression: Line_s + Line_loss <= Line_s_max_pu * Line_s_nom_ext +Process_com_p_lower: + description: "`Process-com-p-lower` — a committed process runs at least its minimum; off, at least nothing" + dims: [scenario, snapshot, process] + where: Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) + expression: Process_p >= Process_p_min_pu * Process_p_nom * (Process_status - Process_maintenance_pu * Process_maintenance_status) ``` ```math -s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Line-ext-s_nom-lower` +### `Process-com-p-upper` -`Line_ext_s_nom_lower` +`Process_com_p_upper` ```yaml -Line_ext_s_nom_lower: - description: "`Line-ext-s_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, line] - where: Line_s_nom_extendable AND Line_active_asset - expression: Line_s_nom_ext >= Line_s_nom_min +Process_com_p_upper: + description: "`Process-com-p-upper` — a committed process runs at most what is available; off, at most nothing" + dims: [scenario, snapshot, process] + where: Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) + expression: Process_p <= Process_p_max_pu * Process_p_nom * (Process_status - Process_maintenance_pu * Process_maintenance_status) ``` ```math -S_{k} \ge \underline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Line-ext-s_nom-upper` +### `Process-com-status-min_down_time_must_stay_up` -`Line_ext_s_nom_upper` +`Process_com_status_must_stay_down` ```yaml -Line_ext_s_nom_upper: - description: "`Line-ext-s_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, line] - where: Line_s_nom_extendable AND Line_active_asset AND Line_s_nom_max - expression: Line_s_nom_ext <= Line_s_nom_max +Process_com_status_must_stay_down: + description: >- + `Process-com-status-min_down_time_must_stay_up` — a process still serving + the down time it brought in stays off; PyPSA names the row `_must_stay_up` + dims: [scenario, snapshot, process] + where: Process_committed AND Process_must_stay_down + expression: Process_status == 0 ``` ```math -S_{k} \le \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \text{ is defined} +u^{z}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{rest}^{z}_{j,\xi,t} ``` -### `Line-s_nom_set` +### `Process-com-status-min_up_time_must_stay_up` -`Line_s_nom_set` +`Process_com_status_must_stay_up` ```yaml -Line_s_nom_set: - description: "`Line-s_nom_set` — the chosen build pinned, wherever a value is given" - dims: [line] - where: Line_s_nom_extendable AND Line_active_asset AND Line_s_nom_set - expression: Line_s_nom_ext == Line_s_nom_set +Process_com_status_must_stay_up: + description: "`Process-com-status-min_up_time_must_stay_up` — a process still serving the up time it brought in stays on" + dims: [scenario, snapshot, process] + where: Process_committed AND Process_must_stay_up + expression: Process_status == 1 ``` ```math -S_{k} = \mathrm{s}^{\mathrm{nom,set}}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \mathrm{s}^{\mathrm{nom,set}}_{k} \text{ is defined} +u^{z}_{j,\xi,t} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{hold}^{z}_{j,\xi,t} ``` -### `Line-s_nom_modularity` +### `Process-com-transition-shut-down` -`Line_s_nom_modularity` +`Process_com_transition_shut_down` ```yaml -Line_s_nom_modularity: - description: "`Line-s_nom_modularity` — the chosen build is a whole number of modules" - dims: [line] - where: Line_s_nom_extendable AND Line_s_nom_mod > 0 AND Line_active_asset - expression: Line_s_nom_ext == Line_s_nom_mod * Line_n_mod +Process_com_transition_shut_down: + description: "`Process-com-transition-shut-down` — turning off is a stop, counted against the state the process carried into the snapshot" + dims: [scenario, snapshot, process] + where: Process_committed + expression: Process_shut_down >= Process_previous_status - Process_status ``` ```math -S_{k} = \mathrm{s}^{\mathrm{mod}}_{k} \cdot N^{s}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} +\mathit{dn}^{z}_{j,\xi,t} \ge \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -### `Line-s_set` +### `Process-com-transition-start-up` -`Line_s_set` +`Process_com_transition_start_up` ```yaml -Line_s_set: - description: "`Line-s_set` — flow pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, line] - where: Line_s_set AND Line_active - expression: Line_s == Line_s_set +Process_com_transition_start_up: + description: "`Process-com-transition-start-up` — turning on is a start, counted against the state the process carried into the snapshot" + dims: [scenario, snapshot, process] + where: Process_committed + expression: Process_start_up >= Process_status - Process_previous_status ``` ```math -s_{k,\xi,t} = \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \text{ is defined} \wedge \mathrm{on}^{s}_{k,t} +\mathit{up}^{z}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -### `Line-v_ang-lower` +### `Process-com-up-time` -`Line_v_ang_lower` +`Process_com_up_time` ```yaml -Line_v_ang_lower: +Process_com_up_time: description: >- - `Line-v_ang-lower` — an AC line carries at least the flow at which the - voltage angle difference across it, `x_pu_eff` times the flow in - radians, is the negative of its limit - dims: [scenario, snapshot, line] - where: Line_v_ang_max AND Line_carrier == 'AC' AND Line_active - expression: Line_s >= -Line_v_ang_max * (3.141592653589793 / 180) / Line_x_pu_eff + `Process-com-up-time` — a process started within its own minimum up time + is still on. The first snapshot's share of the window is the brought-in + up time's, which the must-stay-up mask carries + dims: [scenario, snapshot, process] + where: Process_committed AND Process_min_up_time > 0 AND position(snapshot) > 0 + expression: sum_back(Process_start_up, along=snapshot, window=Process_min_up_time) <= Process_status ``` ```math -s_{k,\xi,t} \ge \frac{-\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{z}} \mathit{up}^{z}_{j,\xi,t'} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{UT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -### `Line-v_ang-upper` +### `Process-ext-p-lower` -`Line_v_ang_upper` +`Process_ext_p_lower` ```yaml -Line_v_ang_upper: - description: >- - `Line-v_ang-upper` — an AC line carries at most the flow at which the - voltage angle difference across it reaches its limit - dims: [scenario, snapshot, line] - where: Line_v_ang_max AND Line_carrier == 'AC' AND Line_active - expression: Line_s <= Line_v_ang_max * (3.141592653589793 / 180) / Line_x_pu_eff +Process_ext_p_lower: + description: "`Process-ext-p-lower` — an extendable process runs at least its minimum of the chosen build, negative for the other way" + dims: [scenario, snapshot, process] + where: Process_p_nom_extendable AND not Process_committable AND Process_active + expression: Process_p >= Process_p_min_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) ``` ```math -s_{k,\xi,t} \le \frac{\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Line-loss_upper` +### `Process-ext-p_nom-lower` -`Line_loss_upper` +`Process_ext_p_nom_lower` ```yaml -Line_loss_upper: - description: "`Line-loss_upper` — a line dissipates at most the loss at its rating" - dims: [scenario, snapshot, line] - where: Line_lossy - expression: Line_loss <= Line_loss_max +Process_ext_p_nom_lower: + description: "`Process-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, process] + where: Process_p_nom_extendable AND Process_active_asset + expression: Process_p_nom_ext >= Process_p_nom_min ``` ```math -\ell_{k,\xi,t} \le \overline{\ell}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +Z_{j} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} ``` -### `Line-loss_tangents-{k}-1` +### `Process-ext-p_nom-upper` -`Line_loss_tangents_forward` +`Process_ext_p_nom_upper` ```yaml -Line_loss_tangents_forward: - description: >- - `Line-loss_tangents-{k}-1`, `Line-loss_secants-pos` — the loss sits above - every cut to its curve for flow one way; PyPSA names one row per tangent - `k`, or one row stacked over its `secant` axis, and this entry states them - all over the segment dimension - dims: [scenario, snapshot, line, segment] - where: Line_lossy - expression: Line_loss + Line_loss_slope * Line_s >= Line_loss_offset +Process_ext_p_nom_upper: + description: "`Process-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, process] + where: Process_p_nom_extendable AND Process_active_asset AND Process_p_nom_max + expression: Process_p_nom_ext <= Process_p_nom_max ``` ```math -\ell_{k,\xi,t} + \mathrm{a}_{k,\xi,b,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,b,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +Z_{j} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \text{ is defined} ``` -### `Line-loss_tangents-{k}--1` +### `Process-ext-p-upper` -`Line_loss_tangents_reverse` +`Process_ext_p_upper` ```yaml -Line_loss_tangents_reverse: - description: >- - `Line-loss_tangents-{k}--1`, `Line-loss_secants-neg` — the same fan - mirrored, the loss depending on the flow's magnitude - dims: [scenario, snapshot, line, segment] - where: Line_lossy - expression: Line_loss - Line_loss_slope * Line_s >= Line_loss_offset +Process_ext_p_upper: + description: "`Process-ext-p-upper` — an extendable process runs at most the chosen build" + dims: [scenario, snapshot, process] + where: Process_p_nom_extendable AND not Process_committable AND Process_active + expression: Process_p <= Process_p_max_pu * (Process_p_nom_ext - Process_maintenance_pu * Process_maintenance_capacity) ``` ```math -\ell_{k,\xi,t} - \mathrm{a}_{k,\xi,b,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,b,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Transformer-fix-s-lower` - -`Transformer_fix_s_lower` +### `Process-fix-p-lower` -```yaml -Transformer_fix_s_lower: - description: "`Transformer-fix-s-lower` — a fixed transformer carries at least the negative of its rating, the loss counted against it" - dims: [scenario, snapshot, transformer] - where: not Transformer_s_nom_extendable AND Transformer_active - expression: Transformer_s - Transformer_loss >= -Transformer_s_max_pu * Transformer_s_nom +`Process_fix_p_lower` + +```yaml +Process_fix_p_lower: + description: "`Process-fix-p-lower` — a fixed process runs at least its minimum, negative for the other way" + dims: [scenario, snapshot, process] + where: not Process_p_nom_extendable AND not Process_committable AND Process_active + expression: Process_p >= Process_p_min_pu * Process_p_nom * (1 - Process_maintenance_pu * Process_maintenance) ``` ```math -\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Transformer-fix-s-upper` +### `Process-fix-p-upper` -`Transformer_fix_s_upper` +`Process_fix_p_upper` ```yaml -Transformer_fix_s_upper: - description: "`Transformer-fix-s-upper` — a fixed transformer carries at most its rating, the loss included" - dims: [scenario, snapshot, transformer] - where: not Transformer_s_nom_extendable AND Transformer_active - expression: Transformer_s + Transformer_loss <= Transformer_s_max_pu * Transformer_s_nom +Process_fix_p_upper: + description: "`Process-fix-p-upper` — a fixed process runs at most its nominal power" + dims: [scenario, snapshot, process] + where: not Process_p_nom_extendable AND not Process_committable AND Process_active + expression: Process_p <= Process_p_max_pu * Process_p_nom * (1 - Process_maintenance_pu * Process_maintenance) ``` ```math -\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Transformer-ext-s-lower` +### `Process-maint-event-count` -`Transformer_ext_s_lower` +`Process_maint_event_count` ```yaml -Transformer_ext_s_lower: - description: "`Transformer-ext-s-lower` — an extendable transformer carries at least the negative of its rating of the chosen build, the loss counted against it" - dims: [scenario, snapshot, transformer] - where: Transformer_s_nom_extendable AND Transformer_active - expression: Transformer_s - Transformer_loss >= -Transformer_s_max_pu * Transformer_s_nom_ext +Process_maint_event_count: + description: "`Process-maint-event-count` — a maintainable process holds its number of maintenance events over the horizon" + dims: [scenario, process] + where: Process_maintainable + expression: sum(Process_maintenance_start, over=snapshot) == Process_maintenance_events ``` ```math -\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\sum_{t \in \mathcal{T}} \mu^{z,\mathrm{up}}_{j,\xi,t} = \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -### `Transformer-ext-s-upper` +### `Process-maint-modstatus-lb` -`Transformer_ext_s_upper` +`Process_maint_modstatus_lb` ```yaml -Transformer_ext_s_upper: - description: "`Transformer-ext-s-upper` — an extendable transformer carries at most its rating of the chosen build, the loss included" - dims: [scenario, snapshot, transformer] - where: Transformer_s_nom_extendable AND Transformer_active - expression: Transformer_s + Transformer_loss <= Transformer_s_max_pu * Transformer_s_nom_ext +Process_maint_modstatus_lb: + description: "`Process-maint-modstatus-lb` — in maintenance, every module on is on in maintenance" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 + expression: Process_maintenance_status >= Process_status - Process_p_nom_max / Process_p_nom_mod * (1 - Process_maintenance) ``` ```math -\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Transformer-ext-s_nom-lower` +### `Process-maint-modstatus-le-maint` -`Transformer_ext_s_nom_lower` +`Process_maint_modstatus_le_maint` ```yaml -Transformer_ext_s_nom_lower: - description: "`Transformer-ext-s_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, transformer] - where: Transformer_s_nom_extendable AND Transformer_active_asset - expression: Transformer_s_nom_ext >= Transformer_s_nom_min +Process_maint_modstatus_le_maint: + description: >- + `Process-maint-modstatus-le-maint` — out of maintenance, no module is on in + maintenance; in it, at most the modules the build cap holds + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 + expression: Process_maintenance_status <= Process_p_nom_max / Process_p_nom_mod * Process_maintenance ``` ```math -\Sigma_{m} \ge \underline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} +\mu^{z,u}_{j,\xi,t} \le \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Transformer-ext-s_nom-upper` +### `Process-maint-modstatus-le-status` -`Transformer_ext_s_nom_upper` +`Process_maint_modstatus_le_status` ```yaml -Transformer_ext_s_nom_upper: - description: "`Transformer-ext-s_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, transformer] - where: Transformer_s_nom_extendable AND Transformer_active_asset AND Transformer_s_nom_max - expression: Transformer_s_nom_ext <= Transformer_s_nom_max +Process_maint_modstatus_le_status: + description: "`Process-maint-modstatus-le-status` — the modules on in maintenance are at most the modules on" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND Process_p_nom_mod > 0 + expression: Process_maintenance_status <= Process_status ``` ```math -\Sigma_{m} \le \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \text{ is defined} +\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Transformer-s_nom_set` +### `Process-maint-start-horizon` -`Transformer_s_nom_set` +`Process_maint_start_horizon` ```yaml -Transformer_s_nom_set: - description: "`Transformer-s_nom_set` — the chosen build pinned, wherever a value is given" - dims: [transformer] - where: Transformer_s_nom_extendable AND Transformer_active_asset AND Transformer_s_nom_set - expression: Transformer_s_nom_ext == Transformer_s_nom_set +Process_maint_start_horizon: + description: "`Process-maint-start-horizon` — no event starts where it could not run its whole duration" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_active AND Process_maintenance_start_blocked + expression: Process_maintenance_start == 0 ``` ```math -\Sigma_{m} = \sigma^{\mathrm{nom,set}}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \sigma^{\mathrm{nom,set}}_{m} \text{ is defined} +\mu^{z,\mathrm{up}}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \wedge \mathrm{blk}^{z}_{j,\xi,t} ``` -### `Transformer-s_nom_modularity` +### `Process-maint-status-lb` -`Transformer_s_nom_modularity` +`Process_maint_status_lb` ```yaml -Transformer_s_nom_modularity: - description: "`Transformer-s_nom_modularity` — the chosen build is a whole number of modules" - dims: [transformer] - where: Transformer_s_nom_extendable AND Transformer_s_nom_mod > 0 AND Transformer_active_asset - expression: Transformer_s_nom_ext == Transformer_s_nom_mod * Transformer_n_mod +Process_maint_status_lb: + description: "`Process-maint-status-lb` — on and in maintenance, the status in maintenance is one" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) + expression: Process_maintenance_status >= Process_status + Process_maintenance - 1 ``` ```math -\Sigma_{m} = \sigma^{\mathrm{mod}}_{m} \cdot N^{\sigma}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} +\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} + \mu^{z}_{j,\xi,t} - 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Transformer-s_set` +### `Process-maint-status-le-maint` -`Transformer_s_set` +`Process_maint_status_le_maint` ```yaml -Transformer_s_set: - description: "`Transformer-s_set` — flow pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, transformer] - where: Transformer_s_set AND Transformer_active - expression: Transformer_s == Transformer_s_set +Process_maint_status_le_maint: + description: "`Process-maint-status-le-maint` — out of maintenance, the status in maintenance is zero" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) + expression: Process_maintenance_status <= Process_maintenance ``` ```math -\sigma_{\xi,t,m} = \sigma^{\mathrm{set}}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \sigma^{\mathrm{set}}_{\xi,t,m} \text{ is defined} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z,u}_{j,\xi,t} \le \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Transformer-v_ang-lower` +### `Process-maint-status-le-status` -`Transformer_v_ang_lower` +`Process_maint_status_le_status` ```yaml -Transformer_v_ang_lower: - description: >- - `Transformer-v_ang-lower` — a transformer with a fixed shift carries at - least the flow at which the voltage angle difference across it, - `x_pu_eff` times the flow plus the shift, is the negative of its limit - dims: [scenario, snapshot, transformer] - where: Transformer_v_ang_max AND NOT Transformer_phase_shift_varying AND Transformer_active - expression: Transformer_s >= -(Transformer_v_ang_max + Transformer_phase_shift_fixed) * (3.141592653589793 / 180) / Transformer_x_pu_eff +Process_maint_status_le_status: + description: "`Process-maint-status-le-status` — the status in maintenance is at most the status" + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_committed AND NOT Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0) + expression: Process_maintenance_status <= Process_status ``` ```math -\sigma_{\xi,t,m} \ge \frac{-\left( \overline{\delta}^{\sigma}_{\xi,m} + \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Transformer-v_ang-upper` +### `Process-maint-window` -`Transformer_v_ang_upper` +`Process_maint_window` ```yaml -Transformer_v_ang_upper: +Process_maint_window: description: >- - `Transformer-v_ang-upper` — a transformer with a fixed shift carries at - most the flow at which the voltage angle difference across it, the - shift included, reaches its limit - dims: [scenario, snapshot, transformer] - where: Transformer_v_ang_max AND NOT Transformer_phase_shift_varying AND Transformer_active - expression: Transformer_s <= (Transformer_v_ang_max - Transformer_phase_shift_fixed) * (3.141592653589793 / 180) / Transformer_x_pu_eff + `Process-maint-window` — a process is in maintenance exactly where an event it + started covers the snapshot; two events do not overlap, since the + maintenance status is at most one + dims: [scenario, snapshot, process] + where: Process_maintainable AND Process_active + expression: Process_maintenance == sum(Process_maintenance_start, over=start, by=Process_maintenance_cover[covered]) ``` ```math -\sigma_{\xi,t,m} \le \frac{\left( \overline{\delta}^{\sigma}_{\xi,m} - \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z}_{j,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ j,\ \xi,\ t' \right) \in \mathrm{Process\_maintenance\_cover}} \mu^{z,\mathrm{up}}_{j,\xi,t'} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Transformer-v_ang-var-lower` +### `Process-maintcap_lower_nommax` -`Transformer_v_ang_var_lower` +`Process_maintcap_lower_nommax` ```yaml -Transformer_v_ang_var_lower: - description: >- - `Transformer-v_ang-var-lower` — for a transformer whose shift is a - decision, the flow plus the shift over `x_pu_eff` is at least the - negative of the limit over `x_pu_eff` - dims: [scenario, snapshot, transformer] - where: Transformer_v_ang_max AND Transformer_phase_shift_varying AND Transformer_active - expression: Transformer_s + Transformer_phase_shift * (3.141592653589793 / 180) / Transformer_x_pu_eff >= -Transformer_v_ang_max * (3.141592653589793 / 180) / Transformer_x_pu_eff +Process_maintcap_lower_nommax: + description: "`Process-maintcap_lower_nommax` — in maintenance, the whole chosen build is taken off" + dims: [scenario, snapshot, process] + where: Process_maint_ext + expression: Process_maintenance_capacity >= Process_p_nom_ext - Process_p_nom_max * (1 - Process_maintenance) ``` ```math -\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \ge \frac{-\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge Z_{j} - \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -### `Transformer-v_ang-var-upper` +### `Process-maintcap_lower_nommin` -`Transformer_v_ang_var_upper` +`Process_maintcap_lower_nommin` ```yaml -Transformer_v_ang_var_upper: - description: >- - `Transformer-v_ang-var-upper` — for a transformer whose shift is a - decision, the flow plus the shift over `x_pu_eff` is at most the limit - over `x_pu_eff` - dims: [scenario, snapshot, transformer] - where: Transformer_v_ang_max AND Transformer_phase_shift_varying AND Transformer_active - expression: Transformer_s + Transformer_phase_shift * (3.141592653589793 / 180) / Transformer_x_pu_eff <= Transformer_v_ang_max * (3.141592653589793 / 180) / Transformer_x_pu_eff +Process_maintcap_lower_nommin: + description: "`Process-maintcap_lower_nommin` — in maintenance, at least the floor of the build is taken off" + dims: [scenario, snapshot, process] + where: Process_maint_ext AND Process_p_nom_min > 0 + expression: Process_maintenance_capacity >= Process_p_nom_min * Process_maintenance ``` ```math -\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \le \frac{\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} \wedge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} > 0 ``` -### `Transformer-loss_upper` +### `Process-maintcap_upper` -`Transformer_loss_upper` +`Process_maintcap_upper` ```yaml -Transformer_loss_upper: - description: "`Transformer-loss_upper` — a transformer dissipates at most the loss at its rating" - dims: [scenario, snapshot, transformer] - where: Transformer_lossy - expression: Transformer_loss <= Transformer_loss_max +Process_maintcap_upper: + description: >- + `Process-maintcap_upper` — the build taken off is at most the chosen build in + maintenance, and at most the build less its floor out of it + dims: [scenario, snapshot, process] + where: Process_maint_ext + expression: Process_maintenance_capacity <= Process_p_nom_ext - Process_p_nom_min * (1 - Process_maintenance) ``` ```math -\ell^{\sigma}_{\xi,t,m} \le \overline{\ell}^{\sigma}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +\mu^{z,\mathrm{nom}}_{j,\xi,t} \le Z_{j} - \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -### `Transformer-loss_tangents-{k}-1` +### `Process-maintcap_upper_nommax` -`Transformer_loss_tangents_forward` +`Process_maintcap_upper_nommax` ```yaml -Transformer_loss_tangents_forward: - description: >- - `Transformer-loss_tangents-{k}-1`, `Transformer-loss_secants-pos` — the - loss sits above every cut to its curve for flow one way, as a line's - does, over the segment dimension - dims: [scenario, snapshot, transformer, segment] - where: Transformer_lossy - expression: Transformer_loss + Transformer_loss_slope * Transformer_s >= Transformer_loss_offset +Process_maintcap_upper_nommax: + description: "`Process-maintcap_upper_nommax` — out of maintenance, no build is taken off" + dims: [scenario, snapshot, process] + where: Process_maint_ext + expression: Process_maintenance_capacity <= Process_p_nom_max * Process_maintenance ``` ```math -\ell^{\sigma}_{\xi,t,m} + \mathrm{a}^{\sigma}_{\xi,b,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,b,t,m} \qquad \forall\, \xi \in \Xi,\ b \in \mathcal{B},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +\mu^{z,\mathrm{nom}}_{j,\xi,t} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -### `Transformer-loss_tangents-{k}--1` +### `Process-p_nom_modularity` -`Transformer_loss_tangents_reverse` +`Process_p_nom_modularity` ```yaml -Transformer_loss_tangents_reverse: - description: >- - `Transformer-loss_tangents-{k}--1`, `Transformer-loss_secants-neg` — the - same fan mirrored, the loss depending on the flow's magnitude - dims: [scenario, snapshot, transformer, segment] - where: Transformer_lossy - expression: Transformer_loss - Transformer_loss_slope * Transformer_s >= Transformer_loss_offset +Process_p_nom_modularity: + description: "`Process-p_nom_modularity` — the chosen build is a whole number of modules" + dims: [process] + where: Process_p_nom_extendable AND Process_p_nom_mod > 0 AND Process_active_asset + expression: Process_p_nom_ext == Process_p_nom_mod * Process_n_mod ``` ```math -\ell^{\sigma}_{\xi,t,m} - \mathrm{a}^{\sigma}_{\xi,b,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,b,t,m} \qquad \forall\, \xi \in \Xi,\ b \in \mathcal{B},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +Z_{j} = \mathrm{z}^{\mathrm{mod}}_{j} \cdot N^{z}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} ``` -### `Line-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p_nom_set` -`Line_fix_s_lower_security` +`Process_p_nom_set` ```yaml -Line_fix_s_lower_security: - description: >- - `Line-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` — - after any one outage, a fixed line carries at least the negative - of its rating: its flow takes on its share of the outaged branch's - flow. PyPSA names one row per outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, line, outage] - where: not Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) - expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s >= -Line_s_max_pu * Line_s_nom +Process_p_nom_set: + description: "`Process-p_nom_set` — the chosen build pinned, wherever a value is given" + dims: [process] + where: Process_p_nom_extendable AND Process_active_asset AND Process_p_nom_set + expression: Process_p_nom_ext == Process_p_nom_set ``` ```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} +Z_{j} = \mathrm{z}^{\mathrm{nom,set}}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \mathrm{z}^{\mathrm{nom,set}}_{j} \text{ is defined} ``` -### `Line-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_down` -`Line_fix_s_upper_security` +`Process_p_ramp_limit_down` ```yaml -Line_fix_s_upper_security: +Process_p_ramp_limit_down: description: >- - `Line-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` — - after any one outage, a fixed line carries at most its rating: its - flow takes on its share of the outaged branch's flow. PyPSA names - one row per outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, line, outage] - where: not Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) - expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s <= Line_s_max_pu * Line_s_nom + `Process-p-ramp_limit_down` — a process lowers internal power no faster than + its ramp limit of the build, and a committed one no further than its + shut-down ramp in the snapshot it turns off. A process that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the internal power it brought in, and no process carries one at + the start of a later investment period — nor does any process a big M releases instead + dims: [scenario, snapshot, process] + where: >- + (Process_ramp_limit_down OR Process_ramp_limit_shut_down) + AND NOT (Process_committable AND Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0)) + AND Process_ramps_from_previous + AND Process_active + expression: Process_previous_p - Process_p <= Process_ramp_down_allowance ``` ```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} +\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \Delta^{z,-}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Line-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_down-run-bigM` -`Line_ext_s_lower_security` +`Process_p_ramp_limit_down_run_big_m` ```yaml -Line_ext_s_lower_security: +Process_p_ramp_limit_down_run_big_m: description: >- - `Line-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` — - after any one outage, an extendable line carries at least the - negative of its rating of the chosen build: its flow takes on its - share of the outaged branch's flow. PyPSA names one row per - outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, line, outage] - where: Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) - expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s >= -Line_s_max_pu * Line_s_nom_ext + `Process-p-ramp_limit_down-run-bigM` — a committed extendable process + lowers internal power no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns off + dims: [scenario, snapshot, process] + where: >- + Process_com_ext + AND (Process_ramp_limit_down OR Process_ramp_limit_shut_down) + AND Process_ramps_from_previous + expression: >- + Process_previous_p - Process_p <= + Process_ramp_down_rate * Process_p_nom_ext + + Process_big_m - Process_big_m * Process_status ``` ```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} +\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} ``` -### `Line-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_down-shut-bigM` -`Line_ext_s_upper_security` +`Process_p_ramp_limit_down_shut_big_m` ```yaml -Line_ext_s_upper_security: +Process_p_ramp_limit_down_shut_big_m: description: >- - `Line-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` — - after any one outage, an extendable line carries at most its rating - of the chosen build: its flow takes on its share of the outaged - branch's flow. PyPSA names one row per outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, line, outage] - where: Line_s_nom_extendable AND at(Line_BODF, by=snapshot_period[period]) - expression: Line_s_monitored + at(Line_BODF, by=snapshot_period[period]) * Outage_s <= Line_s_max_pu * Line_s_nom_ext + `Process-p-ramp_limit_down-shut-bigM` — in the snapshot it turns off, + a committed extendable process ramps no further than its shut-down ramp of + the chosen build; the big M releases the row everywhere else + dims: [scenario, snapshot, process] + where: >- + Process_com_ext + AND (Process_ramp_limit_down OR Process_ramp_limit_shut_down) + AND Process_ramps_from_previous + expression: >- + Process_previous_p - Process_p <= + Process_shut_down_rate * Process_p_nom_ext + + Process_big_m - Process_big_m * Process_shut_down ``` ```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} +\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{dn}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} ``` -### `Transformer-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_up` -`Transformer_fix_s_lower_security` +`Process_p_ramp_limit_up` ```yaml -Transformer_fix_s_lower_security: +Process_p_ramp_limit_up: description: >- - `Transformer-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` - — after any one outage, a fixed transformer carries at least the - negative of its rating: its flow takes on its share of the outaged - branch's flow. PyPSA names one row per outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, transformer, outage] - where: not Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) - expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s >= -Transformer_s_max_pu * Transformer_s_nom + `Process-p-ramp_limit_up` — a process raises internal power no faster than + its ramp limit of the build, and a committed one no further than its + start-up ramp in the snapshot it turns on. A process that came into the + horizon running carries a row at the first snapshot only where its + `p_init` gives the internal power it brought in, and no process carries one at + the start of a later investment period — nor does any process a big M releases instead + dims: [scenario, snapshot, process] + where: >- + (Process_ramp_limit_up OR Process_ramp_limit_start_up) + AND NOT (Process_committable AND Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0)) + AND Process_ramps_from_previous + AND Process_active + expression: Process_p - Process_previous_p <= Process_ramp_up_allowance ``` ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \Delta^{z,+}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Transformer-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_up-run-bigM` -`Transformer_fix_s_upper_security` +`Process_p_ramp_limit_up_run_big_m` ```yaml -Transformer_fix_s_upper_security: +Process_p_ramp_limit_up_run_big_m: description: >- - `Transformer-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` - — after any one outage, a fixed transformer carries at most its - rating: its flow takes on its share of the outaged branch's flow. - PyPSA names one row per outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, transformer, outage] - where: not Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) - expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s <= Transformer_s_max_pu * Transformer_s_nom + `Process-p-ramp_limit_up-run-bigM` — a committed extendable process + raises internal power no faster than its limit of the chosen build; the big M + releases the row in the snapshot it turns on + dims: [scenario, snapshot, process] + where: Process_com_ext AND (Process_ramp_limit_up OR Process_ramp_limit_start_up) AND Process_ramps_from_previous + expression: >- + Process_p - Process_previous_p <= + Process_ramp_up_rate * Process_p_nom_ext + + Process_big_m - Process_big_m * Process_previous_status ``` ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} ``` -### `Transformer-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p-ramp_limit_up-start-bigM` -`Transformer_ext_s_lower_security` +`Process_p_ramp_limit_up_start_big_m` ```yaml -Transformer_ext_s_lower_security: +Process_p_ramp_limit_up_start_big_m: description: >- - `Transformer-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` - — after any one outage, an extendable transformer carries at least - the negative of its rating of the chosen build: its flow takes on - its share of the outaged branch's flow. PyPSA names one row per - outaged component `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, transformer, outage] - where: Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) - expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s >= -Transformer_s_max_pu * Transformer_s_nom_ext + `Process-p-ramp_limit_up-start-bigM` — in the snapshot it turns on, a + committed extendable process ramps no further than its start-up ramp of + the chosen build; the big M releases the row everywhere else + dims: [scenario, snapshot, process] + where: Process_com_ext AND (Process_ramp_limit_up OR Process_ramp_limit_start_up) AND Process_ramps_from_previous + expression: >- + Process_p - Process_previous_p <= + Process_start_up_rate * Process_p_nom_ext + + Process_big_m - Process_big_m * Process_start_up ``` ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{up}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} ``` -### `Transformer-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` +### `Process-p_set` -`Transformer_ext_s_upper_security` +`Process_p_set` ```yaml -Transformer_ext_s_upper_security: - description: >- - `Transformer-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` - — after any one outage, an extendable transformer carries at most - its rating of the chosen build: its flow takes on its share of the - outaged branch's flow. PyPSA names one row per outaged component - `c` and - sub-network `n`, and under `multi_investment_periods` it appends - `-period-{p}` for each period `p`. This entry states them all over the - outage dimension - dims: [scenario, snapshot, transformer, outage] - where: Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) - expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s <= Transformer_s_max_pu * Transformer_s_nom_ext +Process_p_set: + description: "`Process-p_set` — internal power pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, process] + where: Process_p_set AND Process_active + expression: Process_p == Process_p_set ``` ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +z_{j,\xi,t} = \mathrm{z}^{\mathrm{set}}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{z}^{\mathrm{set}}_{j,\xi,t} \text{ is defined} \wedge \mathrm{on}^{z}_{j,t} ``` -### `Kirchhoff-Voltage-Law` +### `Process-shut_down-p-fixed-upper` -`Kirchhoff_Voltage_Law` +`Process_shut_down_p_fixed_upper` ```yaml -Kirchhoff_Voltage_Law: - description: >- - `Kirchhoff-Voltage-Law` — around every independent cycle the - impedance-weighted flows sum to nothing, which is what makes the linear - power flow physical rather than transport. A transformer's flow weighs its - effective reactance, and its phase shift enters the cycle sum too: a - constant where the shift is fixed, or the shift decision times its cycle - weight where the shift is a phase-shifting transformer's to choose. A - snapshot reads the cycles of its own period, of the branches that stand - in it (`constraints.py:1622-1638`); a cycle label that period's basis - does not reach has no row - dims: [scenario, snapshot, cycle] - expression: Cycle_angle_sum == 0 +Process_shut_down_p_fixed_upper: + description: >- + `Process-shut_down-p-fixed-upper` — a stop is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, process] + where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) + expression: Process_shut_down <= Process_modules_installed ``` ```math -\sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} + \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} = 0 \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{dn}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Generator-p-ramp_limit_up` +### `Process-shut_down-p_nom-variable-upper` -`Generator_p_ramp_limit_up` +`Process_shut_down_p_nom_variable_upper` ```yaml -Generator_p_ramp_limit_up: - description: >- - `Generator-p-ramp_limit_up` — a generator raises output no faster than - its ramp limit of the build, and a committed one no further than its - start-up ramp in the snapshot it turns on. A unit that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the output it brought in, and no unit carries one at - the start of a later investment period — nor does any unit a big M releases instead - dims: [scenario, snapshot, generator] - where: >- - (Generator_ramp_limit_up OR Generator_ramp_limit_start_up) - AND NOT (Generator_committable AND Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0)) - AND Generator_ramps_from_previous - AND Generator_active - expression: Generator_p - Generator_previous_p <= Generator_ramp_up_allowance +Process_shut_down_p_nom_variable_upper: + description: "`Process-shut_down-p_nom-variable-upper` — a modular process stops only where a module is built" + 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 ``` ```math -p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \Delta^{+}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} +\mathit{dn}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Generator-p-ramp_limit_down` +### `Process-start_up-p-fixed-upper` -`Generator_p_ramp_limit_down` +`Process_start_up_p_fixed_upper` ```yaml -Generator_p_ramp_limit_down: +Process_start_up_p_fixed_upper: description: >- - `Generator-p-ramp_limit_down` — a generator lowers output no faster than - its ramp limit of the build, and a committed one no further than its - shut-down ramp in the snapshot it turns off. A unit that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the output it brought in, and no unit carries one at - the start of a later investment period — nor does any unit a big M releases instead - dims: [scenario, snapshot, generator] - where: >- - (Generator_ramp_limit_down OR Generator_ramp_limit_shut_down) - AND NOT (Generator_committable AND Generator_p_nom_extendable AND NOT (Generator_p_nom_mod > 0)) - AND Generator_ramps_from_previous - AND Generator_active - expression: Generator_previous_p - Generator_p <= Generator_ramp_down_allowance + `Process-start_up-p-fixed-upper` — a start is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, process] + where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) + expression: Process_start_up <= Process_modules_installed ``` ```math -\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \Delta^{-}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} +\mathit{up}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Link-p-ramp_limit_up` +### `Process-start_up-p_nom-variable-upper` -`Link_p_ramp_limit_up` +`Process_start_up_p_nom_variable_upper` ```yaml -Link_p_ramp_limit_up: - description: >- - `Link-p-ramp_limit_up` — a link raises flow no faster than - its ramp limit of the build, and a committed one no further than its - start-up ramp in the snapshot it turns on. A link that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the flow it brought in, and no link carries one at - the start of a later investment period — nor does any link a big M releases instead - dims: [scenario, snapshot, link] - where: >- - (Link_ramp_limit_up OR Link_ramp_limit_start_up) - AND NOT (Link_committable AND Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)) - AND Link_ramps_from_previous - AND Link_active - expression: Link_p - Link_previous_p <= Link_ramp_up_allowance +Process_start_up_p_nom_variable_upper: + description: "`Process-start_up-p_nom-variable-upper` — a modular process starts only where a module is built" + dims: [scenario, snapshot, process] + where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 + expression: Process_start_up <= Process_n_mod ``` ```math -f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \Delta^{f,+}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} +\mathit{up}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Link-p-ramp_limit_down` +### `Process-status-p-fixed-upper` -`Link_p_ramp_limit_down` +`Process_status_p_fixed_upper` ```yaml -Link_p_ramp_limit_down: +Process_status_p_fixed_upper: description: >- - `Link-p-ramp_limit_down` — a link lowers flow no faster than - its ramp limit of the build, and a committed one no further than its - shut-down ramp in the snapshot it turns off. A link that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the flow it brought in, and no link carries one at - the start of a later investment period — nor does any link a big M releases instead - dims: [scenario, snapshot, link] - where: >- - (Link_ramp_limit_down OR Link_ramp_limit_shut_down) - AND NOT (Link_committable AND Link_p_nom_extendable AND NOT (Link_p_nom_mod > 0)) - AND Link_ramps_from_previous - AND Link_active - expression: Link_previous_p - Link_p <= Link_ramp_down_allowance + `Process-status-p-fixed-upper` — a status is at most the modules in + place, an explicit row as PyPSA writes it: one where the build is not + modular, and the fixed build's whole count of modules where it is + dims: [scenario, snapshot, process] + where: Process_committed AND NOT (Process_p_nom_extendable AND Process_p_nom_mod > 0) + expression: Process_status <= Process_modules_installed ``` ```math -\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \Delta^{f,-}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} +u^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -### `Process-p-ramp_limit_up` +### `Process-status-p_nom-variable-upper` -`Process_p_ramp_limit_up` +`Process_status_p_nom_variable_upper` ```yaml -Process_p_ramp_limit_up: - description: >- - `Process-p-ramp_limit_up` — a process raises internal power no faster than - its ramp limit of the build, and a committed one no further than its - start-up ramp in the snapshot it turns on. A process that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the internal power it brought in, and no process carries one at - the start of a later investment period — nor does any process a big M releases instead +Process_status_p_nom_variable_upper: + description: "`Process-status-p_nom-variable-upper` — a modular process is on only where a module is built" dims: [scenario, snapshot, process] - where: >- - (Process_ramp_limit_up OR Process_ramp_limit_start_up) - AND NOT (Process_committable AND Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0)) - AND Process_ramps_from_previous - AND Process_active - expression: Process_p - Process_previous_p <= Process_ramp_up_allowance + where: Process_committed AND Process_p_nom_extendable AND Process_p_nom_mod > 0 + expression: Process_status <= Process_n_mod ``` ```math -z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \Delta^{z,+}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} +u^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Process-p-ramp_limit_down` +### `StorageUnit-energy_balance` -`Process_p_ramp_limit_down` +`StorageUnit_energy_balance` ```yaml -Process_p_ramp_limit_down: +StorageUnit_energy_balance: description: >- - `Process-p-ramp_limit_down` — a process lowers internal power no faster than - its ramp limit of the build, and a committed one no further than its - shut-down ramp in the snapshot it turns off. A process that came into the - horizon running carries a row at the first snapshot only where its - `p_init` gives the internal power it brought in, and no process carries one at - the start of a later investment period — nor does any process a big M releases instead - dims: [scenario, snapshot, process] - where: >- - (Process_ramp_limit_down OR Process_ramp_limit_shut_down) - AND NOT (Process_committable AND Process_p_nom_extendable AND NOT (Process_p_nom_mod > 0)) - AND Process_ramps_from_previous - AND Process_active - expression: Process_previous_p - Process_p <= Process_ramp_down_allowance + `StorageUnit-energy_balance` — the charge carried in, plus what is + stored after its efficiency, less what dispatch draws down before its + own, plus inflow not spilled + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_active + expression: >- + StorageUnit_state_of_charge == + StorageUnit_charge_carried_in + + StorageUnit_efficiency_store * StorageUnit_p_store * snapshot_weightings_stores + - StorageUnit_p_dispatch * snapshot_weightings_stores / StorageUnit_efficiency_dispatch + + (StorageUnit_inflow - StorageUnit_spill) * snapshot_weightings_stores ``` ```math -\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \Delta^{z,-}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} +\mathit{soc}_{\xi,t,s} = \overleftarrow{\mathit{soc}}_{\xi,t,s} + \eta^{-}_{\xi,t,s} \cdot h^{-}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t} - \frac{h^{+}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t}}{\eta^{+}_{\xi,t,s}} + \left( \mathrm{inflow}_{\xi,t,s} - \mathit{spill}_{\xi,t,s} \right) \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` ### `StorageUnit-ext-p_dispatch-lower` @@ -11656,6 +11583,38 @@ StorageUnit_ext_p_dispatch_upper: h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` +### `StorageUnit-ext-p_nom-lower` + +`StorageUnit_ext_p_nom_lower` + +```yaml +StorageUnit_ext_p_nom_lower: + description: "`StorageUnit-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, storage_unit] + where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset + expression: StorageUnit_p_nom_ext >= StorageUnit_p_nom_min +``` + +```math +H_{s} \ge \underline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} +``` + +### `StorageUnit-ext-p_nom-upper` + +`StorageUnit_ext_p_nom_upper` + +```yaml +StorageUnit_ext_p_nom_upper: + description: "`StorageUnit-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, storage_unit] + where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset AND StorageUnit_p_nom_max + expression: StorageUnit_p_nom_ext <= StorageUnit_p_nom_max +``` + +```math +H_{s} \le \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \text{ is defined} +``` + ### `StorageUnit-ext-p_store-lower` `StorageUnit_ext_p_store_lower` @@ -11722,188 +11681,214 @@ StorageUnit_ext_state_of_charge_upper: \mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -### `StorageUnit-ext-p_nom-lower` +### `StorageUnit-fix-p_dispatch-lower` -`StorageUnit_ext_p_nom_lower` +`StorageUnit_fix_p_dispatch_lower` ```yaml -StorageUnit_ext_p_nom_lower: - description: "`StorageUnit-ext-p_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, storage_unit] - where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset - expression: StorageUnit_p_nom_ext >= StorageUnit_p_nom_min +StorageUnit_fix_p_dispatch_lower: + description: "`StorageUnit-fix-p_dispatch-lower` — dispatch is non-negative" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_p_dispatch >= 0 ``` ```math -H_{s} \ge \underline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} +h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -### `StorageUnit-ext-p_nom-upper` +### `StorageUnit-fix-p_dispatch-upper` -`StorageUnit_ext_p_nom_upper` +`StorageUnit_fix_p_dispatch_upper` + +```yaml +StorageUnit_fix_p_dispatch_upper: + description: "`StorageUnit-fix-p_dispatch-upper` — a fixed unit dispatches at most its nominal power" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_p_dispatch <= StorageUnit_p_max_pu * StorageUnit_p_nom +``` + +```math +h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +``` + +### `StorageUnit-fix-p_store-lower` + +`StorageUnit_fix_p_store_lower` + +```yaml +StorageUnit_fix_p_store_lower: + description: "`StorageUnit-fix-p_store-lower` — storing is non-negative" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_p_store >= 0 +``` + +```math +h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +``` + +### `StorageUnit-fix-p_store-upper` + +`StorageUnit_fix_p_store_upper` ```yaml -StorageUnit_ext_p_nom_upper: - description: "`StorageUnit-ext-p_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, storage_unit] - where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset AND StorageUnit_p_nom_max - expression: StorageUnit_p_nom_ext <= StorageUnit_p_nom_max +StorageUnit_fix_p_store_upper: + description: >- + `StorageUnit-fix-p_store-upper` — a fixed unit stores at most its + nominal power, the minimum-per-unit column carrying that cap negated + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_p_store <= -StorageUnit_p_min_pu * StorageUnit_p_nom ``` ```math -H_{s} \le \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \text{ is defined} +h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -### `StorageUnit-p_nom_set` +### `StorageUnit-fix-state_of_charge-lower` -`StorageUnit_p_nom_set` +`StorageUnit_fix_state_of_charge_lower` ```yaml -StorageUnit_p_nom_set: - description: "`StorageUnit-p_nom_set` — the chosen build pinned, wherever a value is given" - dims: [storage_unit] - where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset AND StorageUnit_p_nom_set - expression: StorageUnit_p_nom_ext == StorageUnit_p_nom_set +StorageUnit_fix_state_of_charge_lower: + description: "`StorageUnit-fix-state_of_charge-lower` — charge is non-negative" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_state_of_charge >= 0 ``` ```math -H_{s} = \mathrm{h}^{\mathrm{nom,set}}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \mathrm{h}^{\mathrm{nom,set}}_{s} \text{ is defined} +\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -### `StorageUnit-p_nom_modularity` +### `StorageUnit-fix-state_of_charge-upper` -`StorageUnit_p_nom_modularity` +`StorageUnit_fix_state_of_charge_upper` ```yaml -StorageUnit_p_nom_modularity: - description: "`StorageUnit-p_nom_modularity` — the chosen build is a whole number of modules" - dims: [storage_unit] - where: StorageUnit_p_nom_extendable AND StorageUnit_p_nom_mod > 0 AND StorageUnit_active_asset - expression: StorageUnit_p_nom_ext == StorageUnit_p_nom_mod * StorageUnit_n_mod +StorageUnit_fix_state_of_charge_upper: + description: "`StorageUnit-fix-state_of_charge-upper` — a fixed unit holds at most its hours at nominal power" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_fix + expression: StorageUnit_state_of_charge <= StorageUnit_max_hours * StorageUnit_p_nom ``` ```math -H_{s} = \mathrm{h}^{\mathrm{mod}}_{s} \cdot N^{h}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} +\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -### `StorageUnit-energy_balance` +### `StorageUnit-p_dispatch_set` -`StorageUnit_energy_balance` +`StorageUnit_p_dispatch_set` ```yaml -StorageUnit_energy_balance: - description: >- - `StorageUnit-energy_balance` — the charge carried in, plus what is - stored after its efficiency, less what dispatch draws down before its - own, plus inflow not spilled +StorageUnit_p_dispatch_set: + description: "`StorageUnit-p_dispatch_set` — dispatch pinned to the given schedule, wherever one is given" dims: [scenario, snapshot, storage_unit] - where: StorageUnit_active - expression: >- - StorageUnit_state_of_charge == - StorageUnit_charge_carried_in - + StorageUnit_efficiency_store * StorageUnit_p_store * snapshot_weightings_stores - - StorageUnit_p_dispatch * snapshot_weightings_stores / StorageUnit_efficiency_dispatch - + (StorageUnit_inflow - StorageUnit_spill) * snapshot_weightings_stores + where: StorageUnit_p_dispatch_set AND StorageUnit_active + expression: StorageUnit_p_dispatch == StorageUnit_p_dispatch_set ``` ```math -\mathit{soc}_{\xi,t,s} = \overleftarrow{\mathit{soc}}_{\xi,t,s} + \eta^{-}_{\xi,t,s} \cdot h^{-}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t} - \frac{h^{+}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t}}{\eta^{+}_{\xi,t,s}} + \left( \mathrm{inflow}_{\xi,t,s} - \mathit{spill}_{\xi,t,s} \right) \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +h^{+}_{\xi,t,s} = \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` -### `Store-fix-e-lower` +### `StorageUnit-p_nom_modularity` -`Store_fix_e_lower` +`StorageUnit_p_nom_modularity` ```yaml -Store_fix_e_lower: - description: "`Store-fix-e-lower` — a fixed store holds at least its floor" - dims: [scenario, snapshot, store] - where: not Store_e_nom_extendable AND Store_active - expression: Store_e >= Store_e_min_pu * Store_e_nom +StorageUnit_p_nom_modularity: + description: "`StorageUnit-p_nom_modularity` — the chosen build is a whole number of modules" + dims: [storage_unit] + where: StorageUnit_p_nom_extendable AND StorageUnit_p_nom_mod > 0 AND StorageUnit_active_asset + expression: StorageUnit_p_nom_ext == StorageUnit_p_nom_mod * StorageUnit_n_mod ``` ```math -e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +H_{s} = \mathrm{h}^{\mathrm{mod}}_{s} \cdot N^{h}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} ``` -### `Store-fix-e-upper` +### `StorageUnit-p_nom_set` -`Store_fix_e_upper` +`StorageUnit_p_nom_set` ```yaml -Store_fix_e_upper: - description: "`Store-fix-e-upper` — a fixed store holds at most its nominal capacity" - dims: [scenario, snapshot, store] - where: not Store_e_nom_extendable AND Store_active - expression: Store_e <= Store_e_max_pu * Store_e_nom +StorageUnit_p_nom_set: + description: "`StorageUnit-p_nom_set` — the chosen build pinned, wherever a value is given" + dims: [storage_unit] + where: StorageUnit_p_nom_extendable AND StorageUnit_active_asset AND StorageUnit_p_nom_set + expression: StorageUnit_p_nom_ext == StorageUnit_p_nom_set ``` ```math -e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +H_{s} = \mathrm{h}^{\mathrm{nom,set}}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \mathrm{h}^{\mathrm{nom,set}}_{s} \text{ is defined} ``` -### `Store-ext-e-lower` +### `StorageUnit-p_set` -`Store_ext_e_lower` +`StorageUnit_p_set` ```yaml -Store_ext_e_lower: - description: "`Store-ext-e-lower` — an extendable store holds at least its floor of the chosen build" - dims: [scenario, snapshot, store] - where: Store_e_nom_extendable AND Store_active - expression: Store_e >= Store_e_min_pu * Store_e_nom_ext +StorageUnit_p_set: + description: "`StorageUnit-p_set` — net dispatch pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_p_set AND StorageUnit_active + expression: StorageUnit_p_dispatch - StorageUnit_p_store == StorageUnit_p_set ``` ```math -e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} = \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` -### `Store-ext-e-upper` +### `StorageUnit-p_store_set` -`Store_ext_e_upper` +`StorageUnit_p_store_set` ```yaml -Store_ext_e_upper: - description: "`Store-ext-e-upper` — an extendable store holds at most the chosen build" - dims: [scenario, snapshot, store] - where: Store_e_nom_extendable AND Store_active - expression: Store_e <= Store_e_max_pu * Store_e_nom_ext +StorageUnit_p_store_set: + description: "`StorageUnit-p_store_set` — charging pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_p_store_set AND StorageUnit_active + expression: StorageUnit_p_store == StorageUnit_p_store_set ``` ```math -e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +h^{-}_{\xi,t,s} = \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` -### `Store-ext-e_nom-lower` +### `StorageUnit-state_of_charge_set` -`Store_ext_e_nom_lower` +`StorageUnit_state_of_charge_set` ```yaml -Store_ext_e_nom_lower: - description: "`Store-ext-e_nom-lower` — the chosen build is at least its floor in every scenario" - dims: [scenario, store] - where: Store_e_nom_extendable AND Store_active_asset - expression: Store_e_nom_ext >= Store_e_nom_min +StorageUnit_state_of_charge_set: + description: "`StorageUnit-state_of_charge_set` — charge pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, storage_unit] + where: StorageUnit_state_of_charge_set AND StorageUnit_active + expression: StorageUnit_state_of_charge == StorageUnit_state_of_charge_set ``` ```math -E_{v} \ge \underline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} +\mathit{soc}_{\xi,t,s} = \mathrm{soc}^{\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{soc}^{\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` -### `Store-ext-e_nom-upper` +### `Store-e_nom_modularity` -`Store_ext_e_nom_upper` +`Store_e_nom_modularity` ```yaml -Store_ext_e_nom_upper: - description: "`Store-ext-e_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" - dims: [scenario, store] - where: Store_e_nom_extendable AND Store_active_asset AND Store_e_nom_max - expression: Store_e_nom_ext <= Store_e_nom_max +Store_e_nom_modularity: + description: "`Store-e_nom_modularity` — the chosen build is a whole number of modules" + dims: [store] + where: Store_e_nom_extendable AND Store_e_nom_mod > 0 AND Store_active_asset + expression: Store_e_nom_ext == Store_e_nom_mod * Store_n_mod ``` ```math -E_{v} \le \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \text{ is defined} +E_{v} = \mathrm{e}^{\mathrm{mod}}_{v} \cdot N^{e}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} ``` ### `Store-e_nom_set` @@ -11922,20 +11907,20 @@ Store_e_nom_set: E_{v} = \mathrm{e}^{\mathrm{nom,set}}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \mathrm{e}^{\mathrm{nom,set}}_{v} \text{ is defined} ``` -### `Store-e_nom_modularity` +### `Store-e_set` -`Store_e_nom_modularity` +`Store_e_set` ```yaml -Store_e_nom_modularity: - description: "`Store-e_nom_modularity` — the chosen build is a whole number of modules" - dims: [store] - where: Store_e_nom_extendable AND Store_e_nom_mod > 0 AND Store_active_asset - expression: Store_e_nom_ext == Store_e_nom_mod * Store_n_mod +Store_e_set: + description: "`Store-e_set` — energy pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, store] + where: Store_e_set AND Store_active + expression: Store_e == Store_e_set ``` ```math -E_{v} = \mathrm{e}^{\mathrm{mod}}_{v} \cdot N^{e}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} +e_{\xi,t,v} = \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \text{ is defined} \wedge \mathrm{on}^{e}_{t,v} ``` ### `Store-energy_balance` @@ -11957,132 +11942,100 @@ Store_energy_balance: e_{\xi,t,v} = \overleftarrow{e}_{\xi,t,v} - q_{\xi,t,v} \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} ``` -### `Generator-p_set` - -`Generator_p_set` - -```yaml -Generator_p_set: - description: "`Generator-p_set` — output pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, generator] - where: Generator_p_set AND Generator_active - expression: Generator_p == Generator_p_set -``` - -```math -p_{g,\xi,t} = \mathrm{p}^{\mathrm{set}}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{set}}_{g,\xi,t} \text{ is defined} \wedge \mathrm{on}_{g,t} -``` - -### `Link-p_set` - -`Link_p_set` - -```yaml -Link_p_set: - description: "`Link-p_set` — flow pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, link] - where: Link_p_set AND Link_active - expression: Link_p == Link_p_set -``` - -```math -f_{l,\xi,t} = \mathrm{f}^{\mathrm{set}}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{f}^{\mathrm{set}}_{l,\xi,t} \text{ is defined} \wedge \mathrm{on}^{f}_{l,t} -``` - -### `Process-p_set` +### `Store-ext-e-lower` -`Process_p_set` +`Store_ext_e_lower` ```yaml -Process_p_set: - description: "`Process-p_set` — internal power pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, process] - where: Process_p_set AND Process_active - expression: Process_p == Process_p_set +Store_ext_e_lower: + description: "`Store-ext-e-lower` — an extendable store holds at least its floor of the chosen build" + dims: [scenario, snapshot, store] + where: Store_e_nom_extendable AND Store_active + expression: Store_e >= Store_e_min_pu * Store_e_nom_ext ``` ```math -z_{j,\xi,t} = \mathrm{z}^{\mathrm{set}}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{z}^{\mathrm{set}}_{j,\xi,t} \text{ is defined} \wedge \mathrm{on}^{z}_{j,t} +e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -### `StorageUnit-p_set` +### `Store-ext-e_nom-lower` -`StorageUnit_p_set` +`Store_ext_e_nom_lower` ```yaml -StorageUnit_p_set: - description: "`StorageUnit-p_set` — net dispatch pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_p_set AND StorageUnit_active - expression: StorageUnit_p_dispatch - StorageUnit_p_store == StorageUnit_p_set +Store_ext_e_nom_lower: + description: "`Store-ext-e_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, store] + where: Store_e_nom_extendable AND Store_active_asset + expression: Store_e_nom_ext >= Store_e_nom_min ``` ```math -h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} = \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} +E_{v} \ge \underline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} ``` -### `StorageUnit-p_dispatch_set` +### `Store-ext-e_nom-upper` -`StorageUnit_p_dispatch_set` +`Store_ext_e_nom_upper` ```yaml -StorageUnit_p_dispatch_set: - description: "`StorageUnit-p_dispatch_set` — dispatch pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_p_dispatch_set AND StorageUnit_active - expression: StorageUnit_p_dispatch == StorageUnit_p_dispatch_set +Store_ext_e_nom_upper: + description: "`Store-ext-e_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, store] + where: Store_e_nom_extendable AND Store_active_asset AND Store_e_nom_max + expression: Store_e_nom_ext <= Store_e_nom_max ``` ```math -h^{+}_{\xi,t,s} = \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} +E_{v} \le \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \text{ is defined} ``` -### `StorageUnit-p_store_set` +### `Store-ext-e-upper` -`StorageUnit_p_store_set` +`Store_ext_e_upper` ```yaml -StorageUnit_p_store_set: - description: "`StorageUnit-p_store_set` — charging pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_p_store_set AND StorageUnit_active - expression: StorageUnit_p_store == StorageUnit_p_store_set +Store_ext_e_upper: + description: "`Store-ext-e-upper` — an extendable store holds at most the chosen build" + dims: [scenario, snapshot, store] + where: Store_e_nom_extendable AND Store_active + expression: Store_e <= Store_e_max_pu * Store_e_nom_ext ``` ```math -h^{-}_{\xi,t,s} = \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} +e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -### `StorageUnit-state_of_charge_set` +### `Store-fix-e-lower` -`StorageUnit_state_of_charge_set` +`Store_fix_e_lower` ```yaml -StorageUnit_state_of_charge_set: - description: "`StorageUnit-state_of_charge_set` — charge pinned to the given schedule, wherever one is given" - dims: [scenario, snapshot, storage_unit] - where: StorageUnit_state_of_charge_set AND StorageUnit_active - expression: StorageUnit_state_of_charge == StorageUnit_state_of_charge_set +Store_fix_e_lower: + description: "`Store-fix-e-lower` — a fixed store holds at least its floor" + dims: [scenario, snapshot, store] + where: not Store_e_nom_extendable AND Store_active + expression: Store_e >= Store_e_min_pu * Store_e_nom ``` ```math -\mathit{soc}_{\xi,t,s} = \mathrm{soc}^{\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{soc}^{\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} +e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -### `Store-e_set` +### `Store-fix-e-upper` -`Store_e_set` +`Store_fix_e_upper` ```yaml -Store_e_set: - description: "`Store-e_set` — energy pinned to the given schedule, wherever one is given" +Store_fix_e_upper: + description: "`Store-fix-e-upper` — a fixed store holds at most its nominal capacity" dims: [scenario, snapshot, store] - where: Store_e_set AND Store_active - expression: Store_e == Store_e_set + where: not Store_e_nom_extendable AND Store_active + expression: Store_e <= Store_e_max_pu * Store_e_nom ``` ```math -e_{\xi,t,v} = \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \text{ is defined} \wedge \mathrm{on}^{e}_{t,v} +e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` ### `Store-p_set` @@ -12101,354 +12054,410 @@ Store_p_set: q_{\xi,t,v} = \mathrm{q}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{q}^{\mathrm{set}}_{\xi,t,v} \text{ is defined} \wedge \mathrm{on}^{e}_{t,v} ``` -### `primary_energy` +### `Transformer-ext-s-lower` -`GlobalConstraint_primary_energy_ub` +`Transformer_ext_s_lower` ```yaml -GlobalConstraint_primary_energy_ub: - description: "`primary_energy` — its total, at most its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '<=' - expression: primary_energy <= GlobalConstraint_constant +Transformer_ext_s_lower: + description: "`Transformer-ext-s-lower` — an extendable transformer carries at least the negative of its rating of the chosen build, the loss counted against it" + dims: [scenario, snapshot, transformer] + where: Transformer_s_nom_extendable AND Transformer_active + expression: Transformer_s - Transformer_loss >= -Transformer_s_max_pu * Transformer_s_nom_ext ``` ```math -\mathit{primary\_energy}_{i,\xi} \le \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{<=}\text{'} +\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `primary_energy` +### `Transformer-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` -`GlobalConstraint_primary_energy_lb` +`Transformer_ext_s_lower_security` ```yaml -GlobalConstraint_primary_energy_lb: - description: "`primary_energy` — its total, at least its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '>=' - expression: primary_energy >= GlobalConstraint_constant +Transformer_ext_s_lower_security: + description: >- + `Transformer-ext-s-lower-security-for-{c}-outage-in-sub-network-{n}` + — after any one outage, an extendable transformer carries at least + the negative of its rating of the chosen build: its flow takes on + its share of the outaged branch's flow. PyPSA names one row per + outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, transformer, outage] + where: Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) + expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s >= -Transformer_s_max_pu * Transformer_s_nom_ext ``` ```math -\mathit{primary\_energy}_{i,\xi} \ge \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{>=}\text{'} +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} ``` -### `primary_energy` +### `Transformer-ext-s_nom-lower` -`GlobalConstraint_primary_energy_eq` +`Transformer_ext_s_nom_lower` ```yaml -GlobalConstraint_primary_energy_eq: - description: "`primary_energy` — its total, at its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'primary_energy' AND GlobalConstraint_sense == '==' - expression: primary_energy == GlobalConstraint_constant +Transformer_ext_s_nom_lower: + description: "`Transformer-ext-s_nom-lower` — the chosen build is at least its floor in every scenario" + dims: [scenario, transformer] + where: Transformer_s_nom_extendable AND Transformer_active_asset + expression: Transformer_s_nom_ext >= Transformer_s_nom_min ``` ```math -\mathit{primary\_energy}_{i,\xi} = \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{==}\text{'} +\Sigma_{m} \ge \underline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} ``` -### `operational_limit` +### `Transformer-ext-s_nom-upper` -`GlobalConstraint_operational_limit_ub` +`Transformer_ext_s_nom_upper` ```yaml -GlobalConstraint_operational_limit_ub: - description: "`operational_limit` — its total, at most its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '<=' - expression: operational_limit <= GlobalConstraint_constant +Transformer_ext_s_nom_upper: + description: "`Transformer-ext-s_nom-upper` — the chosen build is at most its cap in every scenario; a cap of infinity is no row" + dims: [scenario, transformer] + where: Transformer_s_nom_extendable AND Transformer_active_asset AND Transformer_s_nom_max + expression: Transformer_s_nom_ext <= Transformer_s_nom_max ``` ```math -\mathit{operational\_limit}_{i,\xi} \le \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{<=}\text{'} +\Sigma_{m} \le \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \text{ is defined} ``` -### `operational_limit` +### `Transformer-ext-s-upper` -`GlobalConstraint_operational_limit_lb` +`Transformer_ext_s_upper` ```yaml -GlobalConstraint_operational_limit_lb: - description: "`operational_limit` — its total, at least its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '>=' - expression: operational_limit >= GlobalConstraint_constant +Transformer_ext_s_upper: + description: "`Transformer-ext-s-upper` — an extendable transformer carries at most its rating of the chosen build, the loss included" + dims: [scenario, snapshot, transformer] + where: Transformer_s_nom_extendable AND Transformer_active + expression: Transformer_s + Transformer_loss <= Transformer_s_max_pu * Transformer_s_nom_ext ``` ```math -\mathit{operational\_limit}_{i,\xi} \ge \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{>=}\text{'} +\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `operational_limit` +### `Transformer-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` -`GlobalConstraint_operational_limit_eq` +`Transformer_ext_s_upper_security` ```yaml -GlobalConstraint_operational_limit_eq: - description: "`operational_limit` — its total, at its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'operational_limit' AND GlobalConstraint_sense == '==' - expression: operational_limit == GlobalConstraint_constant +Transformer_ext_s_upper_security: + description: >- + `Transformer-ext-s-upper-security-for-{c}-outage-in-sub-network-{n}` + — after any one outage, an extendable transformer carries at most + its rating of the chosen build: its flow takes on its share of the + outaged branch's flow. PyPSA names one row per outaged component + `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, transformer, outage] + where: Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) + expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s <= Transformer_s_max_pu * Transformer_s_nom_ext ``` ```math -\mathit{operational\_limit}_{i,\xi} = \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{==}\text{'} +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} ``` -### `transmission_volume_expansion_limit` +### `Transformer-fix-s-lower` -`GlobalConstraint_transmission_volume_expansion_limit_ub` +`Transformer_fix_s_lower` ```yaml -GlobalConstraint_transmission_volume_expansion_limit_ub: - description: "`transmission_volume_expansion_limit` — its total, at most its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '<=' - expression: transmission_volume_expansion <= GlobalConstraint_constant +Transformer_fix_s_lower: + description: "`Transformer-fix-s-lower` — a fixed transformer carries at least the negative of its rating, the loss counted against it" + dims: [scenario, snapshot, transformer] + where: not Transformer_s_nom_extendable AND Transformer_active + expression: Transformer_s - Transformer_loss >= -Transformer_s_max_pu * Transformer_s_nom ``` ```math -\mathit{transmission\_volume\_expansion}_{i,\xi} \le \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{<=}\text{'} +\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `transmission_volume_expansion_limit` +### `Transformer-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` -`GlobalConstraint_transmission_volume_expansion_limit_lb` +`Transformer_fix_s_lower_security` ```yaml -GlobalConstraint_transmission_volume_expansion_limit_lb: - description: "`transmission_volume_expansion_limit` — its total, at least its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '>=' - expression: transmission_volume_expansion >= GlobalConstraint_constant +Transformer_fix_s_lower_security: + description: >- + `Transformer-fix-s-lower-security-for-{c}-outage-in-sub-network-{n}` + — after any one outage, a fixed transformer carries at least the + negative of its rating: its flow takes on its share of the outaged + branch's flow. PyPSA names one row per outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, transformer, outage] + where: not Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) + expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s >= -Transformer_s_max_pu * Transformer_s_nom ``` ```math -\mathit{transmission\_volume\_expansion}_{i,\xi} \ge \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{>=}\text{'} +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} ``` -### `transmission_volume_expansion_limit` +### `Transformer-fix-s-upper` -`GlobalConstraint_transmission_volume_expansion_limit_eq` +`Transformer_fix_s_upper` ```yaml -GlobalConstraint_transmission_volume_expansion_limit_eq: - description: "`transmission_volume_expansion_limit` — its total, at its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_volume_expansion_limit' AND GlobalConstraint_sense == '==' - expression: transmission_volume_expansion == GlobalConstraint_constant +Transformer_fix_s_upper: + description: "`Transformer-fix-s-upper` — a fixed transformer carries at most its rating, the loss included" + dims: [scenario, snapshot, transformer] + where: not Transformer_s_nom_extendable AND Transformer_active + expression: Transformer_s + Transformer_loss <= Transformer_s_max_pu * Transformer_s_nom ``` ```math -\mathit{transmission\_volume\_expansion}_{i,\xi} = \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{==}\text{'} +\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `transmission_expansion_cost_limit` +### `Transformer-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` -`GlobalConstraint_transmission_expansion_cost_limit_ub` +`Transformer_fix_s_upper_security` ```yaml -GlobalConstraint_transmission_expansion_cost_limit_ub: - description: "`transmission_expansion_cost_limit` — its total, at most its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '<=' - expression: transmission_expansion_cost <= GlobalConstraint_constant +Transformer_fix_s_upper_security: + description: >- + `Transformer-fix-s-upper-security-for-{c}-outage-in-sub-network-{n}` + — after any one outage, a fixed transformer carries at most its + rating: its flow takes on its share of the outaged branch's flow. + PyPSA names one row per outaged component `c` and + sub-network `n`, and under `multi_investment_periods` it appends + `-period-{p}` for each period `p`. This entry states them all over the + outage dimension + dims: [scenario, snapshot, transformer, outage] + where: not Transformer_s_nom_extendable AND at(Transformer_BODF, by=snapshot_period[period]) + expression: Transformer_s_monitored + at(Transformer_BODF, by=snapshot_period[period]) * Outage_s <= Transformer_s_max_pu * Transformer_s_nom ``` ```math -\mathit{transmission\_expansion\_cost}_{i,\xi} \le \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{<=}\text{'} +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} ``` -### `transmission_expansion_cost_limit` +### `Transformer-loss_tangents-{k}-1` -`GlobalConstraint_transmission_expansion_cost_limit_lb` +`Transformer_loss_tangents_forward` ```yaml -GlobalConstraint_transmission_expansion_cost_limit_lb: - description: "`transmission_expansion_cost_limit` — its total, at least its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '>=' - expression: transmission_expansion_cost >= GlobalConstraint_constant +Transformer_loss_tangents_forward: + description: >- + `Transformer-loss_tangents-{k}-1`, `Transformer-loss_secants-pos` — the + loss sits above every cut to its curve for flow one way, as a line's + does, over the segment dimension + dims: [scenario, snapshot, transformer, segment] + where: Transformer_lossy + expression: Transformer_loss + Transformer_loss_slope * Transformer_s >= Transformer_loss_offset +``` + +```math +\ell^{\sigma}_{\xi,t,m} + \mathrm{a}^{\sigma}_{\xi,m,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,m,t,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +``` + +### `Transformer-loss_tangents-{k}--1` + +`Transformer_loss_tangents_reverse` + +```yaml +Transformer_loss_tangents_reverse: + description: >- + `Transformer-loss_tangents-{k}--1`, `Transformer-loss_secants-neg` — the + same fan mirrored, the loss depending on the flow's magnitude + dims: [scenario, snapshot, transformer, segment] + where: Transformer_lossy + expression: Transformer_loss - Transformer_loss_slope * Transformer_s >= Transformer_loss_offset ``` ```math -\mathit{transmission\_expansion\_cost}_{i,\xi} \ge \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{>=}\text{'} +\ell^{\sigma}_{\xi,t,m} - \mathrm{a}^{\sigma}_{\xi,m,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,m,t,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -### `transmission_expansion_cost_limit` +### `Transformer-loss_upper` -`GlobalConstraint_transmission_expansion_cost_limit_eq` +`Transformer_loss_upper` ```yaml -GlobalConstraint_transmission_expansion_cost_limit_eq: - description: "`transmission_expansion_cost_limit` — its total, at its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'transmission_expansion_cost_limit' AND GlobalConstraint_sense == '==' - expression: transmission_expansion_cost == GlobalConstraint_constant +Transformer_loss_upper: + description: "`Transformer-loss_upper` — a transformer dissipates at most the loss at its rating" + dims: [scenario, snapshot, transformer] + where: Transformer_lossy + expression: Transformer_loss <= Transformer_loss_max ``` ```math -\mathit{transmission\_expansion\_cost}_{i,\xi} = \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{==}\text{'} +\ell^{\sigma}_{\xi,t,m} \le \overline{\ell}^{\sigma}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -### `tech_capacity_expansion_limit` +### `Transformer-s_nom_modularity` -`GlobalConstraint_tech_capacity_expansion_limit_ub` +`Transformer_s_nom_modularity` ```yaml -GlobalConstraint_tech_capacity_expansion_limit_ub: - description: "`tech_capacity_expansion_limit` — its total, at most its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '<=' - expression: tech_capacity_expansion <= GlobalConstraint_constant +Transformer_s_nom_modularity: + description: "`Transformer-s_nom_modularity` — the chosen build is a whole number of modules" + dims: [transformer] + where: Transformer_s_nom_extendable AND Transformer_s_nom_mod > 0 AND Transformer_active_asset + expression: Transformer_s_nom_ext == Transformer_s_nom_mod * Transformer_n_mod ``` ```math -\mathit{tech\_capacity\_expansion}_{i} \le \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{<=}\text{'} +\Sigma_{m} = \sigma^{\mathrm{mod}}_{m} \cdot N^{\sigma}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} ``` -### `tech_capacity_expansion_limit` +### `Transformer-s_nom_set` -`GlobalConstraint_tech_capacity_expansion_limit_lb` +`Transformer_s_nom_set` ```yaml -GlobalConstraint_tech_capacity_expansion_limit_lb: - description: "`tech_capacity_expansion_limit` — its total, at least its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '>=' - expression: tech_capacity_expansion >= GlobalConstraint_constant +Transformer_s_nom_set: + description: "`Transformer-s_nom_set` — the chosen build pinned, wherever a value is given" + dims: [transformer] + where: Transformer_s_nom_extendable AND Transformer_active_asset AND Transformer_s_nom_set + expression: Transformer_s_nom_ext == Transformer_s_nom_set ``` ```math -\mathit{tech\_capacity\_expansion}_{i} \ge \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{>=}\text{'} +\Sigma_{m} = \sigma^{\mathrm{nom,set}}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \sigma^{\mathrm{nom,set}}_{m} \text{ is defined} ``` -### `tech_capacity_expansion_limit` +### `Transformer-s_set` -`GlobalConstraint_tech_capacity_expansion_limit_eq` +`Transformer_s_set` ```yaml -GlobalConstraint_tech_capacity_expansion_limit_eq: - description: "`tech_capacity_expansion_limit` — its total, at its constant" - dims: [scenario, global_constraint] - where: GlobalConstraint_type == 'tech_capacity_expansion_limit' AND GlobalConstraint_sense == '==' - expression: tech_capacity_expansion == GlobalConstraint_constant +Transformer_s_set: + description: "`Transformer-s_set` — flow pinned to the given schedule, wherever one is given" + dims: [scenario, snapshot, transformer] + where: Transformer_s_set AND Transformer_active + expression: Transformer_s == Transformer_s_set ``` ```math -\mathit{tech\_capacity\_expansion}_{i} = \mathrm{K}_{i,\xi} \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi \,:\, \mathrm{type}_{i} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{i,\xi} = \text{'}\mathrm{==}\text{'} +\sigma_{\xi,t,m} = \sigma^{\mathrm{set}}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \sigma^{\mathrm{set}}_{\xi,t,m} \text{ is defined} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `Bus-nodal_balance` +### `Transformer-v_ang-lower` -`Bus_nodal_balance` +`Transformer_v_ang_lower` ```yaml -Bus_nodal_balance: +Transformer_v_ang_lower: description: >- - `Bus-nodal_balance` — what is generated at a bus, storage dispatch and - stores included, less what the links take away, plus what arrives over - them after losses and any delay at every port they deliver to, each - process port drawing or delivering at its own rate and each passive branch - carrying its flow, meets the load there, less half of every incident - line's and transformer's loss — PyPSA dissipates a branch's loss half at - either end. Each generator, storage unit, store and load term enters - with its component's `sign` (`constraints.py:1404-1405`, `:1514`), and - an inactive load not at all. A bus nothing is attached to has no row; PyPSA refuses one that - carries load, and this file does not yet. - dims: [scenario, snapshot, bus] - expression: Bus_injection == 0 + `Transformer-v_ang-lower` — a transformer with a fixed shift carries at + least the flow at which the voltage angle difference across it, + `x_pu_eff` times the flow plus the shift, is the negative of its limit + dims: [scenario, snapshot, transformer] + where: Transformer_v_ang_max AND NOT Transformer_phase_shift_varying AND Transformer_active + expression: Transformer_s >= -(Transformer_v_ang_max + Transformer_phase_shift_fixed) * (3.141592653589793 / 180) / Transformer_x_pu_eff ``` ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} - \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) - \left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} + \sum_{d \in \mathcal{D} \,:\, \mathrm{Load\_bus}(d) = n} \check{\mathrm{load}}_{d,\xi,t} + \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} + \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) + \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} - \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \sigma_{\xi,t,m} \right) + \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \sigma_{\xi,t,m} - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) = 0 \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\sigma_{\xi,t,m} \ge \frac{-\left( \overline{\delta}^{\sigma}_{\xi,m} + \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `Carrier-growth_limit` +### `Transformer-v_ang-upper` -`Carrier_growth_limit` +`Transformer_v_ang_upper` ```yaml -Carrier_growth_limit: +Transformer_v_ang_upper: description: >- - `Carrier-growth_limit` — what a carrier adds across its extendable components in a period, - counting each build in the first period it stands in, is at most its allowance plus a share of - what it added the period before; the first period has no predecessor, so `edge=0` leaves it the - bare allowance - dims: [carrier, period] - where: Carrier_max_growth - expression: >- - Carrier_additions - - shift(Carrier_additions, along=period, offset=1, edge=0) * Carrier_relative_growth - <= Carrier_max_growth + `Transformer-v_ang-upper` — a transformer with a fixed shift carries at + most the flow at which the voltage angle difference across it, the + shift included, reaches its limit + dims: [scenario, snapshot, transformer] + where: Transformer_v_ang_max AND NOT Transformer_phase_shift_varying AND Transformer_active + expression: Transformer_s <= (Transformer_v_ang_max - Transformer_phase_shift_fixed) * (3.141592653589793 / 180) / Transformer_x_pu_eff ``` ```math -\mathit{Carrier\_additions}_{i,y} - \mathit{Carrier\_additions}_{i,y \boxminus_{0} 1} \cdot \mathrm{r}^{+}_{i} \le \overline{\Delta}_{i} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} \,:\, \overline{\Delta}_{i} \text{ is defined} +\sigma_{\xi,t,m} \le \frac{\left( \overline{\delta}^{\sigma}_{\xi,m} - \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `CVaR-excess-{s}` +### `Transformer-v_ang-var-lower` -`CVaR_excess` +`Transformer_v_ang_var_lower` ```yaml -CVaR_excess: - description: "`CVaR-excess-{s}` — a scenario's operating cost beyond the tail's start is its excess; PyPSA names one row per scenario" - dims: [scenario] - where: CVaR_omega - expression: CVaR_a - scenario_opex + CVaR_theta >= 0 +Transformer_v_ang_var_lower: + description: >- + `Transformer-v_ang-var-lower` — for a transformer whose shift is a + decision, the flow plus the shift over `x_pu_eff` is at least the + negative of the limit over `x_pu_eff` + dims: [scenario, snapshot, transformer] + where: Transformer_v_ang_max AND Transformer_phase_shift_varying AND Transformer_active + expression: Transformer_s + Transformer_phase_shift * (3.141592653589793 / 180) / Transformer_x_pu_eff >= -Transformer_v_ang_max * (3.141592653589793 / 180) / Transformer_x_pu_eff ``` ```math -a_{\xi} - \mathit{scenario\_opex}_{\xi} + \theta \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} +\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \ge \frac{-\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `CVaR-def` +### `Transformer-v_ang-var-upper` -`CVaR_def` +`Transformer_v_ang_var_upper` ```yaml -CVaR_def: - description: "`CVaR-def` — the tail's average is at least where it starts plus the expected excess over the tail's probability" - dims: [] - where: CVaR_omega - expression: CVaR_theta + 1 / (1 - CVaR_alpha) * sum(scenario_weight * CVaR_a, over=scenario) <= CVaR +Transformer_v_ang_var_upper: + description: >- + `Transformer-v_ang-var-upper` — for a transformer whose shift is a + decision, the flow plus the shift over `x_pu_eff` is at most the limit + over `x_pu_eff` + dims: [scenario, snapshot, transformer] + where: Transformer_v_ang_max AND Transformer_phase_shift_varying AND Transformer_active + expression: Transformer_s + Transformer_phase_shift * (3.141592653589793 / 180) / Transformer_x_pu_eff <= Transformer_v_ang_max * (3.141592653589793 / 180) / Transformer_x_pu_eff ``` ```math -\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} +\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \le \frac{\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -### `Generator_maintenance_events_positive` +### `Generator_came_in_running_unless_committable` ```yaml -Generator_maintenance_events_positive: - holds: "Generator_maintenance_events > 0" - where: "Generator_maintainable" +Generator_came_in_running_unless_committable: + holds: "Generator_status_initial == 1" + where: "NOT Generator_committable AND (Generator_ramp_limit_up OR Generator_ramp_limit_down OR Generator_ramp_limit_start_up OR Generator_ramp_limit_shut_down)" description: >- - a maintainable generator with no event schedules no maintenance — - PyPSA refuses it (`consistency.py:1493`) + PyPSA reads `up_time_before` of a unit that is not committable in its + ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp + alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA + builds a row at the first snapshot with nothing carried in, and caps + the unit there at zero, or at its start-up ramp where another unit of + the component is committable with a fixed build + (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents + the attribute as read only for a committable unit and does not check + it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The + spec does not state that row, so it refuses the data ``` ```math -\mathrm{n}^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\mathrm{u}^{0}_{g,\xi} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}_{g} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) ``` -### `Generator_maintenance_duration_positive` +### `Generator_maintenance_build_cap_is_finite` ```yaml -Generator_maintenance_duration_positive: - holds: "Generator_maintenance_duration > 0" - where: "Generator_maintainable" +Generator_maintenance_build_cap_is_finite: + holds: "Generator_p_nom_max < inf" + where: "Generator_maintainable AND Generator_p_nom_extendable" description: >- - an event that covers no hours is no maintenance window — PyPSA - refuses it (`consistency.py:1483`) + the `maintcap` rows hold the chosen build in maintenance against + `p_nom_max`, so an infinite cap is an infinite coefficient — PyPSA + refuses it (`consistency.py:1528`) ``` ```math -\tau^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{ext}_{g} ``` ### `Generator_maintenance_duration_fits_the_horizon` @@ -12467,6 +12476,21 @@ Generator_maintenance_duration_fits_the_horizon: \tau^{\mathrm{mnt}}_{g,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` +### `Generator_maintenance_duration_positive` + +```yaml +Generator_maintenance_duration_positive: + holds: "Generator_maintenance_duration > 0" + where: "Generator_maintainable" + description: >- + an event that covers no hours is no maintenance window — PyPSA + refuses it (`consistency.py:1483`) +``` + +```math +\tau^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +``` + ### `Generator_maintenance_events_fit_the_horizon` ```yaml @@ -12483,20 +12507,19 @@ Generator_maintenance_events_fit_the_horizon: \tau^{\mathrm{mnt}}_{g,\xi} \cdot \mathrm{n}^{\mathrm{mnt}}_{g,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` -### `Generator_maintenance_build_cap_is_finite` +### `Generator_maintenance_events_positive` ```yaml -Generator_maintenance_build_cap_is_finite: - holds: "Generator_p_nom_max < inf" - where: "Generator_maintainable AND Generator_p_nom_extendable" +Generator_maintenance_events_positive: + holds: "Generator_maintenance_events > 0" + where: "Generator_maintainable" description: >- - the `maintcap` rows hold the chosen build in maintenance against - `p_nom_max`, so an infinite cap is an infinite coefficient — PyPSA - refuses it (`consistency.py:1528`) + a maintainable generator with no event schedules no maintenance — + PyPSA refuses it (`consistency.py:1493`) ``` ```math -\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{ext}_{g} +\mathrm{n}^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` ### `Generator_maintenance_module_count_is_finite` @@ -12513,37 +12536,81 @@ Generator_maintenance_module_count_is_finite: ``` ```math -\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{com}_{g} \wedge \neg \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{com}_{g} \wedge \neg \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +``` + +### `Generator_marginal_cost_quadratic_without_risk_preference` + +```yaml +Generator_marginal_cost_quadratic_without_risk_preference: + holds: "Generator_marginal_cost_quadratic == 0" + where: "CVaR_omega" + description: >- + a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA + refuses quadratic costs under any risk preference + (`optimize.py:470-477`), `omega = 0` included. Data prep writes a + `CVaR_omega` row only where a risk preference is set +``` + +```math +\mathrm{c}^{(2)}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +``` + +### `GlobalConstraint_tech_capacity_expansion_limit_without_scenarios` + +```yaml +GlobalConstraint_tech_capacity_expansion_limit_without_scenarios: + holds: "GlobalConstraint_type != 'tech_capacity_expansion_limit'" + where: "count(scenario_weight, over=scenario) > 1" + description: >- + PyPSA does not build a `tech_capacity_expansion_limit` row on a + network with scenarios and refuses it + (`global_constraints.py:67-69`). The spec cannot tell a network with + one scenario from one with none, so it refuses only where there is + more than one scenario +``` + +```math +\mathrm{type}_{l} \neq \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \qquad \forall\, l \in \mathcal{L} \,:\, \lvert \{ \xi \in \Xi \,:\, \pi_{\xi} \text{ is defined} \} \rvert > 1 ``` -### `Link_maintenance_events_positive` +### `Link_came_in_running_unless_committable` ```yaml -Link_maintenance_events_positive: - holds: "Link_maintenance_events > 0" - where: "Link_maintainable" +Link_came_in_running_unless_committable: + holds: "Link_status_initial == 1" + where: "NOT Link_committable AND (Link_ramp_limit_up OR Link_ramp_limit_down OR Link_ramp_limit_start_up OR Link_ramp_limit_shut_down)" description: >- - a maintainable link with no event schedules no maintenance — - PyPSA refuses it (`consistency.py:1493`) + PyPSA reads `up_time_before` of a link that is not committable in its + ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp + alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA + builds a row at the first snapshot with nothing carried in, and caps + the link there at zero, or at its start-up ramp where another link of + the component is committable with a fixed build + (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents + the attribute as read only for a committable link and does not check + it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The + spec does not state that row, so it refuses the data ``` ```math -\mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\mathrm{u}^{f,0}_{l,\xi} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}^{f}_{l} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) ``` -### `Link_maintenance_duration_positive` +### `Link_maintenance_build_cap_is_finite` ```yaml -Link_maintenance_duration_positive: - holds: "Link_maintenance_duration > 0" - where: "Link_maintainable" +Link_maintenance_build_cap_is_finite: + holds: "Link_p_nom_max < inf" + where: "Link_maintainable AND Link_p_nom_extendable" description: >- - an event that covers no hours is no maintenance window — PyPSA - refuses it (`consistency.py:1483`) + the `maintcap` rows hold the chosen build in maintenance against + `p_nom_max`, so an infinite cap is an infinite coefficient — PyPSA + refuses it (`consistency.py:1528`) ``` ```math -\tau^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} < \infty \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} ``` ### `Link_maintenance_duration_fits_the_horizon` @@ -12562,6 +12629,21 @@ Link_maintenance_duration_fits_the_horizon: \tau^{f,\mathrm{mnt}}_{l,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` +### `Link_maintenance_duration_positive` + +```yaml +Link_maintenance_duration_positive: + holds: "Link_maintenance_duration > 0" + where: "Link_maintainable" + description: >- + an event that covers no hours is no maintenance window — PyPSA + refuses it (`consistency.py:1483`) +``` + +```math +\tau^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +``` + ### `Link_maintenance_events_fit_the_horizon` ```yaml @@ -12578,20 +12660,19 @@ Link_maintenance_events_fit_the_horizon: \tau^{f,\mathrm{mnt}}_{l,\xi} \cdot \mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` -### `Link_maintenance_build_cap_is_finite` +### `Link_maintenance_events_positive` ```yaml -Link_maintenance_build_cap_is_finite: - holds: "Link_p_nom_max < inf" - where: "Link_maintainable AND Link_p_nom_extendable" +Link_maintenance_events_positive: + holds: "Link_maintenance_events > 0" + where: "Link_maintainable" description: >- - the `maintcap` rows hold the chosen build in maintenance against - `p_nom_max`, so an infinite cap is an infinite coefficient — PyPSA - refuses it (`consistency.py:1528`) + a maintainable link with no event schedules no maintenance — + PyPSA refuses it (`consistency.py:1493`) ``` ```math -\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} < \infty \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} +\mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` ### `Link_maintenance_module_count_is_finite` @@ -12611,66 +12692,63 @@ Link_maintenance_module_count_is_finite: \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} < \infty \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{com}^{f}_{l} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -### `Process_maintenance_events_positive` - -```yaml -Process_maintenance_events_positive: - holds: "Process_maintenance_events > 0" - where: "Process_maintainable" - description: >- - a maintainable process with no event schedules no maintenance — - PyPSA refuses it (`consistency.py:1493`) -``` - -```math -\mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} -``` - -### `Process_maintenance_duration_positive` +### `Link_marginal_cost_quadratic_without_risk_preference` ```yaml -Process_maintenance_duration_positive: - holds: "Process_maintenance_duration > 0" - where: "Process_maintainable" +Link_marginal_cost_quadratic_without_risk_preference: + holds: "Link_marginal_cost_quadratic == 0" + where: "CVaR_omega" description: >- - an event that covers no hours is no maintenance window — PyPSA - refuses it (`consistency.py:1483`) + a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA + refuses quadratic costs under any risk preference + (`optimize.py:470-477`), `omega = 0` included. Data prep writes a + `CVaR_omega` row only where a risk preference is set ``` ```math -\tau^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\mathrm{c}^{f,(2)}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} ``` -### `Process_maintenance_duration_fits_the_horizon` +### `Link_output_delay_under_uniform_weighting` ```yaml -Process_maintenance_duration_fits_the_horizon: - holds: "Process_maintenance_duration <= sum(snapshot_weightings_generators, over=snapshot)" - where: "Process_maintainable" +Link_output_delay_under_uniform_weighting: + holds: "snapshot_weightings_generators == shift(snapshot_weightings_generators, along=snapshot, offset=1, edge='wrap')" + where: "Link_output_delay > 0" description: >- - one event longer than the horizon, in generator weightings, blocks - every start and makes the event count infeasible — PyPSA refuses it - (`consistency.py:1504`) + a delayed port lags by the same whole number of snapshots in every + period. PyPSA lags by elapsed time in `generators` weighting and + rounds the source down to a snapshot start (`multiports.py:100-133`), + so the two agree only where that weighting is one value over the + horizon. PyPSA does not refuse an uneven weighting, so the file does + (#299) ``` ```math -\tau^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, o \in \mathcal{O},\ t \in \mathcal{T} \,:\, \mathrm{d}^{f}_{o} > 0 ``` -### `Process_maintenance_events_fit_the_horizon` +### `Process_came_in_running_unless_committable` ```yaml -Process_maintenance_events_fit_the_horizon: - holds: "Process_maintenance_duration * Process_maintenance_events <= sum(snapshot_weightings_generators, over=snapshot)" - where: "Process_maintainable" +Process_came_in_running_unless_committable: + holds: "Process_status_initial == 1" + where: "NOT Process_committable AND (Process_ramp_limit_up OR Process_ramp_limit_down OR Process_ramp_limit_start_up OR Process_ramp_limit_shut_down)" description: >- - the events together longer than the horizon, in generator - weightings, cannot all be scheduled — PyPSA refuses it - (`consistency.py:1516`) + PyPSA reads `up_time_before` of a process that is not committable in its + ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp + alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA + builds a row at the first snapshot with nothing carried in, and caps + the process there at zero, or at its start-up ramp where another process of + the component is committable with a fixed build + (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents + the attribute as read only for a committable process and does not check + it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The + spec does not state that row, so it refuses the data ``` ```math -\tau^{z,\mathrm{mnt}}_{j,\xi} \cdot \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\mathrm{u}^{z,0}_{j,\xi} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}^{z}_{j} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) ``` ### `Process_maintenance_build_cap_is_finite` @@ -12689,181 +12767,162 @@ Process_maintenance_build_cap_is_finite: \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} < \infty \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} ``` -### `Process_maintenance_module_count_is_finite` - -```yaml -Process_maintenance_module_count_is_finite: - holds: "Process_p_nom_max < inf" - where: "Process_maintainable AND Process_committable AND NOT Process_p_nom_extendable AND Process_p_nom_mod > 0" - description: >- - the `maint-modstatus` rows bound the modules on in maintenance by - `p_nom_max / p_nom_mod`, so an infinite cap is an infinite - coefficient. PyPSA does not check it, and HiGHS refuses the model - (`constraints.py:504-507`) -``` - -```math -\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} < \infty \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{com}^{z}_{j} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 -``` - -### `Link_output_delay_under_uniform_weighting` +### `Process_maintenance_duration_fits_the_horizon` ```yaml -Link_output_delay_under_uniform_weighting: - holds: "snapshot_weightings_generators == shift(snapshot_weightings_generators, along=snapshot, offset=1, edge='wrap')" - where: "Link_output_delay > 0" +Process_maintenance_duration_fits_the_horizon: + holds: "Process_maintenance_duration <= sum(snapshot_weightings_generators, over=snapshot)" + where: "Process_maintainable" description: >- - a delayed port lags by the same whole number of snapshots in every - period. PyPSA lags by elapsed time in `generators` weighting and - rounds the source down to a snapshot start (`multiports.py:100-133`), - so the two agree only where that weighting is one value over the - horizon. PyPSA does not refuse an uneven weighting, so the file does - (#299) + one event longer than the horizon, in generator weightings, blocks + every start and makes the event count infeasible — PyPSA refuses it + (`consistency.py:1504`) ``` ```math -\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, o \in \mathcal{O},\ t \in \mathcal{T} \,:\, \mathrm{d}^{f}_{o} > 0 +\tau^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -### `Process_output_delay_under_uniform_weighting` +### `Process_maintenance_duration_positive` ```yaml -Process_output_delay_under_uniform_weighting: - holds: "snapshot_weightings_generators == shift(snapshot_weightings_generators, along=snapshot, offset=1, edge='wrap')" - where: "Process_output_delay > 0" +Process_maintenance_duration_positive: + holds: "Process_maintenance_duration > 0" + where: "Process_maintainable" description: >- - the same for a delayed process port (#299) + an event that covers no hours is no maintenance window — PyPSA + refuses it (`consistency.py:1483`) ``` ```math -\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, r \in \mathcal{R},\ t \in \mathcal{T} \,:\, \mathrm{d}^{z}_{r} > 0 +\tau^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -### `StorageUnit_stands_in_one_run` +### `Process_maintenance_events_fit_the_horizon` ```yaml -StorageUnit_stands_in_one_run: - holds: "count(StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1), over=snapshot) <= 1" +Process_maintenance_events_fit_the_horizon: + holds: "Process_maintenance_duration * Process_maintenance_events <= sum(snapshot_weightings_generators, over=snapshot)" + where: "Process_maintainable" description: >- - the snapshots a storage unit stands in are one unbroken run, as a build - year and a lifetime make them. The opening row holds at the first - of them only, and a cyclic storage unit reaches back - `StorageUnit_inactive_snapshots` further to the last of them + the events together longer than the horizon, in generator + weightings, cannot all be scheduled — PyPSA refuses it + (`consistency.py:1516`) ``` ```math -\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \} \rvert \le 1 \qquad \forall\, s \in \mathcal{S} +\tau^{z,\mathrm{mnt}}_{j,\xi} \cdot \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -### `StorageUnit_opens_late_only_where_it_opens` +### `Process_maintenance_events_positive` ```yaml -StorageUnit_opens_late_only_where_it_opens: - holds: "StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1) AND position(snapshot) > 0" - where: "StorageUnit_opens_late" +Process_maintenance_events_positive: + holds: "Process_maintenance_events > 0" + where: "Process_maintainable" description: >- - `StorageUnit_opens_late` marks the first snapshot the storage unit stands in, past - the first of the horizon, and no other + a maintainable process with no event schedules no maintenance — + PyPSA refuses it (`consistency.py:1493`) ``` ```math -\mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \wedge \mathrm{pos}(t) > 0 \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{open}_{t,s} +\mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -### `StorageUnit_opens_late_where_it_opens` +### `Process_maintenance_module_count_is_finite` ```yaml -StorageUnit_opens_late_where_it_opens: - holds: "StorageUnit_opens_late" - where: "StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1) AND position(snapshot) > 0" +Process_maintenance_module_count_is_finite: + holds: "Process_p_nom_max < inf" + where: "Process_maintainable AND Process_committable AND NOT Process_p_nom_extendable AND Process_p_nom_mod > 0" description: >- - a storage unit that opens past the first snapshot of the horizon opens on - its initial level, or its last level where it is cyclic, only where - `StorageUnit_opens_late` marks the snapshot + the `maint-modstatus` rows bound the modules on in maintenance by + `p_nom_max / p_nom_mod`, so an infinite cap is an infinite + coefficient. PyPSA does not check it, and HiGHS refuses the model + (`constraints.py:504-507`) ``` ```math -\mathrm{open}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \wedge \mathrm{pos}(t) > 0 +\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} < \infty \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{com}^{z}_{j} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -### `Store_stands_in_one_run` +### `Process_marginal_cost_quadratic_without_risk_preference` ```yaml -Store_stands_in_one_run: - holds: "count(Store_active AND NOT shift(Store_active, along=snapshot, offset=1), over=snapshot) <= 1" +Process_marginal_cost_quadratic_without_risk_preference: + holds: "Process_marginal_cost_quadratic == 0" + where: "CVaR_omega" description: >- - the snapshots a store stands in are one unbroken run, as a build - year and a lifetime make them. The opening row holds at the first - of them only, and a cyclic store reaches back - `Store_inactive_snapshots` further to the last of them + a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA + refuses quadratic costs under any risk preference + (`optimize.py:470-477`), `omega = 0` included. Data prep writes a + `CVaR_omega` row only where a risk preference is set ``` ```math -\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \} \rvert \le 1 \qquad \forall\, v \in \mathcal{V} +\mathrm{c}^{z,(2)}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} ``` -### `Store_opens_late_only_where_it_opens` +### `Process_output_delay_under_uniform_weighting` ```yaml -Store_opens_late_only_where_it_opens: - holds: "Store_active AND NOT shift(Store_active, along=snapshot, offset=1) AND position(snapshot) > 0" - where: "Store_opens_late" +Process_output_delay_under_uniform_weighting: + holds: "snapshot_weightings_generators == shift(snapshot_weightings_generators, along=snapshot, offset=1, edge='wrap')" + where: "Process_output_delay > 0" description: >- - `Store_opens_late` marks the first snapshot the store stands in, past - the first of the horizon, and no other + the same for a delayed process port (#299) ``` ```math -\mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \wedge \mathrm{pos}(t) > 0 \qquad \forall\, t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{open}^{e}_{t,v} +\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, r \in \mathcal{R},\ t \in \mathcal{T} \,:\, \mathrm{d}^{z}_{r} > 0 ``` -### `Store_opens_late_where_it_opens` +### `StorageUnit_marginal_cost_quadratic_without_risk_preference` ```yaml -Store_opens_late_where_it_opens: - holds: "Store_opens_late" - where: "Store_active AND NOT shift(Store_active, along=snapshot, offset=1) AND position(snapshot) > 0" +StorageUnit_marginal_cost_quadratic_without_risk_preference: + holds: "StorageUnit_marginal_cost_quadratic == 0" + where: "CVaR_omega" description: >- - a store that opens past the first snapshot of the horizon opens on - its initial level, or its last level where it is cyclic, only where - `Store_opens_late` marks the snapshot + a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA + refuses quadratic costs under any risk preference + (`optimize.py:470-477`), `omega = 0` included. Data prep writes a + `CVaR_omega` row only where a risk preference is set ``` ```math -\mathrm{open}^{e}_{t,v} \qquad \forall\, t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \wedge \mathrm{pos}(t) > 0 +\mathrm{c}^{h,(2)}_{\xi,t,s} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \omega \text{ is defined} ``` -### `StorageUnit_primary_energy_per_period_closes_over_the_horizon` +### `StorageUnit_opens_late_only_where_it_opens` ```yaml -StorageUnit_primary_energy_per_period_closes_over_the_horizon: - holds: "count(NOT GlobalConstraint_counts_snapshot, over=snapshot) == 0" - where: "StorageUnit_primary_energy_weight AND StorageUnit_state_of_charge_initial_per_period" +StorageUnit_opens_late_only_where_it_opens: + holds: "StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1) AND position(snapshot) > 0" + where: "StorageUnit_opens_late" description: >- - PyPSA reads the closing charge of a unit that reopens per period at - the last snapshot of every period, and fails on a `primary_energy` row - that names an `investment_period` (`global_constraints.py:469`) + `StorageUnit_opens_late` marks the first snapshot the storage unit stands in, past + the first of the horizon, and no other ``` ```math -\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{i,\xi,t} \} \rvert = 0 \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{i,\xi,s} \text{ is defined} \wedge \mathrm{reset}_{\xi,s} +\mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \wedge \mathrm{pos}(t) > 0 \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{open}_{t,s} ``` -### `StorageUnit_primary_energy_carried_over_has_unit_years` +### `StorageUnit_opens_late_where_it_opens` ```yaml -StorageUnit_primary_energy_carried_over_has_unit_years: - holds: "period_weight_years == 1" - where: "StorageUnit_primary_energy_weight AND NOT StorageUnit_state_of_charge_initial_per_period" +StorageUnit_opens_late_where_it_opens: + holds: "StorageUnit_opens_late" + where: "StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1) AND position(snapshot) > 0" description: >- - a unit that carries its charge from one period to the next closes - once, at the last counted snapshot, and no period's years weighs that - level — PyPSA refuses it where any period's years is not one - (`global_constraints.py:443`) + a storage unit that opens past the first snapshot of the horizon opens on + its initial level, or its last level where it is cyclic, only where + `StorageUnit_opens_late` marks the snapshot ``` ```math -\mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{i,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} +\mathrm{open}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \wedge \mathrm{pos}(t) > 0 ``` ### `StorageUnit_operational_limit_carried_over_has_unit_years` @@ -12878,96 +12937,63 @@ StorageUnit_operational_limit_carried_over_has_unit_years: ``` ```math -\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{b}^{h}_{i,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{i,\xi,t} -``` - -### `Store_primary_energy_per_period_closes_over_the_horizon` - -```yaml -Store_primary_energy_per_period_closes_over_the_horizon: - holds: "count(NOT GlobalConstraint_counts_snapshot, over=snapshot) == 0" - where: "Store_primary_energy_weight AND Store_e_initial_per_period" - description: >- - PyPSA reads the closing energy of a store that reopens per period at - the last snapshot of every period, and fails on a `primary_energy` row - that names an `investment_period` (`global_constraints.py:521`) -``` - -```math -\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{i,\xi,t} \} \rvert = 0 \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{i,\xi,v} \text{ is defined} \wedge \mathrm{reset}^{e}_{\xi,v} +\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{b}^{h}_{l,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{l,\xi,t} ``` -### `Store_primary_energy_carried_over_has_unit_years` +### `StorageUnit_primary_energy_carried_over_has_unit_years` ```yaml -Store_primary_energy_carried_over_has_unit_years: +StorageUnit_primary_energy_carried_over_has_unit_years: holds: "period_weight_years == 1" - where: "Store_primary_energy_weight AND NOT Store_e_initial_per_period" + where: "StorageUnit_primary_energy_weight AND NOT StorageUnit_state_of_charge_initial_per_period" description: >- - a store that carries its energy from one period to the next closes + a unit that carries its charge from one period to the next closes once, at the last counted snapshot, and no period's years weighs that level — PyPSA refuses it where any period's years is not one - (`global_constraints.py:495`) -``` - -```math -\mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{i,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} -``` - -### `Store_operational_limit_carried_over_has_unit_years` - -```yaml -Store_operational_limit_carried_over_has_unit_years: - holds: "at(period_weight_years == 1, by=snapshot_period[period])" - where: "Store_operational_limit_weight AND NOT Store_e_initial_per_period AND GlobalConstraint_counts_snapshot" - description: >- - the same for an `operational_limit` row, over the periods it counts — - PyPSA refuses it (`global_constraints.py:696`) + (`global_constraints.py:443`) ``` ```math -\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, i \in \mathcal{I},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{b}^{e}_{i,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{i,\xi,t} +\mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, l \in \mathcal{L},\ y \in \mathcal{Y},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{l,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} ``` -### `Generator_marginal_cost_quadratic_without_risk_preference` +### `StorageUnit_primary_energy_per_period_closes_over_the_horizon` ```yaml -Generator_marginal_cost_quadratic_without_risk_preference: - holds: "Generator_marginal_cost_quadratic == 0" - where: "CVaR_omega" +StorageUnit_primary_energy_per_period_closes_over_the_horizon: + holds: "count(NOT GlobalConstraint_counts_snapshot, over=snapshot) == 0" + where: "StorageUnit_primary_energy_weight AND StorageUnit_state_of_charge_initial_per_period" description: >- - a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA - refuses quadratic costs under any risk preference - (`optimize.py:470-477`), `omega = 0` included. Data prep writes a - `CVaR_omega` row only where a risk preference is set + PyPSA reads the closing charge of a unit that reopens per period at + the last snapshot of every period, and fails on a `primary_energy` row + that names an `investment_period` (`global_constraints.py:469`) ``` ```math -\mathrm{c}^{(2)}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{l,\xi,t} \} \rvert = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{l,\xi,s} \text{ is defined} \wedge \mathrm{reset}_{\xi,s} ``` -### `Link_marginal_cost_quadratic_without_risk_preference` +### `StorageUnit_stands_in_one_run` ```yaml -Link_marginal_cost_quadratic_without_risk_preference: - holds: "Link_marginal_cost_quadratic == 0" - where: "CVaR_omega" +StorageUnit_stands_in_one_run: + holds: "count(StorageUnit_active AND NOT shift(StorageUnit_active, along=snapshot, offset=1), over=snapshot) <= 1" description: >- - a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA - refuses quadratic costs under any risk preference - (`optimize.py:470-477`), `omega = 0` included. Data prep writes a - `CVaR_omega` row only where a risk preference is set + the snapshots a storage unit stands in are one unbroken run, as a build + year and a lifetime make them. The opening row holds at the first + of them only, and a cyclic storage unit reaches back + `StorageUnit_inactive_snapshots` further to the last of them ``` ```math -\mathrm{c}^{f,(2)}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \} \rvert \le 1 \qquad \forall\, s \in \mathcal{S} ``` -### `Process_marginal_cost_quadratic_without_risk_preference` +### `Store_marginal_cost_quadratic_without_risk_preference` ```yaml -Process_marginal_cost_quadratic_without_risk_preference: - holds: "Process_marginal_cost_quadratic == 0" +Store_marginal_cost_quadratic_without_risk_preference: + holds: "Store_marginal_cost_quadratic == 0" where: "CVaR_omega" description: >- a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA @@ -12977,128 +13003,102 @@ Process_marginal_cost_quadratic_without_risk_preference: ``` ```math -\mathrm{c}^{z,(2)}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +\mathrm{c}^{q,(2)}_{\xi,t,v} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \omega \text{ is defined} ``` -### `StorageUnit_marginal_cost_quadratic_without_risk_preference` +### `Store_opens_late_only_where_it_opens` ```yaml -StorageUnit_marginal_cost_quadratic_without_risk_preference: - holds: "StorageUnit_marginal_cost_quadratic == 0" - where: "CVaR_omega" +Store_opens_late_only_where_it_opens: + holds: "Store_active AND NOT shift(Store_active, along=snapshot, offset=1) AND position(snapshot) > 0" + where: "Store_opens_late" description: >- - a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA - refuses quadratic costs under any risk preference - (`optimize.py:470-477`), `omega = 0` included. Data prep writes a - `CVaR_omega` row only where a risk preference is set + `Store_opens_late` marks the first snapshot the store stands in, past + the first of the horizon, and no other ``` ```math -\mathrm{c}^{h,(2)}_{\xi,t,s} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \omega \text{ is defined} +\mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \wedge \mathrm{pos}(t) > 0 \qquad \forall\, t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{open}^{e}_{t,v} ``` -### `Store_marginal_cost_quadratic_without_risk_preference` +### `Store_opens_late_where_it_opens` ```yaml -Store_marginal_cost_quadratic_without_risk_preference: - holds: "Store_marginal_cost_quadratic == 0" - where: "CVaR_omega" +Store_opens_late_where_it_opens: + holds: "Store_opens_late" + where: "Store_active AND NOT shift(Store_active, along=snapshot, offset=1) AND position(snapshot) > 0" description: >- - a quadratic cost puts a square into every `CVaR-excess` row, and PyPSA - refuses quadratic costs under any risk preference - (`optimize.py:470-477`), `omega = 0` included. Data prep writes a - `CVaR_omega` row only where a risk preference is set + a store that opens past the first snapshot of the horizon opens on + its initial level, or its last level where it is cyclic, only where + `Store_opens_late` marks the snapshot ``` ```math -\mathrm{c}^{q,(2)}_{\xi,t,v} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \omega \text{ is defined} +\mathrm{open}^{e}_{t,v} \qquad \forall\, t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \wedge \mathrm{pos}(t) > 0 ``` -### `GlobalConstraint_tech_capacity_expansion_limit_without_scenarios` +### `Store_operational_limit_carried_over_has_unit_years` ```yaml -GlobalConstraint_tech_capacity_expansion_limit_without_scenarios: - holds: "GlobalConstraint_type != 'tech_capacity_expansion_limit'" - where: "count(scenario_weight, over=scenario) > 1" +Store_operational_limit_carried_over_has_unit_years: + holds: "at(period_weight_years == 1, by=snapshot_period[period])" + where: "Store_operational_limit_weight AND NOT Store_e_initial_per_period AND GlobalConstraint_counts_snapshot" description: >- - PyPSA does not build a `tech_capacity_expansion_limit` row on a - network with scenarios and refuses it - (`global_constraints.py:67-69`). The spec cannot tell a network with - one scenario from one with none, so it refuses only where there is - more than one scenario + the same for an `operational_limit` row, over the periods it counts — + PyPSA refuses it (`global_constraints.py:696`) ``` ```math -\mathrm{type}_{i} \neq \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \qquad \forall\, i \in \mathcal{I} \,:\, \lvert \{ \xi \in \Xi \,:\, \pi_{\xi} \text{ is defined} \} \rvert > 1 +\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{b}^{e}_{l,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{l,\xi,t} ``` -### `Generator_came_in_running_unless_committable` +### `Store_primary_energy_carried_over_has_unit_years` ```yaml -Generator_came_in_running_unless_committable: - holds: "Generator_status_initial == 1" - where: "NOT Generator_committable AND (Generator_ramp_limit_up OR Generator_ramp_limit_down OR Generator_ramp_limit_start_up OR Generator_ramp_limit_shut_down)" +Store_primary_energy_carried_over_has_unit_years: + holds: "period_weight_years == 1" + where: "Store_primary_energy_weight AND NOT Store_e_initial_per_period" description: >- - PyPSA reads `up_time_before` of a unit that is not committable in its - ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp - alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA - builds a row at the first snapshot with nothing carried in, and caps - the unit there at zero, or at its start-up ramp where another unit of - the component is committable with a fixed build - (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents - the attribute as read only for a committable unit and does not check - it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The - spec does not state that row, so it refuses the data + a store that carries its energy from one period to the next closes + once, at the last counted snapshot, and no period's years weighs that + level — PyPSA refuses it where any period's years is not one + (`global_constraints.py:495`) ``` ```math -\mathrm{u}^{0}_{g,\xi} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}_{g} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) +\mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, l \in \mathcal{L},\ y \in \mathcal{Y},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{l,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} ``` -### `Link_came_in_running_unless_committable` +### `Store_primary_energy_per_period_closes_over_the_horizon` ```yaml -Link_came_in_running_unless_committable: - holds: "Link_status_initial == 1" - where: "NOT Link_committable AND (Link_ramp_limit_up OR Link_ramp_limit_down OR Link_ramp_limit_start_up OR Link_ramp_limit_shut_down)" +Store_primary_energy_per_period_closes_over_the_horizon: + holds: "count(NOT GlobalConstraint_counts_snapshot, over=snapshot) == 0" + where: "Store_primary_energy_weight AND Store_e_initial_per_period" description: >- - PyPSA reads `up_time_before` of a link that is not committable in its - ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp - alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA - builds a row at the first snapshot with nothing carried in, and caps - the link there at zero, or at its start-up ramp where another link of - the component is committable with a fixed build - (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents - the attribute as read only for a committable link and does not check - it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The - spec does not state that row, so it refuses the data + PyPSA reads the closing energy of a store that reopens per period at + the last snapshot of every period, and fails on a `primary_energy` row + that names an `investment_period` (`global_constraints.py:521`) ``` ```math -\mathrm{u}^{f,0}_{l,\xi} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}^{f}_{l} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) +\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{l,\xi,t} \} \rvert = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{l,\xi,v} \text{ is defined} \wedge \mathrm{reset}^{e}_{\xi,v} ``` -### `Process_came_in_running_unless_committable` +### `Store_stands_in_one_run` ```yaml -Process_came_in_running_unless_committable: - holds: "Process_status_initial == 1" - where: "NOT Process_committable AND (Process_ramp_limit_up OR Process_ramp_limit_down OR Process_ramp_limit_start_up OR Process_ramp_limit_shut_down)" +Store_stands_in_one_run: + holds: "count(Store_active AND NOT shift(Store_active, along=snapshot, offset=1), over=snapshot) <= 1" description: >- - PyPSA reads `up_time_before` of a process that is not committable in its - ramp rows, which a ramp limit, a start-up ramp or a shut-down ramp - alone builds (`constraints.py:1018-1019`). Where it is zero, PyPSA - builds a row at the first snapshot with nothing carried in, and caps - the process there at zero, or at its start-up ramp where another process of - the component is committable with a fixed build - (`constraints.py:1063-1066`, `1082-1084`). PyPSA documents - the attribute as read only for a committable process and does not check - it. PyPSA has not decided which row is intended (PyPSA/PyPSA#1943). The - spec does not state that row, so it refuses the data + the snapshots a store stands in are one unbroken run, as a build + year and a lifetime make them. The opening row holds at the first + of them only, and a cyclic store reaches back + `Store_inactive_snapshots` further to the last of them ``` ```math -\mathrm{u}^{z,0}_{j,\xi} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{com}^{z}_{j} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) +\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \} \rvert \le 1 \qquad \forall\, v \in \mathcal{V} ``` diff --git a/docs/examples/pypsa/carrier.md b/docs/examples/pypsa/carrier.md index 1681516b..72ce427f 100644 --- a/docs/examples/pypsa/carrier.md +++ b/docs/examples/pypsa/carrier.md @@ -73,8 +73,8 @@ constraints: | Symbol | Meaning | |---|---| -| $`\mathcal{Y}`$ | index $`y`$ — `period` — investment periods — PyPSA's `investment_periods` | | $`\mathcal{I}`$ | index $`i`$ — `carrier` — energy carriers, what a growth limit is set per | +| $`\mathcal{Y}`$ | index $`y`$ — `period` — investment periods — PyPSA's `investment_periods` | #### Parameters diff --git a/docs/examples/pypsa/cost.md b/docs/examples/pypsa/cost.md index c3960fcf..74fcf8ae 100644 --- a/docs/examples/pypsa/cost.md +++ b/docs/examples/pypsa/cost.md @@ -68,8 +68,8 @@ constraints: | Symbol | Meaning | |---|---| -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\omega`$ | `CVaR_omega` (scalar), data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression another file defines | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `risk_weighted_opex` to | @@ -89,9 +89,9 @@ constraints: | Symbol | Meaning | |---|---| +| $`CVaR`$ | `CVaR` (scalar), `neutral` where the mask leaves it out — `CVaR` — the tail's average cost, what the objective prices at `omega` | | $`a`$ | `CVaR_a` over $`\Xi`$, `neutral` where the mask leaves it out — `CVaR-a` — how far a scenario's operating cost exceeds the tail's start; nothing where it does not | | $`\theta`$ | `CVaR_theta` (scalar), `neutral` where the mask leaves it out — `CVaR-theta` — where the tail starts, the value at risk | -| $`CVaR`$ | `CVaR` (scalar), `neutral` where the mask leaves it out — `CVaR` — the tail's average cost, what the objective prices at `omega` | #### Definitions @@ -101,22 +101,22 @@ constraints: #### Variable domains -**`CVaR_a`** +**`CVaR`** ```math -a_{\xi} \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} +CVaR \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} ``` -**`CVaR_theta`** +**`CVaR_a`** ```math -\theta \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} +a_{\xi} \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} ``` -**`CVaR`** +**`CVaR_theta`** ```math -CVaR \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} +\theta \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} ``` #### Definitions @@ -129,15 +129,15 @@ CVaR \in \mathbb{R} \qquad \text{where } \omega \text{ is defined} #### Subject to -**`CVaR_excess`** +**`CVaR_def`** ```math -a_{\xi} - \mathit{scenario\_opex}_{\xi} + \theta \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} +\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} ``` -**`CVaR_def`** +**`CVaR_excess`** ```math -\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} +a_{\xi} - \mathit{scenario\_opex}_{\xi} + \theta \ge 0 \qquad \forall\, \xi \in \Xi \,:\, \omega \text{ is defined} ``` diff --git a/docs/examples/pypsa/generator.md b/docs/examples/pypsa/generator.md index cc4f68c4..a7ac750b 100644 --- a/docs/examples/pypsa/generator.md +++ b/docs/examples/pypsa/generator.md @@ -316,63 +316,63 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{com}`$ | `Generator_committable` over $`\mathcal{G}`$, data another file declares | | $`\gamma`$ | `Generator_maintenance_pu` over $`\mathcal{G} \times \Xi`$, data another file declares | -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | -| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu`$ | `Generator_maintenance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`\mu^{\mathrm{nom}}`$ | `Generator_maintenance_capacity` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Generator_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Generator_additions` to | | $`\mathit{w}^{\mathrm{gc}}`$ | `GlobalConstraint_energy_weight` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, an expression another file defines | -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{L} \times \Xi`$, an expression this file adds `Generator_primary_energy` to | | $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{L} \times \Xi`$, an expression this file adds `Generator_operational_limit` to | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{L}`$, an expression this file adds `Generator_tech_capacity_expansion` to | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{L} \times \Xi`$, an expression this file adds `Generator_primary_energy` to | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Generator_opex` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{L}`$, an expression this file adds `Generator_tech_capacity_expansion` to | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Generator_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Generator_additions` to | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Generator_injection` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I},\ \mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N}`$ — generating units, each on one bus | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_bus}: \mathcal{G} \to \mathcal{N},\ \mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I}`$ — generating units, each on one bus | | $`\mathcal{L}`$ | index $`l`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Generator\_carrier}: \mathcal{G} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G} \times \Xi`$ — nominal power | -| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$ — whether the nominal power is a decision | -| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — least output, per unit of nominal power | -| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — most output, per unit of nominal power — an availability profile | -| $`\mathrm{c}`$ | `Generator_marginal_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one unit of output | -| $`\mathrm{c}^{(2)}`$ | `Generator_marginal_cost_quadratic` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — 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{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — 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{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{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$ — whether a generator stands in a snapshot's period — PyPSA's `active`, from build year and lifetime, data prep | | $`\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{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\mathcal{G} \times \Xi`$ — 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{W}`$ | `Generator_capital_weight` over $`\mathcal{G}`$ — the sum of period weights a generator stands in — PyPSA's `active * period_weighting`, summed, data prep | +| $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\mathcal{G} \times \Xi`$ — most energy over the horizon — a fuel or emission budget in energy terms; infinity where no cap is meant | +| $`\underline{\mathrm{E}}`$ | `Generator_e_sum_min` over $`\mathcal{G} \times \Xi`$ — least energy over the horizon; minus infinity where no floor is meant | | $`\mathrm{new}`$ | `Generator_first_active` over $`\mathcal{G} \times \mathcal{Y}`$ — 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 $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — least nominal power an extendable generator may be built at | +| $`\mathrm{c}`$ | `Generator_marginal_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one unit of output | +| $`\mathrm{c}^{(2)}`$ | `Generator_marginal_cost_quadratic` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of the square of one unit of output | +| $`\mathrm{N}^{\mathrm{fix}}`$ | `Generator_modules_installed` over $`\mathcal{G} \times \Xi`$ — 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{b}`$ | `Generator_operational_limit_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` where the data has no row — one where the generator is in the row's set — data prep; one outside it has no row | +| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — most output, per unit of nominal power — an availability profile | +| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — least output, per unit of nominal power | +| $`\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{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G} \times \Xi`$ — nominal power | +| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$ — whether the nominal power is a decision | | $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\mathcal{G} \times \Xi`$ — most nominal power an extendable generator may be built at | -| $`\mathrm{c}^{\mathrm{cap}}`$ | `Generator_capital_cost` over $`\mathcal{G} \times \Xi`$ — 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 | +| $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\mathcal{G} \times \Xi`$ — least nominal power an extendable generator may be built at | +| $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{p}^{\mathrm{nom,set}}`$ | `Generator_p_nom_set` over $`\mathcal{G}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$ — least energy over the horizon; minus infinity where no floor is meant | -| $`\overline{\mathrm{E}}`$ | `Generator_e_sum_max` over $`\mathcal{G} \times \Xi`$ — most energy over the horizon — a fuel or emission budget in energy terms; infinity where no cap is meant | +| $`\mathrm{p}^{\mathrm{set}}`$ | `Generator_p_set` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given output schedule; a generator without one has no row here | | $`\mathrm{a}`$ | `Generator_primary_energy_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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{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{m}`$ | `Generator_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{L}`$, `neutral` 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 | #### Conditions @@ -385,23 +385,23 @@ assumptions: | Symbol | Meaning | |---|---| -| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-p` — output of a generator in a snapshot | | $`N`$ | `Generator_n_mod` over $`\mathcal{G}`$ — `Generator-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-p` — output of a generator in a snapshot | | $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ — `Generator-p_nom` — nominal power where it is a decision, for a generator that is active; the parameter of the same PyPSA name carries the fixed regime | #### Definitions | Symbol | Meaning | |---|---| -| $`\widetilde{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_effective` over $`\mathcal{G} \times \Xi`$ — the build a generator's limits are taken against — the chosen one where it is extendable, the given one otherwise | +| $`\mathit{Generator\_additions}`$ | `Generator_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Generator\_capex}`$ | `Generator_capex` (scalar) | +| $`\mathit{Generator\_injection}`$ | `Generator_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Generator\_operational\_limit}`$ | `Generator_operational_limit` over $`\mathcal{L} \times \Xi`$ | +| $`\mathit{Generator\_opex}`$ | `Generator_opex` over $`\Xi`$ | | $`\widehat{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_committed` over $`\mathcal{G} \times \Xi`$ — the build a committed unit's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | +| $`\widetilde{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_effective` over $`\mathcal{G} \times \Xi`$ — the build a generator's limits are taken against — the chosen one where it is extendable, the given one otherwise | | $`\mathit{Generator\_primary\_energy}`$ | `Generator_primary_energy` over $`\mathcal{L} \times \Xi`$ | -| $`\mathit{Generator\_operational\_limit}`$ | `Generator_operational_limit` over $`\mathcal{L} \times \Xi`$ | | $`\mathit{Generator\_tech\_capacity\_expansion}`$ | `Generator_tech_capacity_expansion` over $`\mathcal{L}`$ | -| $`\mathit{Generator\_opex}`$ | `Generator_opex` over $`\Xi`$ | -| $`\mathit{Generator\_capex}`$ | `Generator_capex` (scalar) | -| $`\mathit{Generator\_additions}`$ | `Generator_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Generator\_injection}`$ | `Generator_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | #### Conditions @@ -413,16 +413,16 @@ assumptions: #### Variable domains -**`Generator_p`** +**`Generator_n_mod`** ```math -p_{g,\xi,t} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}_{g,t} +N_{g} \ge 0, N_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \wedge \mathrm{act}_{g} ``` -**`Generator_n_mod`** +**`Generator_p`** ```math -N_{g} \ge 0, N_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \wedge \mathrm{act}_{g} +p_{g,\xi,t} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}_{g,t} ``` **`Generator_p_nom_ext`** @@ -433,22 +433,22 @@ P_{g} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \ #### Definitions -**`Generator_p_nom_effective`** +**`Generator_additions`** ```math -\widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} P_{g} & \text{if } \mathrm{ext}_{g} \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Generator\_additions}_{i,y} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_carrier}(g) = i} P_{g} \cdot \mathrm{new}_{g,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -**`Generator_p_nom_committed`** +**`Generator_capex`** ```math -\widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} \mathrm{p}^{\mathrm{mod}}_{g} & \text{if } \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Generator\_capex} = \sum_{g \in \mathcal{G},\ \xi \in \Xi} \pi_{\xi} \cdot P_{g} \cdot \mathrm{c}^{\mathrm{cap}}_{g,\xi} \cdot \mathrm{W}_{g} ``` -**`Generator_primary_energy`** +**`Generator_injection`** ```math -\mathit{Generator\_primary\_energy}_{l,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{l,\xi,t} \cdot \mathrm{a}_{g,l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\mathit{Generator\_injection}_{n,\xi,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Generator_operational_limit`** @@ -457,48 +457,48 @@ P_{g} \in \mathbb{R} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \ \mathit{Generator\_operational\_limit}_{l,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{l,\xi,t} \cdot \mathrm{b}_{g,l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -**`Generator_tech_capacity_expansion`** +**`Generator_opex`** ```math -\mathit{Generator\_tech\_capacity\_expansion}_{l} = \sum_{g \in \mathcal{G}} P_{g} \cdot \mathrm{m}_{g,l} \qquad \forall\, l \in \mathcal{L} +\mathit{Generator\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot \mathrm{c}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot p_{g,\xi,t} \cdot \mathrm{c}^{(2)}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -**`Generator_opex`** +**`Generator_p_nom_committed`** ```math -\mathit{Generator\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot \mathrm{c}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} p_{g,\xi,t} \cdot p_{g,\xi,t} \cdot \mathrm{c}^{(2)}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} \mathrm{p}^{\mathrm{mod}}_{g} & \text{if } \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Generator_capex`** +**`Generator_p_nom_effective`** ```math -\mathit{Generator\_capex} = \sum_{g \in \mathcal{G},\ \xi \in \Xi} \pi_{\xi} \cdot P_{g} \cdot \mathrm{c}^{\mathrm{cap}}_{g,\xi} \cdot \mathrm{W}_{g} +\widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} = \begin{cases} P_{g} & \text{if } \mathrm{ext}_{g} \\ \mathrm{p}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Generator_additions`** +**`Generator_primary_energy`** ```math -\mathit{Generator\_additions}_{i,y} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_carrier}(g) = i} P_{g} \cdot \mathrm{new}_{g,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{Generator\_primary\_energy}_{l,\xi} = \sum_{g \in \mathcal{G}} \sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathit{w}^{\mathrm{gc}}_{l,\xi,t} \cdot \mathrm{a}_{g,l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -**`Generator_injection`** +**`Generator_tech_capacity_expansion`** ```math -\mathit{Generator\_injection}_{n,\xi,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{Generator\_bus}(g) = n} \mathrm{sgn}_{g} \cdot p_{g,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_tech\_capacity\_expansion}_{l} = \sum_{g \in \mathcal{G}} P_{g} \cdot \mathrm{m}_{g,l} \qquad \forall\, l \in \mathcal{L} ``` #### Subject to -**`Generator_fix_p_lower`** +**`Generator_e_sum_max`** ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \le \overline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \overline{\mathrm{E}}_{g,\xi} \text{ is defined} ``` -**`Generator_fix_p_upper`** +**`Generator_e_sum_min`** ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} +\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \ge \underline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \underline{\mathrm{E}}_{g,\xi} \text{ is defined} ``` **`Generator_ext_p_lower`** @@ -507,12 +507,6 @@ p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_ p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Generator_ext_p_upper`** - -```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} -``` - **`Generator_ext_p_nom_lower`** ```math @@ -525,22 +519,22 @@ P_{g} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \ P_{g} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \text{ is defined} ``` -**`Generator_p_nom_set`** +**`Generator_ext_p_upper`** ```math -P_{g} = \mathrm{p}^{\mathrm{nom,set}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \mathrm{p}^{\mathrm{nom,set}}_{g} \text{ is defined} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Generator_e_sum_min`** +**`Generator_fix_p_lower`** ```math -\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \ge \underline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \underline{\mathrm{E}}_{g,\xi} \text{ is defined} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Generator_e_sum_max`** +**`Generator_fix_p_upper`** ```math -\sum_{t \in \mathcal{T}} p_{g,\xi,t} \cdot \mathrm{w}^{\mathrm{gen}}_{t} \le \overline{\mathrm{E}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \overline{\mathrm{E}}_{g,\xi} \text{ is defined} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \gamma_{g,\xi} \cdot \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}_{g} \wedge \neg \mathrm{com}_{g} \wedge \mathrm{on}_{g,t} ``` **`Generator_p_nom_modularity`** @@ -549,6 +543,12 @@ P_{g} = \mathrm{p}^{\mathrm{nom,set}}_{g} \qquad \forall\, g \in \mathcal{G} \,: P_{g} = \mathrm{p}^{\mathrm{mod}}_{g} \cdot N_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \wedge \mathrm{act}_{g} ``` +**`Generator_p_nom_set`** + +```math +P_{g} = \mathrm{p}^{\mathrm{nom,set}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{ext}_{g} \wedge \mathrm{act}_{g} \wedge \mathrm{p}^{\mathrm{nom,set}}_{g} \text{ is defined} +``` + **`Generator_p_set`** ```math diff --git a/docs/examples/pypsa/generator_commitment.md b/docs/examples/pypsa/generator_commitment.md index 72b2efe8..b3f0826e 100644 --- a/docs/examples/pypsa/generator_commitment.md +++ b/docs/examples/pypsa/generator_commitment.md @@ -308,21 +308,21 @@ constraints: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | +| $`\gamma`$ | `Generator_maintenance_pu` over $`\mathcal{G} \times \Xi`$, data another file declares | +| $`\mathrm{N}^{\mathrm{fix}}`$ | `Generator_modules_installed` over $`\mathcal{G} \times \Xi`$, data another file declares | +| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\mathrm{nonneg}`$ | `Generator_p_min_pu_nonneg` over $`\mathcal{G}`$, data another file declares | | $`\mathrm{p}^{\mathrm{nom}}`$ | `Generator_p_nom` over $`\mathcal{G} \times \Xi`$, data another file declares | | $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$, data another file declares | -| $`\underline{\mathrm{p}}`$ | `Generator_p_min_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | -| $`\overline{\mathrm{p}}`$ | `Generator_p_max_pu` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, data another file declares | -| $`\mathrm{N}^{\mathrm{fix}}`$ | `Generator_modules_installed` over $`\mathcal{G} \times \Xi`$, data another file declares | -| $`\mathrm{nonneg}`$ | `Generator_p_min_pu_nonneg` over $`\mathcal{G}`$, data another file declares | -| $`\gamma`$ | `Generator_maintenance_pu` over $`\mathcal{G} \times \Xi`$, data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | -| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | -| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | -| $`N`$ | `Generator_n_mod` over $`\mathcal{G}`$ | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu^{\mathrm{nom}}`$ | `Generator_maintenance_capacity` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`\mu^{u}`$ | `Generator_maintenance_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | +| $`N`$ | `Generator_n_mod` over $`\mathcal{G}`$ | +| $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Generator_commitment_opex` to | | $`\mathrm{on}^{\mathrm{com}}`$ | `Generator_committed` over $`\mathcal{G} \times \mathcal{T}`$, a condition another file defines | @@ -331,25 +331,25 @@ constraints: | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units, each on one bus | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| +| $`\mathrm{M}`$ | `Generator_big_m` over $`\mathcal{G} \times \Xi`$, `neutral` 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{com}`$ | `Generator_committable` over $`\mathcal{G}`$ — whether output is gated by an on/off status decision | -| $`\mathrm{UT}`$ | `Generator_min_up_time` over $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays on once started | | $`\mathrm{DT}`$ | `Generator_min_down_time` over $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays off once stopped | -| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$ — one where the unit was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{hold}`$ | `Generator_must_stay_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the up time a unit brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{UT}`$ | `Generator_min_up_time` over $`\mathcal{G} \times \Xi`$ — least snapshots a unit stays on once started | | $`\mathrm{rest}`$ | `Generator_must_stay_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the down time a unit brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{\mathrm{up}}`$ | `Generator_start_up_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{hold}`$ | `Generator_must_stay_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — true while the up time a unit brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | | $`\mathrm{c}^{\mathrm{dn}}`$ | `Generator_shut_down_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{\mathrm{on}}`$ | `Generator_stand_by_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{M}`$ | `Generator_big_m` over $`\mathcal{G} \times \Xi`$, `neutral` 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{c}^{\mathrm{up}}`$ | `Generator_start_up_cost` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$ — one where the unit was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | #### Conditions @@ -361,17 +361,17 @@ constraints: | Symbol | Meaning | |---|---| -| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-status` — how much of a committable unit is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-start_up` — how much of a committable unit turns on this snapshot, capped as the status is | | $`\mathit{dn}`$ | `Generator_shut_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-shut_down` — how much of a committable unit turns off this snapshot, capped as the status is | +| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-start_up` — how much of a committable unit turns on this snapshot, capped as the status is | +| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — `Generator-status` — how much of a committable unit is on: an integer the rows below cap at one, or at the module count where the build is modular | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{Generator\_commitment\_opex}`$ | `Generator_commitment_opex` over $`\Xi`$ | | $`\overleftarrow{u}`$ | `Generator_previous_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the commitment state a generator carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | | $`\overleftarrow{u}^{\circ}`$ | `Generator_status_carried_over` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the state a generator carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | -| $`\mathit{Generator\_commitment\_opex}`$ | `Generator_commitment_opex` over $`\Xi`$ | #### Notation @@ -389,10 +389,10 @@ constraints: #### Variable domains -**`Generator_status`** +**`Generator_shut_down`** ```math -u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +\mathit{dn}_{g,\xi,t} \ge 0, \mathit{dn}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` **`Generator_start_up`** @@ -401,151 +401,151 @@ u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} \mathit{up}_{g,\xi,t} \ge 0, \mathit{up}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_shut_down`** +**`Generator_status`** ```math -\mathit{dn}_{g,\xi,t} \ge 0, \mathit{dn}_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +u_{g,\xi,t} \ge 0, u_{g,\xi,t} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` #### Definitions -**`Generator_previous_status`** +**`Generator_commitment_opex`** ```math -\overleftarrow{u}_{g,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}_{g,t - 1} \\ \overleftarrow{u}^{\circ}_{g,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Generator\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} u_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{on}}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{up}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{up}}_{g,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{dn}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{dn}}_{g,\xi,t} \qquad \forall\, \xi \in \Xi ``` -**`Generator_status_carried_over`** +**`Generator_previous_status`** ```math -\overleftarrow{u}^{\circ}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{u}_{g,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}_{g,t - 1} \\ \overleftarrow{u}^{\circ}_{g,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Generator_commitment_opex`** +**`Generator_status_carried_over`** ```math -\mathit{Generator\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} u_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{on}}_{g,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{up}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{up}}_{g,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{g \in \mathcal{G}} \mathit{dn}_{g,\xi,t} \cdot \mathrm{c}^{\mathrm{dn}}_{g,\xi,t} \qquad \forall\, \xi \in \Xi +\overleftarrow{u}^{\circ}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` #### Subject to -**`Generator_com_p_lower`** +**`Generator_com_down_time`** ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}} \mathit{dn}_{g,\xi,t'} \le 1 - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{DT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Generator_com_p_upper`** +**`Generator_com_ext_p_lower`** ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) + \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} - \mathrm{M}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -**`Generator_com_transition_start_up`** +**`Generator_com_ext_p_lower_nonneg`** ```math -\mathit{up}_{g,\xi,t} \ge u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +p_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \mathrm{nonneg}_{g} ``` -**`Generator_com_transition_shut_down`** +**`Generator_com_ext_p_upper_big_m`** ```math -\mathit{dn}_{g,\xi,t} \ge \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} +p_{g,\xi,t} \le \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -**`Generator_com_up_time`** +**`Generator_com_ext_p_upper_cap`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}} \mathit{up}_{g,\xi,t'} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{UT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} ``` -**`Generator_com_down_time`** +**`Generator_com_mod_p_lower`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}} \mathit{dn}_{g,\xi,t'} \le 1 - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{DT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_com_status_must_stay_up`** +**`Generator_com_mod_p_upper`** ```math -u_{g,\xi,t} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{hold}_{g,\xi,t} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_com_status_must_stay_down`** +**`Generator_com_p_lower`** ```math -u_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{rest}_{g,\xi,t} +p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_com_ext_p_upper_cap`** +**`Generator_com_p_upper`** ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_com_ext_p_upper_big_m`** +**`Generator_com_status_must_stay_down`** ```math -p_{g,\xi,t} \le \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +u_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{rest}_{g,\xi,t} ``` -**`Generator_com_ext_p_lower`** +**`Generator_com_status_must_stay_up`** ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \left( P_{g} - \gamma_{g,\xi} \cdot \mu^{\mathrm{nom}}_{g,\xi,t} \right) + \mathrm{M}_{g,\xi} \cdot u_{g,\xi,t} - \mathrm{M}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} +u_{g,\xi,t} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{hold}_{g,\xi,t} ``` -**`Generator_com_ext_p_lower_nonneg`** +**`Generator_com_transition_shut_down`** ```math -p_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \mathrm{nonneg}_{g} +\mathit{dn}_{g,\xi,t} \ge \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_com_mod_p_lower`** +**`Generator_com_transition_start_up`** ```math -p_{g,\xi,t} \ge \underline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mathit{up}_{g,\xi,t} \ge u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} ``` -**`Generator_com_mod_p_upper`** +**`Generator_com_up_time`** ```math -p_{g,\xi,t} \le \overline{\mathrm{p}}_{g,\xi,t} \cdot \mathrm{p}^{\mathrm{mod}}_{g} \cdot \left( u_{g,\xi,t} - \gamma_{g,\xi} \cdot \mu^{u}_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}} \mathit{up}_{g,\xi,t'} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{UT}_{g,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Generator_status_p_fixed_upper`** +**`Generator_shut_down_p_fixed_upper`** ```math -u_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{dn}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_start_up_p_fixed_upper`** +**`Generator_shut_down_p_nom_variable_upper`** ```math -\mathit{up}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{dn}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_shut_down_p_fixed_upper`** +**`Generator_start_up_p_fixed_upper`** ```math -\mathit{dn}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mathit{up}_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_status_p_nom_variable_upper`** +**`Generator_start_up_p_nom_variable_upper`** ```math -u_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mathit{up}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_start_up_p_nom_variable_upper`** +**`Generator_status_p_fixed_upper`** ```math -\mathit{up}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +u_{g,\xi,t} \le \mathrm{N}^{\mathrm{fix}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \left( \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_shut_down_p_nom_variable_upper`** +**`Generator_status_p_nom_variable_upper`** ```math -\mathit{dn}_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +u_{g,\xi,t} \le N_{g} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{ext}_{g} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` diff --git a/docs/examples/pypsa/generator_maintenance.md b/docs/examples/pypsa/generator_maintenance.md index f269f60c..227f32e7 100644 --- a/docs/examples/pypsa/generator_maintenance.md +++ b/docs/examples/pypsa/generator_maintenance.md @@ -251,33 +251,33 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$, data another file declares | +| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | | $`\mathrm{com}`$ | `Generator_committable` over $`\mathcal{G}`$, data another file declares | +| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$, data another file declares | +| $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\mathcal{G} \times \Xi`$, data another file declares | +| $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\mathcal{G} \times \Xi`$, data another file declares | | $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, data another file declares | -| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | -| $`\underline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_min` over $`\mathcal{G} \times \Xi`$, data another file declares | -| $`\overline{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_max` over $`\mathcal{G} \times \Xi`$, data another file declares | -| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ | +| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`\mathrm{on}^{\mathrm{com}}`$ | `Generator_committed` over $`\mathcal{G} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| +| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — generating units, each on one bus | | $`\Xi`$ | index $`\xi`$ — `scenario` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — dispatch periods | -| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{Generator\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{G} \times \Xi \times \mathcal{T}`$, `Generator_maintenance_cover` is `absent` where the data has no row — generating units, each on one bus | #### Parameters | Symbol | Meaning | |---|---| | $`\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 $`\mathcal{G} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\mathcal{G} \times \Xi`$ — how many maintenance events the horizon holds | | $`\tau^{\mathrm{mnt}}`$ | `Generator_maintenance_duration` over $`\mathcal{G} \times \Xi`$, `neutral` 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{n}^{\mathrm{mnt}}`$ | `Generator_maintenance_events` over $`\mathcal{G} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma`$ | `Generator_maintenance_pu` over $`\mathcal{G} \times \Xi`$ — the share of the build a maintenance event takes off | | $`\mathrm{blk}`$ | `Generator_maintenance_start_blocked` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — 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 | #### Conditions @@ -291,8 +291,8 @@ assumptions: | Symbol | Meaning | |---|---| | $`\mu`$ | `Generator_maintenance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance` — whether a maintainable generator is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{\mathrm{up}}`$ | `Generator_maintenance_start` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{\mathrm{nom}}`$ | `Generator_maintenance_capacity` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{\mathrm{up}}`$ | `Generator_maintenance_start` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{u}`$ | `Generator_maintenance_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Generator-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | #### Conditions @@ -311,16 +311,16 @@ assumptions: 0 \le \mu_{g,\xi,t} \le 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Generator_maintenance_start`** +**`Generator_maintenance_capacity`** ```math -\mu^{\mathrm{up}}_{g,\xi,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} +\mu^{\mathrm{nom}}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -**`Generator_maintenance_capacity`** +**`Generator_maintenance_start`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mu^{\mathrm{up}}_{g,\xi,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` **`Generator_maintenance_status`** @@ -337,40 +337,40 @@ assumptions: \sum_{t \in \mathcal{T}} \mu^{\mathrm{up}}_{g,\xi,t} = \mathrm{n}^{\mathrm{mnt}}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` -**`Generator_maint_window`** +**`Generator_maint_modstatus_lb`** ```math -\mu_{g,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ g,\ \xi,\ t' \right) \in \mathrm{Generator\_maintenance\_cover}} \mu^{\mathrm{up}}_{g,\xi,t'} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} +\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} - \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_maint_start_horizon`** +**`Generator_maint_modstatus_le_maint`** ```math -\mu^{\mathrm{up}}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} \wedge \mathrm{blk}_{g,\xi,t} +\mu^{u}_{g,\xi,t} \le \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_maintcap_upper`** +**`Generator_maint_modstatus_le_status`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \le P_{g} - \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 ``` -**`Generator_maintcap_upper_nommax`** +**`Generator_maint_start_horizon`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mu^{\mathrm{up}}_{g,\xi,t} = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} \wedge \mathrm{blk}_{g,\xi,t} ``` -**`Generator_maintcap_lower_nommax`** +**`Generator_maint_status_lb`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge P_{g} - \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} +\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} + \mu_{g,\xi,t} - 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_maintcap_lower_nommin`** +**`Generator_maint_status_le_maint`** ```math -\mu^{\mathrm{nom}}_{g,\xi,t} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} \wedge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} > 0 +\mu^{u}_{g,\xi,t} \le \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` **`Generator_maint_status_le_status`** @@ -379,54 +379,54 @@ assumptions: \mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) ``` -**`Generator_maint_status_le_maint`** +**`Generator_maint_window`** ```math -\mu^{u}_{g,\xi,t} \le \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mu_{g,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ g,\ \xi,\ t' \right) \in \mathrm{Generator\_maintenance\_cover}} \mu^{\mathrm{up}}_{g,\xi,t'} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}_{g,t} ``` -**`Generator_maint_status_lb`** +**`Generator_maintcap_lower_nommax`** ```math -\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} + \mu_{g,\xi,t} - 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \neg \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) +\mu^{\mathrm{nom}}_{g,\xi,t} \ge P_{g} - \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -**`Generator_maint_modstatus_le_status`** +**`Generator_maintcap_lower_nommin`** ```math -\mu^{u}_{g,\xi,t} \le u_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mu^{\mathrm{nom}}_{g,\xi,t} \ge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} \wedge \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} > 0 ``` -**`Generator_maint_modstatus_le_maint`** +**`Generator_maintcap_upper`** ```math -\mu^{u}_{g,\xi,t} \le \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mu^{\mathrm{nom}}_{g,\xi,t} \le P_{g} - \underline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` -**`Generator_maint_modstatus_lb`** +**`Generator_maintcap_upper_nommax`** ```math -\mu^{u}_{g,\xi,t} \ge u_{g,\xi,t} - \frac{\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi}}{\mathrm{p}^{\mathrm{mod}}_{g}} \cdot \left( 1 - \mu_{g,\xi,t} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}_{g} \wedge \mathrm{on}^{\mathrm{com}}_{g,t} \wedge \mathrm{p}^{\mathrm{mod}}_{g} > 0 +\mu^{\mathrm{nom}}_{g,\xi,t} \le \overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \mu_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{mnt,ext}}_{g,t} ``` #### Assumptions -**`Generator_maintenance_events_positive`** +**`Generator_maintenance_build_cap_is_finite`** ```math -\mathrm{n}^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{ext}_{g} ``` -**`Generator_maintenance_duration_positive`** +**`Generator_maintenance_duration_fits_the_horizon`** ```math -\tau^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\tau^{\mathrm{mnt}}_{g,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` -**`Generator_maintenance_duration_fits_the_horizon`** +**`Generator_maintenance_duration_positive`** ```math -\tau^{\mathrm{mnt}}_{g,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} +\tau^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` **`Generator_maintenance_events_fit_the_horizon`** @@ -435,10 +435,10 @@ assumptions: \tau^{\mathrm{mnt}}_{g,\xi} \cdot \mathrm{n}^{\mathrm{mnt}}_{g,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` -**`Generator_maintenance_build_cap_is_finite`** +**`Generator_maintenance_events_positive`** ```math -\overline{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} < \infty \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} \wedge \mathrm{ext}_{g} +\mathrm{n}^{\mathrm{mnt}}_{g,\xi} > 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{mnt}_{g} ``` **`Generator_maintenance_module_count_is_finite`** diff --git a/docs/examples/pypsa/generator_ramping.md b/docs/examples/pypsa/generator_ramping.md index ae33d81f..43764d96 100644 --- a/docs/examples/pypsa/generator_ramping.md +++ b/docs/examples/pypsa/generator_ramping.md @@ -265,40 +265,40 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$, data another file declares | +| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{M}`$ | `Generator_big_m` over $`\mathcal{G} \times \Xi`$, data another file declares | | $`\mathrm{com}`$ | `Generator_committable` over $`\mathcal{G}`$, data another file declares | -| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$, data another file declares | +| $`\mathrm{ext}`$ | `Generator_p_nom_extendable` over $`\mathcal{G}`$, data another file declares | | $`\mathrm{p}^{\mathrm{mod}}`$ | `Generator_p_nom_mod` over $`\mathcal{G}`$, data another file declares | -| $`\mathrm{M}`$ | `Generator_big_m` over $`\mathcal{G} \times \Xi`$, data another file declares | -| $`\mathrm{on}`$ | `Generator_active` over $`\mathcal{G} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{u}^{0}`$ | `Generator_status_initial` over $`\mathcal{G} \times \Xi`$, data another file declares | | $`p`$ | `Generator_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | -| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{dn}`$ | `Generator_shut_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`P`$ | `Generator_p_nom_ext` over $`\mathcal{G}`$ | -| $`\overleftarrow{u}`$ | `Generator_previous_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, an expression another file defines | -| $`\widetilde{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_effective` over $`\mathcal{G} \times \Xi`$, an expression another file defines | +| $`\mathit{dn}`$ | `Generator_shut_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{up}`$ | `Generator_start_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | +| $`u`$ | `Generator_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ | | $`\widehat{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_committed` over $`\mathcal{G} \times \Xi`$, an expression another file defines | +| $`\widetilde{\mathrm{p}}^{\mathrm{nom}}`$ | `Generator_p_nom_effective` over $`\mathcal{G} \times \Xi`$, an expression another file defines | +| $`\overleftarrow{u}`$ | `Generator_previous_status` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, an expression another file defines | | $`\mathrm{on}^{\mathrm{com,ext}}`$ | `Generator_com_ext` over $`\mathcal{G} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units, each on one bus | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{ru}`$ | `Generator_ramp_limit_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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{p}^{0}`$ | `Generator_p_init` over $`\mathcal{G} \times \Xi`$, `neutral` 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 | | $`\mathrm{rd}`$ | `Generator_ramp_limit_down` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \Xi`$, `neutral` 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 | +| $`\mathrm{ru}^{\mathrm{up}}`$ | `Generator_ramp_limit_start_up` over $`\mathcal{G} \times \Xi`$, `neutral` 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{ru}`$ | `Generator_ramp_limit_up` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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 | #### Conditions @@ -311,12 +311,12 @@ assumptions: | Symbol | Meaning | |---|---| | $`\overleftarrow{p}`$ | `Generator_previous_p` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the output a generator carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | -| $`\widetilde{\mathrm{ru}}`$ | `Generator_ramp_up_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\Delta^{-}`$ | `Generator_ramp_down_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may lower output between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}`$ | `Generator_ramp_down_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{\mathrm{up}}`$ | `Generator_start_up_rate` over $`\mathcal{G} \times \Xi`$ — the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{\mathrm{dn}}`$ | `Generator_shut_down_rate` over $`\mathcal{G} \times \Xi`$ — the shut-down ramp a unit's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | | $`\Delta^{+}`$ | `Generator_ramp_up_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may raise output between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{-}`$ | `Generator_ramp_down_allowance` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — how far a generator may lower output between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}`$ | `Generator_ramp_up_rate` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$ — the ramp limit a unit's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{\mathrm{dn}}`$ | `Generator_shut_down_rate` over $`\mathcal{G} \times \Xi`$ — the shut-down ramp a unit's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{\mathrm{up}}`$ | `Generator_start_up_rate` over $`\mathcal{G} \times \Xi`$ — the start-up ramp a unit's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | #### Notation @@ -341,10 +341,10 @@ assumptions: \overleftarrow{p}_{g,\xi,t} = \begin{cases} \mathrm{u}^{0}_{g,\xi} \cdot \mathrm{p}^{0}_{g,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ p_{g,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Generator_ramp_up_rate`** +**`Generator_ramp_down_allowance`** ```math -\widetilde{\mathrm{ru}}_{g,\xi,t} = \begin{cases} \mathrm{ru}_{g,\xi,t} & \text{if } \mathrm{ru}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\Delta^{-}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot u_{g,\xi,t} + \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Generator_ramp_down_rate`** @@ -353,42 +353,36 @@ assumptions: \widetilde{\mathrm{rd}}_{g,\xi,t} = \begin{cases} \mathrm{rd}_{g,\xi,t} & \text{if } \mathrm{rd}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Generator_start_up_rate`** +**`Generator_ramp_up_allowance`** ```math -\widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} = \begin{cases} \mathrm{ru}^{\mathrm{up}}_{g,\xi} & \text{if } \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\Delta^{+}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} + \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Generator_shut_down_rate`** +**`Generator_ramp_up_rate`** ```math -\widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} = \begin{cases} \mathrm{rd}^{\mathrm{dn}}_{g,\xi} & \text{if } \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\widetilde{\mathrm{ru}}_{g,\xi,t} = \begin{cases} \mathrm{ru}_{g,\xi,t} & \text{if } \mathrm{ru}_{g,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Generator_ramp_up_allowance`** +**`Generator_shut_down_rate`** ```math -\Delta^{+}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} + \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( u_{g,\xi,t} - \overleftarrow{u}_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} = \begin{cases} \mathrm{rd}^{\mathrm{dn}}_{g,\xi} & \text{if } \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Generator_ramp_down_allowance`** +**`Generator_start_up_rate`** ```math -\Delta^{-}_{g,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot u_{g,\xi,t} + \widetilde{\mathrm{rd}}^{\mathrm{dn}}_{g,\xi} \cdot \widehat{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} \cdot \left( \overleftarrow{u}_{g,\xi,t} - u_{g,\xi,t} \right) & \text{if } \mathrm{com}_{g} \\ \widetilde{\mathrm{rd}}_{g,\xi,t} \cdot \widetilde{\mathrm{p}}^{\mathrm{nom}}_{g,\xi} & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} = \begin{cases} \mathrm{ru}^{\mathrm{up}}_{g,\xi} & \text{if } \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` #### Subject to -**`Generator_p_ramp_limit_up_run_big_m`** - -```math -p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} -``` - -**`Generator_p_ramp_limit_up_start_big_m`** +**`Generator_p_ramp_limit_down`** ```math -p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{up}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \Delta^{-}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} ``` **`Generator_p_ramp_limit_down_run_big_m`** @@ -409,10 +403,16 @@ p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}^{\mathrm{u p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \Delta^{+}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} ``` -**`Generator_p_ramp_limit_down`** +**`Generator_p_ramp_limit_up_run_big_m`** ```math -\overleftarrow{p}_{g,\xi,t} - p_{g,\xi,t} \le \Delta^{-}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}_{g,\xi,t} \text{ is defined} \vee \mathrm{rd}^{\mathrm{dn}}_{g,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}_{g} \wedge \mathrm{ext}_{g} \wedge \neg \left( \mathrm{p}^{\mathrm{mod}}_{g} > 0 \right) \right) \wedge \mathrm{prev}_{g,\xi,t} \wedge \mathrm{on}_{g,t} +p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}_{g,\xi,t} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \overleftarrow{u}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} +``` + +**`Generator_p_ramp_limit_up_start_big_m`** + +```math +p_{g,\xi,t} - \overleftarrow{p}_{g,\xi,t} \le \widetilde{\mathrm{ru}}^{\mathrm{up}}_{g,\xi} \cdot P_{g} + \mathrm{M}_{g,\xi} - \mathrm{M}_{g,\xi} \cdot \mathit{up}_{g,\xi,t} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{\mathrm{com,ext}}_{g,t} \wedge \left( \mathrm{ru}_{g,\xi,t} \text{ is defined} \vee \mathrm{ru}^{\mathrm{up}}_{g,\xi} \text{ is defined} \right) \wedge \mathrm{prev}_{g,\xi,t} ``` #### Assumptions diff --git a/docs/examples/pypsa/global_constraints.md b/docs/examples/pypsa/global_constraints.md index 976ff3eb..91efaa46 100644 --- a/docs/examples/pypsa/global_constraints.md +++ b/docs/examples/pypsa/global_constraints.md @@ -144,87 +144,87 @@ assumptions: | Symbol | Meaning | |---|---| | $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression another file defines | | $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{G} \times \Xi`$, an expression another file defines | -| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression another file defines | -| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression another file defines | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression another file defines | | $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression another file defines | +| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression another file defines | +| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression another file defines | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{type}`$ | `GlobalConstraint_type` over $`\mathcal{G}`$ — which formula the row takes — `primary_energy`, `operational_limit`, `transmission_volume_expansion_limit`, `transmission_expansion_cost_limit` or `tech_capacity_expansion_limit` | -| $`\mathrm{sense}`$ | `GlobalConstraint_sense` over $`\mathcal{G} \times \Xi`$ — 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 $`\mathcal{G} \times \Xi`$ — 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{sense}`$ | `GlobalConstraint_sense` over $`\mathcal{G} \times \Xi`$ — which way the row binds in each scenario — `<=`, `>=` or `==`; PyPSA reads a row's sense per scenario (`global_constraints.py:551`, `:749`, `:829`) | +| $`\mathrm{type}`$ | `GlobalConstraint_type` over $`\mathcal{G}`$ — which formula the row takes — `primary_energy`, `operational_limit`, `transmission_volume_expansion_limit`, `transmission_expansion_cost_limit` or `tech_capacity_expansion_limit` | #### Subject to -**`GlobalConstraint_primary_energy_ub`** +**`GlobalConstraint_operational_limit_eq`** ```math -\mathit{primary\_energy}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} +\mathit{operational\_limit}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} ``` -**`GlobalConstraint_primary_energy_lb`** +**`GlobalConstraint_operational_limit_lb`** ```math -\mathit{primary\_energy}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} +\mathit{operational\_limit}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} ``` -**`GlobalConstraint_primary_energy_eq`** +**`GlobalConstraint_operational_limit_ub`** ```math -\mathit{primary\_energy}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} +\mathit{operational\_limit}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} ``` -**`GlobalConstraint_operational_limit_ub`** +**`GlobalConstraint_primary_energy_eq`** ```math -\mathit{operational\_limit}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} +\mathit{primary\_energy}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} ``` -**`GlobalConstraint_operational_limit_lb`** +**`GlobalConstraint_primary_energy_lb`** ```math -\mathit{operational\_limit}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} +\mathit{primary\_energy}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} ``` -**`GlobalConstraint_operational_limit_eq`** +**`GlobalConstraint_primary_energy_ub`** ```math -\mathit{operational\_limit}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{operational\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} +\mathit{primary\_energy}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{primary\_energy}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} ``` -**`GlobalConstraint_transmission_volume_expansion_limit_ub`** +**`GlobalConstraint_tech_capacity_expansion_limit_eq`** ```math -\mathit{transmission\_volume\_expansion}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} +\mathit{tech\_capacity\_expansion}_{g} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} ``` -**`GlobalConstraint_transmission_volume_expansion_limit_lb`** +**`GlobalConstraint_tech_capacity_expansion_limit_lb`** ```math -\mathit{transmission\_volume\_expansion}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} +\mathit{tech\_capacity\_expansion}_{g} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} ``` -**`GlobalConstraint_transmission_volume_expansion_limit_eq`** +**`GlobalConstraint_tech_capacity_expansion_limit_ub`** ```math -\mathit{transmission\_volume\_expansion}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} +\mathit{tech\_capacity\_expansion}_{g} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} ``` -**`GlobalConstraint_transmission_expansion_cost_limit_ub`** +**`GlobalConstraint_transmission_expansion_cost_limit_eq`** ```math -\mathit{transmission\_expansion\_cost}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} +\mathit{transmission\_expansion\_cost}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} ``` **`GlobalConstraint_transmission_expansion_cost_limit_lb`** @@ -233,28 +233,28 @@ assumptions: \mathit{transmission\_expansion\_cost}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} ``` -**`GlobalConstraint_transmission_expansion_cost_limit_eq`** +**`GlobalConstraint_transmission_expansion_cost_limit_ub`** ```math -\mathit{transmission\_expansion\_cost}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} +\mathit{transmission\_expansion\_cost}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_expansion\_cost\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} ``` -**`GlobalConstraint_tech_capacity_expansion_limit_ub`** +**`GlobalConstraint_transmission_volume_expansion_limit_eq`** ```math -\mathit{tech\_capacity\_expansion}_{g} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} +\mathit{transmission\_volume\_expansion}_{g,\xi} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} ``` -**`GlobalConstraint_tech_capacity_expansion_limit_lb`** +**`GlobalConstraint_transmission_volume_expansion_limit_lb`** ```math -\mathit{tech\_capacity\_expansion}_{g} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} +\mathit{transmission\_volume\_expansion}_{g,\xi} \ge \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{>=}\text{'} ``` -**`GlobalConstraint_tech_capacity_expansion_limit_eq`** +**`GlobalConstraint_transmission_volume_expansion_limit_ub`** ```math -\mathit{tech\_capacity\_expansion}_{g} = \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{tech\_capacity\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{==}\text{'} +\mathit{transmission\_volume\_expansion}_{g,\xi} \le \mathrm{K}_{g,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi \,:\, \mathrm{type}_{g} = \text{'}\mathrm{transmission\_volume\_expansion\_limit}\text{'} \wedge \mathrm{sense}_{g,\xi} = \text{'}\mathrm{<=}\text{'} ``` #### Assumptions diff --git a/docs/examples/pypsa/index.md b/docs/examples/pypsa/index.md index c998873d..6a51bf42 100644 --- a/docs/examples/pypsa/index.md +++ b/docs/examples/pypsa/index.md @@ -51,15 +51,15 @@ The fragments are of three kinds: | Sum | Over | Read in | The terms, by the fragment that adds each | | --- | --- | --- | --- | | `total_cost` | scalar | [settings](settings.md) | [`risk_weighted_opex`](cost.md), [`Generator_capex`](generator.md), [`Line_capex`](line.md), [`Link_capex`](link.md), [`Process_capex`](process.md), [`StorageUnit_capex`](storage_unit.md), [`Store_capex`](store.md), [`Transformer_capex`](transformer.md) | -| `scenario_opex` | `scenario` | [settings](settings.md) | [`Generator_opex`](generator.md), [`Generator_commitment_opex`](generator_commitment.md), [`Link_opex`](link.md), [`Link_commitment_opex`](link_commitment.md), [`Process_opex`](process.md), [`Process_commitment_opex`](process_commitment.md), [`StorageUnit_opex`](storage_unit.md), [`Store_opex`](store.md) | | `Bus_injection` | `bus, scenario, snapshot` | [network](network.md) | [`Generator_injection`](generator.md), [`Line_injection`](line.md), [`Link_injection`](link.md), [`Load_injection`](load.md), [`Process_injection`](process.md), [`StorageUnit_injection`](storage_unit.md), [`Store_injection`](store.md), [`Transformer_injection`](transformer.md) | -| `tech_capacity_expansion` | `global_constraint` | [settings](settings.md) | [`Generator_tech_capacity_expansion`](generator.md), [`Line_tech_capacity_expansion`](line.md), [`Link_tech_capacity_expansion`](link.md), [`Process_tech_capacity_expansion`](process.md), [`StorageUnit_tech_capacity_expansion`](storage_unit.md), [`Store_tech_capacity_expansion`](store.md) | +| `scenario_opex` | `scenario` | [settings](settings.md) | [`Generator_opex`](generator.md), [`Generator_commitment_opex`](generator_commitment.md), [`Link_opex`](link.md), [`Link_commitment_opex`](link_commitment.md), [`Process_opex`](process.md), [`Process_commitment_opex`](process_commitment.md), [`StorageUnit_opex`](storage_unit.md), [`Store_opex`](store.md) | | `Carrier_additions` | `carrier, period` | [settings](settings.md) | [`Generator_additions`](generator.md), [`Line_additions`](line.md), [`Link_additions`](link.md), [`Process_additions`](process.md), [`StorageUnit_additions`](storage_unit.md), [`Store_additions`](store.md) | -| `primary_energy` | `global_constraint, scenario` | [settings](settings.md) | [`Generator_primary_energy`](generator.md), [`StorageUnit_primary_energy`](storage_unit.md), [`Store_primary_energy`](store.md) | +| `tech_capacity_expansion` | `global_constraint` | [settings](settings.md) | [`Generator_tech_capacity_expansion`](generator.md), [`Line_tech_capacity_expansion`](line.md), [`Link_tech_capacity_expansion`](link.md), [`Process_tech_capacity_expansion`](process.md), [`StorageUnit_tech_capacity_expansion`](storage_unit.md), [`Store_tech_capacity_expansion`](store.md) | | `operational_limit` | `global_constraint, scenario` | [settings](settings.md) | [`Generator_operational_limit`](generator.md), [`StorageUnit_operational_limit`](storage_unit.md), [`Store_operational_limit`](store.md) | -| `transmission_volume_expansion` | `global_constraint, scenario` | [settings](settings.md) | [`Line_transmission_volume_expansion`](line.md), [`Link_transmission_volume_expansion`](link.md) | -| `transmission_expansion_cost` | `global_constraint, scenario` | [settings](settings.md) | [`Line_transmission_expansion_cost`](line.md), [`Link_transmission_expansion_cost`](link.md) | +| `primary_energy` | `global_constraint, scenario` | [settings](settings.md) | [`Generator_primary_energy`](generator.md), [`StorageUnit_primary_energy`](storage_unit.md), [`Store_primary_energy`](store.md) | | `Cycle_angle_sum` | `cycle, scenario, snapshot` | [power_flow](power_flow.md) | [`Line_angle_sum`](line.md), [`Transformer_angle_sum`](transformer.md) | +| `transmission_expansion_cost` | `global_constraint, scenario` | [settings](settings.md) | [`Line_transmission_expansion_cost`](line.md), [`Link_transmission_expansion_cost`](link.md) | +| `transmission_volume_expansion` | `global_constraint, scenario` | [settings](settings.md) | [`Line_transmission_volume_expansion`](line.md), [`Link_transmission_volume_expansion`](link.md) | ### The fragments @@ -67,28 +67,28 @@ The fragments are of three kinds: | --- | --- | --- | --- | --- | --- | | [carrier](carrier.md) | 2 | 0 | 1 | 1 | | | [cost](cost.md) | 1 | 3 | 2 | 4 | `total_cost` | -| [generator](generator.md) | 24 | 3 | 11 | 17 | `primary_energy`, `operational_limit`, `tech_capacity_expansion`, `scenario_opex`, `total_cost`, `Carrier_additions`, `Bus_injection` | +| [generator](generator.md) | 24 | 3 | 11 | 17 | `Carrier_additions`, `total_cost`, `Bus_injection`, `operational_limit`, `scenario_opex`, `primary_energy`, `tech_capacity_expansion` | | [generator_commitment](generator_commitment.md) | 10 | 3 | 20 | 17 | `scenario_opex` | | [generator_maintenance](generator_maintenance.md) | 5 | 4 | 13 | 9 | | | [generator_ramping](generator_ramping.md) | 5 | 0 | 6 | 14 | | | [global_constraints](global_constraints.md) | 3 | 0 | 15 | 6 | | -| [line](line.md) | 22 | 4 | 14 | 9 | `transmission_volume_expansion`, `transmission_expansion_cost`, `tech_capacity_expansion`, `total_cost`, `Carrier_additions`, `Bus_injection`, `Cycle_angle_sum` | -| [link](link.md) | 24 | 3 | 9 | 16 | `transmission_volume_expansion`, `transmission_expansion_cost`, `tech_capacity_expansion`, `scenario_opex`, `total_cost`, `Carrier_additions`, `Bus_injection` | +| [line](line.md) | 22 | 4 | 14 | 9 | `Carrier_additions`, `Cycle_angle_sum`, `total_cost`, `Bus_injection`, `tech_capacity_expansion`, `transmission_expansion_cost`, `transmission_volume_expansion` | +| [link](link.md) | 24 | 3 | 9 | 16 | `Carrier_additions`, `total_cost`, `Bus_injection`, `scenario_opex`, `tech_capacity_expansion`, `transmission_expansion_cost`, `transmission_volume_expansion` | | [link_commitment](link_commitment.md) | 10 | 3 | 20 | 17 | `scenario_opex` | | [link_maintenance](link_maintenance.md) | 5 | 4 | 13 | 9 | | | [link_ramping](link_ramping.md) | 5 | 0 | 6 | 14 | | | [load](load.md) | 3 | 0 | 0 | 1 | `Bus_injection` | | [network](network.md) | 0 | 0 | 1 | 1 | | | [power_flow](power_flow.md) | 0 | 0 | 1 | 1 | | -| [process](process.md) | 22 | 3 | 9 | 14 | `tech_capacity_expansion`, `scenario_opex`, `total_cost`, `Carrier_additions`, `Bus_injection` | +| [process](process.md) | 22 | 3 | 9 | 14 | `Carrier_additions`, `total_cost`, `Bus_injection`, `scenario_opex`, `tech_capacity_expansion` | | [process_commitment](process_commitment.md) | 10 | 3 | 20 | 17 | `scenario_opex` | | [process_maintenance](process_maintenance.md) | 5 | 4 | 13 | 9 | | | [process_ramping](process_ramping.md) | 5 | 0 | 6 | 14 | | | [security](security.md) | 2 | 0 | 8 | 10 | | | [settings](settings.md) | 9 | 0 | 0 | 8 | | -| [storage_unit](storage_unit.md) | 36 | 6 | 21 | 14 | `primary_energy`, `operational_limit`, `tech_capacity_expansion`, `scenario_opex`, `total_cost`, `Carrier_additions`, `Bus_injection` | -| [store](store.md) | 29 | 4 | 11 | 14 | `primary_energy`, `operational_limit`, `tech_capacity_expansion`, `scenario_opex`, `total_cost`, `Carrier_additions`, `Bus_injection` | -| [transformer](transformer.md) | 24 | 5 | 16 | 5 | `total_cost`, `Bus_injection`, `Cycle_angle_sum` | +| [storage_unit](storage_unit.md) | 36 | 6 | 21 | 14 | `Carrier_additions`, `total_cost`, `Bus_injection`, `operational_limit`, `scenario_opex`, `primary_energy`, `tech_capacity_expansion` | +| [store](store.md) | 29 | 4 | 11 | 14 | `Carrier_additions`, `total_cost`, `Bus_injection`, `operational_limit`, `scenario_opex`, `primary_energy`, `tech_capacity_expansion` | +| [transformer](transformer.md) | 24 | 5 | 16 | 5 | `Cycle_angle_sum`, `total_cost`, `Bus_injection` | ## Leaving a file out diff --git a/docs/examples/pypsa/line.md b/docs/examples/pypsa/line.md index 2cf97aa3..e2719a49 100644 --- a/docs/examples/pypsa/line.md +++ b/docs/examples/pypsa/line.md @@ -357,27 +357,27 @@ constraints: |---|---| | $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathrm{lossy}`$ | `transmission_losses` (scalar), data another file declares | -| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Line_transmission_volume_expansion` to | -| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Line_transmission_expansion_cost` to | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Line_tech_capacity_expansion` to | -| $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Line_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Line_additions` to | | $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Line_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Line_additions` to | | $`\mathit{Cycle\_angle\_sum}`$ | `Cycle_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$, an expression this file adds `Line_angle_sum` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Line_tech_capacity_expansion` to | +| $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Line_capex` to | +| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Line_transmission_expansion_cost` to | +| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Line_transmission_volume_expansion` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{K}`$ | index $`k`$ — `line` with $`\mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I},\ \mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N}`$ — passive branches, each between two buses, their flow set by impedance | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{C}`$ | index $`c`$ — `cycle` — independent cycles of the passive network graph — the cycle basis, data prep. Each period has its own basis, of the branches that stand in it; a label is a position in that period's basis, so one label names a different cycle in another period | -| $`\mathcal{E}`$ | index $`e`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | +| $`\mathcal{K}`$ | index $`k`$ — `line` with $`\mathrm{Line\_bus0}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_bus1}: \mathcal{K} \to \mathcal{N},\ \mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I}`$ — passive branches, each between two buses, their flow set by impedance | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Line\_carrier}: \mathcal{K} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{E}`$ | index $`e`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters @@ -385,26 +385,26 @@ constraints: |---|---| | $`\mathrm{on}^{s}`$ | `Line_active` over $`\mathcal{K} \times \mathcal{T}`$ — whether a line stands in a snapshot's period — PyPSA's `active`, data prep | | $`\mathrm{act}^{s}`$ | `Line_active_asset` over $`\mathcal{K}`$ — whether a line 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{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\mathcal{K} \times \Xi`$ — 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{W}^{s}`$ | `Line_capital_weight` over $`\mathcal{K}`$ — the sum of period weights a line stands in — PyPSA's `active * period_weighting`, summed, data prep | +| $`\mathrm{x}`$ | `Line_cycle_weight` over $`\mathcal{C} \times \mathcal{K} \times \mathcal{Y}`$, `neutral` 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{cc}`$ | `Line_expansion_cost_weight` over $`\mathcal{G} \times \mathcal{K} \times \Xi`$, `neutral` 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{new}^{s}`$ | `Line_first_active` over $`\mathcal{K} \times \mathcal{Y}`$ — one in the first period a line stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | +| $`\overline{\ell}`$ | `Line_loss_max` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the loss at a line's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, data prep | +| $`\mathrm{b}`$ | `Line_loss_offset` over $`\mathcal{K} \times \Xi \times \mathcal{E} \times \mathcal{T}`$ — 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{a}`$ | `Line_loss_slope` over $`\mathcal{K} \times \Xi \times \mathcal{E} \times \mathcal{T}`$ — 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 | +| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — most flow either way, per unit of nominal apparent power | | $`\mathrm{s}^{\mathrm{nom}}`$ | `Line_s_nom` over $`\mathcal{K} \times \Xi`$ — 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — most flow either way, per unit of nominal apparent power | -| $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\mathcal{K} \times \Xi`$ — least nominal apparent power an extendable line may be built at | | $`\overline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_max` over $`\mathcal{K} \times \Xi`$ — most nominal apparent power an extendable line may be built at | -| $`\mathrm{c}^{\mathrm{cap},s}`$ | `Line_capital_cost` over $`\mathcal{K} \times \Xi`$ — 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 | +| $`\underline{\mathrm{s}}^{\mathrm{nom}}`$ | `Line_s_nom_min` over $`\mathcal{K} \times \Xi`$ — least nominal apparent power an extendable line may be built at | +| $`\mathrm{s}^{\mathrm{mod}}`$ | `Line_s_nom_mod` over $`\mathcal{K}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{s}^{\mathrm{nom,set}}`$ | `Line_s_nom_set` over $`\mathcal{K}`$, `neutral` 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 $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given flow schedule; a line without one has no row here | +| $`\mathrm{m}^{l}`$ | `Line_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{K}`$, `neutral` 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 | | $`\overline{\delta}`$ | `Line_v_ang_max` over $`\mathcal{K} \times \Xi`$, `neutral` 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 $`\mathcal{K} \times \Xi`$ — 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{C} \times \mathcal{K} \times \mathcal{Y}`$, `neutral` 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 $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — 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 $`\mathcal{K} \times \Xi \times \mathcal{E} \times \mathcal{T}`$ — 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 $`\mathcal{K} \times \Xi \times \mathcal{E} \times \mathcal{T}`$ — 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 $`\mathcal{G} \times \mathcal{K} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \mathcal{K} \times \Xi`$, `neutral` 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}`$, `neutral` 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{x}^{\mathrm{eff}}`$ | `Line_x_pu_eff` over $`\mathcal{K} \times \Xi`$ — the line's effective series reactance — PyPSA's `x_pu_eff`, `x` over the square of its bus's nominal voltage, data prep | #### Conditions @@ -416,23 +416,23 @@ constraints: | Symbol | Meaning | |---|---| -| $`s`$ | `Line_s` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — `Line-s` — PyPSA's `p0`, the flow measured at the `Line_bus0` end: a positive value withdraws there and injects at `Line_bus1`, lossless | | $`\ell`$ | `Line_loss` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Line-loss` — what a line dissipates carrying its flow, pushed down by the cost and held up by the cuts; absent, and zero in the balance, where the network is lossless | -| $`S`$ | `Line_s_nom_ext` over $`\mathcal{K}`$ — `Line-s_nom` — nominal apparent power where it is a decision, for a line that is active; the parameter of the same PyPSA name carries the fixed regime | | $`N^{s}`$ | `Line_n_mod` over $`\mathcal{K}`$ — `Line-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`s`$ | `Line_s` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — `Line-s` — PyPSA's `p0`, the flow measured at the `Line_bus0` end: a positive value withdraws there and injects at `Line_bus1`, lossless | +| $`S`$ | `Line_s_nom_ext` over $`\mathcal{K}`$ — `Line-s_nom` — nominal apparent power where it is a decision, for a line that is active; the parameter of the same PyPSA name carries the fixed regime | #### Definitions | Symbol | Meaning | |---|---| -| $`\mathit{Line\_transmission\_volume\_expansion}`$ | `Line_transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{Line\_transmission\_expansion\_cost}`$ | `Line_transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{Line\_tech\_capacity\_expansion}`$ | `Line_tech_capacity_expansion` over $`\mathcal{G}`$ | -| $`\mathit{Line\_capex}`$ | `Line_capex` (scalar) | | $`\mathit{Line\_additions}`$ | `Line_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\check{s}`$ | `Line_s_monitored` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the flow a line's post-contingency rows read — its flow where it stands, nothing where it does not, since PyPSA builds those rows for every branch of the sub-network in every snapshot | -| $`\mathit{Line\_injection}`$ | `Line_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | | $`\mathit{Line\_angle\_sum}`$ | `Line_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Line\_capex}`$ | `Line_capex` (scalar) | +| $`\mathit{Line\_injection}`$ | `Line_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\check{s}`$ | `Line_s_monitored` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$ — the flow a line's post-contingency rows read — its flow where it stands, nothing where it does not, since PyPSA builds those rows for every branch of the sub-network in every snapshot | +| $`\mathit{Line\_tech\_capacity\_expansion}`$ | `Line_tech_capacity_expansion` over $`\mathcal{G}`$ | +| $`\mathit{Line\_transmission\_expansion\_cost}`$ | `Line_transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$ | +| $`\mathit{Line\_transmission\_volume\_expansion}`$ | `Line_transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$ | #### Conditions @@ -444,48 +444,42 @@ constraints: #### Variable domains -**`Line_s`** - -```math -s_{k,\xi,t} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s}_{k,t} -``` - **`Line_loss`** ```math \ell_{k,\xi,t} \ge 0 \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -**`Line_s_nom_ext`** +**`Line_n_mod`** ```math -S_{k} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} +N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} ``` -**`Line_n_mod`** +**`Line_s`** ```math -N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} +s_{k,\xi,t} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s}_{k,t} ``` -#### Definitions - -**`Line_transmission_volume_expansion`** +**`Line_s_nom_ext`** ```math -\mathit{Line\_transmission\_volume\_expansion}_{g,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{len}_{g,k,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +S_{k} \in \mathbb{R} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} ``` -**`Line_transmission_expansion_cost`** +#### Definitions + +**`Line_additions`** ```math -\mathit{Line\_transmission\_expansion\_cost}_{g,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{cc}_{g,k,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Line\_additions}_{i,y} = \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_carrier}(k) = i} S_{k} \cdot \mathrm{new}^{s}_{k,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -**`Line_tech_capacity_expansion`** +**`Line_angle_sum`** ```math -\mathit{Line\_tech\_capacity\_expansion}_{g} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{m}^{l}_{g,k} \qquad \forall\, g \in \mathcal{G} +\mathit{Line\_angle\_sum}_{c,\xi,t} = \sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Line_capex`** @@ -494,10 +488,10 @@ N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,: \mathit{Line\_capex} = \sum_{k \in \mathcal{K},\ \xi \in \Xi} \pi_{\xi} \cdot S_{k} \cdot \mathrm{c}^{\mathrm{cap},s}_{k,\xi} \cdot \mathrm{W}^{s}_{k} ``` -**`Line_additions`** +**`Line_injection`** ```math -\mathit{Line\_additions}_{i,y} = \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_carrier}(k) = i} S_{k} \cdot \mathrm{new}^{s}_{k,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{Line\_injection}_{n,\xi,t} = -\left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Line_s_monitored`** @@ -506,36 +500,42 @@ N^{s}_{k} \ge 0, N^{s}_{k} \in \mathbb{Z} \qquad \forall\, k \in \mathcal{K} \,: \check{s}_{k,\xi,t} = \begin{cases} s_{k,\xi,t} & \text{if } \mathrm{on}^{s}_{k,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Line_injection`** +**`Line_tech_capacity_expansion`** ```math -\mathit{Line\_injection}_{n,\xi,t} = -\left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} s_{k,\xi,t} \right) + \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} s_{k,\xi,t} - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus0}(k) = n} \ell_{k,\xi,t} \right) - 0.5 \cdot \left( \sum_{k \in \mathcal{K} \,:\, \mathrm{Line\_bus1}(k) = n} \ell_{k,\xi,t} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Line\_tech\_capacity\_expansion}_{g} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{m}^{l}_{g,k} \qquad \forall\, g \in \mathcal{G} ``` -**`Line_angle_sum`** +**`Line_transmission_expansion_cost`** ```math -\mathit{Line\_angle\_sum}_{c,\xi,t} = \sum_{k \in \mathcal{K}} s_{k,\xi,t} \cdot \mathrm{x}_{c,k,\mathrm{snapshot\_period}(t)} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Line\_transmission\_expansion\_cost}_{g,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{cc}_{g,k,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +``` + +**`Line_transmission_volume_expansion`** + +```math +\mathit{Line\_transmission\_volume\_expansion}_{g,\xi} = \sum_{k \in \mathcal{K}} S_{k} \cdot \mathrm{len}_{g,k,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` #### Subject to -**`Line_fix_s_lower`** +**`Line_ext_s_lower`** ```math -s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_fix_s_upper`** +**`Line_ext_s_nom_lower`** ```math -s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +S_{k} \ge \underline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} ``` -**`Line_ext_s_lower`** +**`Line_ext_s_nom_upper`** ```math -s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} +S_{k} \le \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \text{ is defined} ``` **`Line_ext_s_upper`** @@ -544,63 +544,63 @@ s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \q s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_ext_s_nom_lower`** +**`Line_fix_s_lower`** ```math -S_{k} \ge \underline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} +s_{k,\xi,t} - \ell_{k,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_ext_s_nom_upper`** +**`Line_fix_s_upper`** ```math -S_{k} \le \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \overline{\mathrm{s}}^{\mathrm{nom}}_{k,\xi} \text{ is defined} +s_{k,\xi,t} + \ell_{k,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_s_nom_set`** +**`Line_loss_tangents_forward`** ```math -S_{k} = \mathrm{s}^{\mathrm{nom,set}}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \mathrm{s}^{\mathrm{nom,set}}_{k} \text{ is defined} +\ell_{k,\xi,t} + \mathrm{a}_{k,\xi,e,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,e,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ e \in \mathcal{E},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -**`Line_s_nom_modularity`** +**`Line_loss_tangents_reverse`** ```math -S_{k} = \mathrm{s}^{\mathrm{mod}}_{k} \cdot N^{s}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} +\ell_{k,\xi,t} - \mathrm{a}_{k,\xi,e,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,e,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ e \in \mathcal{E},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -**`Line_s_set`** +**`Line_loss_upper`** ```math -s_{k,\xi,t} = \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \text{ is defined} \wedge \mathrm{on}^{s}_{k,t} +\ell_{k,\xi,t} \le \overline{\ell}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} ``` -**`Line_v_ang_lower`** +**`Line_s_nom_modularity`** ```math -s_{k,\xi,t} \ge \frac{-\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} +S_{k} = \mathrm{s}^{\mathrm{mod}}_{k} \cdot N^{s}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{s}^{\mathrm{mod}}_{k} > 0 \wedge \mathrm{act}^{s}_{k} ``` -**`Line_v_ang_upper`** +**`Line_s_nom_set`** ```math -s_{k,\xi,t} \le \frac{\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} +S_{k} = \mathrm{s}^{\mathrm{nom,set}}_{k} \qquad \forall\, k \in \mathcal{K} \,:\, \mathrm{ext}^{s}_{k} \wedge \mathrm{act}^{s}_{k} \wedge \mathrm{s}^{\mathrm{nom,set}}_{k} \text{ is defined} ``` -**`Line_loss_upper`** +**`Line_s_set`** ```math -\ell_{k,\xi,t} \le \overline{\ell}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +s_{k,\xi,t} = \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{s}^{\mathrm{set}}_{k,\xi,t} \text{ is defined} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_loss_tangents_forward`** +**`Line_v_ang_lower`** ```math -\ell_{k,\xi,t} + \mathrm{a}_{k,\xi,e,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,e,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ e \in \mathcal{E},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +s_{k,\xi,t} \ge \frac{-\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} ``` -**`Line_loss_tangents_reverse`** +**`Line_v_ang_upper`** ```math -\ell_{k,\xi,t} - \mathrm{a}_{k,\xi,e,t} \cdot s_{k,\xi,t} \ge \mathrm{b}_{k,\xi,e,t} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ e \in \mathcal{E},\ t \in \mathcal{T} \,:\, \mathrm{on}^{s,\mathrm{lossy}}_{k,t} +s_{k,\xi,t} \le \frac{\overline{\delta}_{k,\xi} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff}}_{k,\xi}} \qquad \forall\, k \in \mathcal{K},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \overline{\delta}_{k,\xi} \text{ is defined} \wedge \mathrm{Line\_carrier}(k) = \text{'}\mathrm{AC}\text{'} \wedge \mathrm{on}^{s}_{k,t} ``` diff --git a/docs/examples/pypsa/link.md b/docs/examples/pypsa/link.md index dffb91e2..84d3f746 100644 --- a/docs/examples/pypsa/link.md +++ b/docs/examples/pypsa/link.md @@ -368,64 +368,64 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$, data another file declares | | $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$, data another file declares | -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | -| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu^{f}`$ | `Link_maintenance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`\mu^{f,\mathrm{nom}}`$ | `Link_maintenance_capacity` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Link_transmission_volume_expansion` to | -| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Link_transmission_expansion_cost` to | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Link_tech_capacity_expansion` to | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Link_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Link_additions` to | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Link_opex` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Link_tech_capacity_expansion` to | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Link_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Link_additions` to | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Link_injection` to | +| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Link_transmission_expansion_cost` to | +| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Link_transmission_volume_expansion` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L}`$ — controllable connections, each from one bus to the buses it delivers to | -| $`\mathcal{O}`$ | index $`o`$ — `link_output` with $`\mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L},\ \mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N}`$ — a link's output ports, one label per port a link declares — PyPSA's `bus1`, `bus2`, … columns read long, so a link of any number of output ports is one term in the balance, data prep | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | +| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L}`$ — controllable connections, each from one bus to the buses it delivers to | +| $`\mathcal{O}`$ | index $`o`$ — `link_output` with $`\mathrm{Link\_output\_bus}: \mathcal{O} \to \mathcal{N},\ \mathrm{Link\_output\_link}: \mathcal{O} \to \mathcal{L}`$ — a link's output ports, one label per port a link declares — PyPSA's `bus1`, `bus2`, … columns read long, so a link of any number of output ports is one term in the balance, data prep | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Link\_carrier}: \mathcal{L} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{f}^{\mathrm{nom}}`$ | `Link_p_nom` over $`\mathcal{L} \times \Xi`$ — 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — least flow, per unit of nominal power — negative for a link that carries both ways | -| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — most flow, per unit of nominal power | +| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$ — whether a link stands in a snapshot's period — PyPSA's `active`, data prep | +| $`\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{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\mathcal{L} \times \Xi`$ — 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{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 | | $`\eta`$ | `Link_efficiency` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — share of the flow that arrives at an output port, PyPSA's `efficiency`, `efficiency2`, … read long — negative where that port consumes rather than delivers. Read at the snapshot the flow arrives, so a delayed port delivers at its arrival snapshot's efficiency (`constraints.py:1498`) | -| $`\mathrm{d}^{f}`$ | `Link_output_delay` over $`\mathcal{O}`$ — snapshots a port's delivery lags its link's flow — PyPSA's `delay`, `delay2`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that delivers at once. A port has the same delay in every scenario, because PyPSA refuses a delay that differs by scenario (`constants.py:52`) | -| $`\mathrm{cyc}^{f}`$ | `Link_output_cyclic_delay` over $`\mathcal{O}`$ — whether a delayed port's flow wraps from the end of its investment period — PyPSA's `cyclic_delay`, `cyclic_delay2`, …; where it does not, the flow still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | +| $`\mathrm{cc}^{f}`$ | `Link_expansion_cost_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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{new}^{f}`$ | `Link_first_active` over $`\mathcal{L} \times \mathcal{Y}`$ — one in the first period a link stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | | $`\mathrm{c}^{f}`$ | `Link_marginal_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one unit of flow | | $`\mathrm{c}^{f,(2)}`$ | `Link_marginal_cost_quadratic` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of the square of one unit of flow | -| $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — 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{cyc}^{f}`$ | `Link_output_cyclic_delay` over $`\mathcal{O}`$ — whether a delayed port's flow wraps from the end of its investment period — PyPSA's `cyclic_delay`, `cyclic_delay2`, …; where it does not, the flow still in transit at each period's first snapshots is lost. The flag is the same in every scenario, as the delay is | +| $`\mathrm{d}^{f}`$ | `Link_output_delay` over $`\mathcal{O}`$ — snapshots a port's delivery lags its link's flow — PyPSA's `delay`, `delay2`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that delivers at once. A port has the same delay in every scenario, because PyPSA refuses a delay that differs by scenario (`constants.py:52`) | +| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — most flow, per unit of nominal power | +| $`\underline{\mathrm{f}}`$ | `Link_p_min_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — least flow, per unit of nominal power — negative for a link that carries both ways | | $`\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{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$ — whether a link stands in a snapshot's period — PyPSA's `active`, data prep | -| $`\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{L} \times \mathcal{Y}`$ — 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 $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{L} \times \Xi`$ — least nominal power an extendable link may be built at | +| $`\mathrm{f}^{\mathrm{nom}}`$ | `Link_p_nom` over $`\mathcal{L} \times \Xi`$ — nominal power | +| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$ — whether the nominal power is a decision | | $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\mathcal{L} \times \Xi`$ — most nominal power an extendable link may be built at | -| $`\mathrm{c}^{\mathrm{cap},f}`$ | `Link_capital_cost` over $`\mathcal{L} \times \Xi`$ — 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 | +| $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\mathcal{L} \times \Xi`$ — least nominal power an extendable link may be built at | +| $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\mathrm{f}^{\mathrm{nom,set}}`$ | `Link_p_nom_set` over $`\mathcal{L}`$, `neutral` 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 $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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{f}^{\mathrm{set}}`$ | `Link_p_set` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given flow schedule; a link without one has no row here | | $`\mathrm{m}^{f}`$ | `Link_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{L}`$, `neutral` 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{len}^{f}`$ | `Link_volume_weight` over $`\mathcal{G} \times \mathcal{L} \times \Xi`$, `neutral` 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 | #### Conditions @@ -437,24 +437,24 @@ assumptions: | Symbol | Meaning | |---|---| -| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-p` — PyPSA's `p0`, the flow measured at the `Link_bus0` end: a positive value withdraws there and injects at every bus the link's output ports deliver to | | $`N^{f}`$ | `Link_n_mod` over $`\mathcal{L}`$ — `Link-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-p` — PyPSA's `p0`, the flow measured at the `Link_bus0` end: a positive value withdraws there and injects at every bus the link's output ports deliver to | | $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ — `Link-p_nom` — nominal power where it is a decision, for a link that is active; the parameter of the same PyPSA name carries the fixed regime | #### Definitions | Symbol | Meaning | |---|---| -| $`\widetilde{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_effective` over $`\mathcal{L} \times \Xi`$ — the build a link's limits are taken against — the chosen one where it is extendable, the given one otherwise | -| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$ — the build a committed link's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | -| $`\overrightarrow{f}`$ | `Link_output_arrival` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — what a link delivers to an output port at a snapshot — its flow delayed by the port's `delay` within its investment period, times the port's efficiency at the snapshot the flow arrives; where the port is `cyclic_delay` the delayed flow wraps from the period's end, and where it is not the flow still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) delivers its flow unshifted, cyclic or not | -| $`\mathit{Link\_transmission\_volume\_expansion}`$ | `Link_transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{Link\_transmission\_expansion\_cost}`$ | `Link_transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{Link\_tech\_capacity\_expansion}`$ | `Link_tech_capacity_expansion` over $`\mathcal{G}`$ | -| $`\mathit{Link\_opex}`$ | `Link_opex` over $`\Xi`$ | -| $`\mathit{Link\_capex}`$ | `Link_capex` (scalar) | | $`\mathit{Link\_additions}`$ | `Link_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Link\_capex}`$ | `Link_capex` (scalar) | | $`\mathit{Link\_injection}`$ | `Link_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Link\_opex}`$ | `Link_opex` over $`\Xi`$ | +| $`\overrightarrow{f}`$ | `Link_output_arrival` over $`\mathcal{O} \times \Xi \times \mathcal{T}`$ — what a link delivers to an output port at a snapshot — its flow delayed by the port's `delay` within its investment period, times the port's efficiency at the snapshot the flow arrives; where the port is `cyclic_delay` the delayed flow wraps from the period's end, and where it is not the flow still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) delivers its flow unshifted, cyclic or not | +| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$ — the build a committed link's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | +| $`\widetilde{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_effective` over $`\mathcal{L} \times \Xi`$ — the build a link's limits are taken against — the chosen one where it is extendable, the given one otherwise | +| $`\mathit{Link\_tech\_capacity\_expansion}`$ | `Link_tech_capacity_expansion` over $`\mathcal{G}`$ | +| $`\mathit{Link\_transmission\_expansion\_cost}`$ | `Link_transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$ | +| $`\mathit{Link\_transmission\_volume\_expansion}`$ | `Link_transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$ | #### Notation @@ -474,16 +474,16 @@ assumptions: #### Variable domains -**`Link_p`** +**`Link_n_mod`** ```math -f_{l,\xi,t} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f}_{l,t} +N^{f}_{l} \ge 0, N^{f}_{l} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} ``` -**`Link_n_mod`** +**`Link_p`** ```math -N^{f}_{l} \ge 0, N^{f}_{l} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} +f_{l,\xi,t} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f}_{l,t} ``` **`Link_p_nom_ext`** @@ -494,84 +494,84 @@ F_{l} \in \mathbb{R} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{ #### Definitions -**`Link_p_nom_effective`** +**`Link_additions`** ```math -\widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} F_{l} & \text{if } \mathrm{ext}^{f}_{l} \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\mathit{Link\_additions}_{i,y} = \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_carrier}(l) = i} F_{l} \cdot \mathrm{new}^{f}_{l,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -**`Link_p_nom_committed`** +**`Link_capex`** ```math -\widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} \mathrm{f}^{\mathrm{mod}}_{l} & \text{if } \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\mathit{Link\_capex} = \sum_{l \in \mathcal{L},\ \xi \in \Xi} \pi_{\xi} \cdot F_{l} \cdot \mathrm{c}^{\mathrm{cap},f}_{l,\xi} \cdot \mathrm{W}^{f}_{l} ``` -**`Link_output_arrival`** +**`Link_injection`** ```math -\overrightarrow{f}_{o,\xi,t} = \begin{cases} f_{\mathrm{Link\_output\_link}(o),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{if } \mathrm{cyc}^{f}_{o} \\ f_{\mathrm{Link\_output\_link}(o),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, o \in \mathcal{O},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_injection}_{n,\xi,t} = -\left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_transmission_volume_expansion`** +**`Link_opex`** ```math -\mathit{Link\_transmission\_volume\_expansion}_{g,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{len}^{f}_{g,l,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Link\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot \mathrm{c}^{f}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot f_{l,\xi,t} \cdot \mathrm{c}^{f,(2)}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -**`Link_transmission_expansion_cost`** +**`Link_output_arrival`** ```math -\mathit{Link\_transmission\_expansion\_cost}_{g,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{cc}^{f}_{g,l,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\overrightarrow{f}_{o,\xi,t} = \begin{cases} f_{\mathrm{Link\_output\_link}(o),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{if } \mathrm{cyc}^{f}_{o} \\ f_{\mathrm{Link\_output\_link}(o),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{f}} \cdot \eta_{o,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, o \in \mathcal{O},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_tech_capacity_expansion`** +**`Link_p_nom_committed`** ```math -\mathit{Link\_tech\_capacity\_expansion}_{g} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{m}^{f}_{g,l} \qquad \forall\, g \in \mathcal{G} +\widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} \mathrm{f}^{\mathrm{mod}}_{l} & \text{if } \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -**`Link_opex`** +**`Link_p_nom_effective`** ```math -\mathit{Link\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot \mathrm{c}^{f}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} f_{l,\xi,t} \cdot f_{l,\xi,t} \cdot \mathrm{c}^{f,(2)}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} = \begin{cases} F_{l} & \text{if } \mathrm{ext}^{f}_{l} \\ \mathrm{f}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -**`Link_capex`** +**`Link_tech_capacity_expansion`** ```math -\mathit{Link\_capex} = \sum_{l \in \mathcal{L},\ \xi \in \Xi} \pi_{\xi} \cdot F_{l} \cdot \mathrm{c}^{\mathrm{cap},f}_{l,\xi} \cdot \mathrm{W}^{f}_{l} +\mathit{Link\_tech\_capacity\_expansion}_{g} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{m}^{f}_{g,l} \qquad \forall\, g \in \mathcal{G} ``` -**`Link_additions`** +**`Link_transmission_expansion_cost`** ```math -\mathit{Link\_additions}_{i,y} = \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_carrier}(l) = i} F_{l} \cdot \mathrm{new}^{f}_{l,y} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{Link\_transmission\_expansion\_cost}_{g,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{cc}^{f}_{g,l,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Link_injection`** +**`Link_transmission_volume_expansion`** ```math -\mathit{Link\_injection}_{n,\xi,t} = -\left( \sum_{l \in \mathcal{L} \,:\, \mathrm{Link\_bus0}(l) = n} f_{l,\xi,t} \right) + \sum_{o \in \mathcal{O} \,:\, \mathrm{Link\_output\_bus}(o) = n} \overrightarrow{f}_{o,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_transmission\_volume\_expansion}_{g,\xi} = \sum_{l \in \mathcal{L}} F_{l} \cdot \mathrm{len}^{f}_{g,l,\xi} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` #### Subject to -**`Link_fix_p_lower`** +**`Link_ext_p_lower`** ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_fix_p_upper`** +**`Link_ext_p_nom_lower`** ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +F_{l} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} ``` -**`Link_ext_p_lower`** +**`Link_ext_p_nom_upper`** ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +F_{l} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \text{ is defined} ``` **`Link_ext_p_upper`** @@ -580,28 +580,28 @@ f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f} f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_ext_p_nom_lower`** +**`Link_fix_p_lower`** ```math -F_{l} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_ext_p_nom_upper`** +**`Link_fix_p_upper`** ```math -F_{l} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \text{ is defined} +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \gamma^{f}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{f}_{l} \wedge \neg \mathrm{com}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_p_nom_set`** +**`Link_p_nom_modularity`** ```math -F_{l} = \mathrm{f}^{\mathrm{nom,set}}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \mathrm{f}^{\mathrm{nom,set}}_{l} \text{ is defined} +F_{l} = \mathrm{f}^{\mathrm{mod}}_{l} \cdot N^{f}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} ``` -**`Link_p_nom_modularity`** +**`Link_p_nom_set`** ```math -F_{l} = \mathrm{f}^{\mathrm{mod}}_{l} \cdot N^{f}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \wedge \mathrm{act}^{f}_{l} +F_{l} = \mathrm{f}^{\mathrm{nom,set}}_{l} \qquad \forall\, l \in \mathcal{L} \,:\, \mathrm{ext}^{f}_{l} \wedge \mathrm{act}^{f}_{l} \wedge \mathrm{f}^{\mathrm{nom,set}}_{l} \text{ is defined} ``` **`Link_p_set`** @@ -612,15 +612,15 @@ f_{l,\xi,t} = \mathrm{f}^{\mathrm{set}}_{l,\xi,t} \qquad \forall\, l \in \mathca #### Assumptions -**`Link_output_delay_under_uniform_weighting`** +**`Link_marginal_cost_quadratic_without_risk_preference`** ```math -\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, o \in \mathcal{O},\ t \in \mathcal{T} \,:\, \mathrm{d}^{f}_{o} > 0 +\mathrm{c}^{f,(2)}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} ``` -**`Link_marginal_cost_quadratic_without_risk_preference`** +**`Link_output_delay_under_uniform_weighting`** ```math -\mathrm{c}^{f,(2)}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, o \in \mathcal{O},\ t \in \mathcal{T} \,:\, \mathrm{d}^{f}_{o} > 0 ``` diff --git a/docs/examples/pypsa/link_commitment.md b/docs/examples/pypsa/link_commitment.md index 57b8e0c7..77a68c7e 100644 --- a/docs/examples/pypsa/link_commitment.md +++ b/docs/examples/pypsa/link_commitment.md @@ -308,21 +308,21 @@ constraints: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | +| $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$, data another file declares | +| $`\mathrm{N}^{f,\mathrm{fix}}`$ | `Link_modules_installed` over $`\mathcal{L} \times \Xi`$, data another file declares | +| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\underline{\mathrm{f}}`$ | `Link_p_min_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\mathrm{nonneg}^{f}`$ | `Link_p_min_pu_nonneg` over $`\mathcal{L}`$, data another file declares | | $`\mathrm{f}^{\mathrm{nom}}`$ | `Link_p_nom` over $`\mathcal{L} \times \Xi`$, data another file declares | | $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$, data another file declares | -| $`\underline{\mathrm{f}}`$ | `Link_p_min_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, data another file declares | -| $`\overline{\mathrm{f}}`$ | `Link_p_max_pu` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, data another file declares | -| $`\mathrm{N}^{f,\mathrm{fix}}`$ | `Link_modules_installed` over $`\mathcal{L} \times \Xi`$, data another file declares | -| $`\mathrm{nonneg}^{f}`$ | `Link_p_min_pu_nonneg` over $`\mathcal{L}`$, data another file declares | -| $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$, data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | -| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | -| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | -| $`N^{f}`$ | `Link_n_mod` over $`\mathcal{L}`$ | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu^{f,\mathrm{nom}}`$ | `Link_maintenance_capacity` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`\mu^{f,u}`$ | `Link_maintenance_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | +| $`N^{f}`$ | `Link_n_mod` over $`\mathcal{L}`$ | +| $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Link_commitment_opex` to | | $`\mathrm{on}^{f,\mathrm{com}}`$ | `Link_committed` over $`\mathcal{L} \times \mathcal{T}`$, a condition another file defines | @@ -331,25 +331,25 @@ constraints: | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{L}`$ | index $`l`$ — `link` — controllable connections, each from one bus to the buses it delivers to | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| +| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\mathcal{L} \times \Xi`$, `neutral` 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{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$ — whether flow is gated by an on/off status decision | -| $`\mathrm{UT}^{f}`$ | `Link_min_up_time` over $`\mathcal{L} \times \Xi`$ — least snapshots a link stays on once started | | $`\mathrm{DT}^{f}`$ | `Link_min_down_time` over $`\mathcal{L} \times \Xi`$ — least snapshots a link stays off once stopped | -| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$ — one where the link was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{hold}^{f}`$ | `Link_must_stay_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the up time a link brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{UT}^{f}`$ | `Link_min_up_time` over $`\mathcal{L} \times \Xi`$ — least snapshots a link stays on once started | | $`\mathrm{rest}^{f}`$ | `Link_must_stay_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the down time a link brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{f,\mathrm{up}}`$ | `Link_start_up_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{hold}^{f}`$ | `Link_must_stay_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true while the up time a link brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | | $`\mathrm{c}^{f,\mathrm{dn}}`$ | `Link_shut_down_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{f,\mathrm{on}}`$ | `Link_stand_by_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\mathcal{L} \times \Xi`$, `neutral` 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{c}^{f,\mathrm{up}}`$ | `Link_start_up_cost` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$ — one where the link was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | #### Conditions @@ -361,17 +361,17 @@ constraints: | Symbol | Meaning | |---|---| -| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-status` — how much of a committable link is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-start_up` — how much of a committable link turns on this snapshot, capped as the status is | | $`\mathit{dn}^{f}`$ | `Link_shut_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-shut_down` — how much of a committable link turns off this snapshot, capped as the status is | +| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-start_up` — how much of a committable link turns on this snapshot, capped as the status is | +| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — `Link-status` — how much of a committable link is on: an integer the rows below cap at one, or at the module count where the build is modular | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{Link\_commitment\_opex}`$ | `Link_commitment_opex` over $`\Xi`$ | | $`\overleftarrow{u}^{f}`$ | `Link_previous_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the commitment state a link carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | | $`\overleftarrow{u}^{\circ f}`$ | `Link_status_carried_over` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the state a link carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | -| $`\mathit{Link\_commitment\_opex}`$ | `Link_commitment_opex` over $`\Xi`$ | #### Notation @@ -389,10 +389,10 @@ constraints: #### Variable domains -**`Link_status`** +**`Link_shut_down`** ```math -u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +\mathit{dn}^{f}_{l,\xi,t} \ge 0, \mathit{dn}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` **`Link_start_up`** @@ -401,151 +401,151 @@ u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \ma \mathit{up}^{f}_{l,\xi,t} \ge 0, \mathit{up}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Link_shut_down`** +**`Link_status`** ```math -\mathit{dn}^{f}_{l,\xi,t} \ge 0, \mathit{dn}^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +u^{f}_{l,\xi,t} \ge 0, u^{f}_{l,\xi,t} \in \mathbb{Z} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` #### Definitions -**`Link_previous_status`** +**`Link_commitment_opex`** ```math -\overleftarrow{u}^{f}_{l,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{f}_{l,t - 1} \\ \overleftarrow{u}^{\circ f}_{l,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Link\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} u^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{on}}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{up}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{up}}_{l,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{dn}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{dn}}_{l,\xi,t} \qquad \forall\, \xi \in \Xi ``` -**`Link_status_carried_over`** +**`Link_previous_status`** ```math -\overleftarrow{u}^{\circ f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{f}_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{u}^{f}_{l,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{f}_{l,t - 1} \\ \overleftarrow{u}^{\circ f}_{l,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_commitment_opex`** +**`Link_status_carried_over`** ```math -\mathit{Link\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} u^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{on}}_{l,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{up}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{up}}_{l,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{l \in \mathcal{L}} \mathit{dn}^{f}_{l,\xi,t} \cdot \mathrm{c}^{f,\mathrm{dn}}_{l,\xi,t} \qquad \forall\, \xi \in \Xi +\overleftarrow{u}^{\circ f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{f}_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` #### Subject to -**`Link_com_p_lower`** +**`Link_com_down_time`** ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{f}} \mathit{dn}^{f}_{l,\xi,t'} \le 1 - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{DT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Link_com_p_upper`** +**`Link_com_ext_p_lower`** ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) + \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} - \mathrm{M}^{f}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -**`Link_com_transition_start_up`** +**`Link_com_ext_p_lower_nonneg`** ```math -\mathit{up}^{f}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +f_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \mathrm{nonneg}^{f}_{l} ``` -**`Link_com_transition_shut_down`** +**`Link_com_ext_p_upper_big_m`** ```math -\mathit{dn}^{f}_{l,\xi,t} \ge \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} +f_{l,\xi,t} \le \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -**`Link_com_up_time`** +**`Link_com_ext_p_upper_cap`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{f}} \mathit{up}^{f}_{l,\xi,t'} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{UT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} ``` -**`Link_com_down_time`** +**`Link_com_mod_p_lower`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{f}} \mathit{dn}^{f}_{l,\xi,t'} \le 1 - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{DT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_com_status_must_stay_up`** +**`Link_com_mod_p_upper`** ```math -u^{f}_{l,\xi,t} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{hold}^{f}_{l,\xi,t} +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_com_status_must_stay_down`** +**`Link_com_p_lower`** ```math -u^{f}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{rest}^{f}_{l,\xi,t} +f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_com_ext_p_upper_cap`** +**`Link_com_p_upper`** ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_com_ext_p_upper_big_m`** +**`Link_com_status_must_stay_down`** ```math -f_{l,\xi,t} \le \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +u^{f}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{rest}^{f}_{l,\xi,t} ``` -**`Link_com_ext_p_lower`** +**`Link_com_status_must_stay_up`** ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \left( F_{l} - \gamma^{f}_{l,\xi} \cdot \mu^{f,\mathrm{nom}}_{l,\xi,t} \right) + \mathrm{M}^{f}_{l,\xi} \cdot u^{f}_{l,\xi,t} - \mathrm{M}^{f}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} +u^{f}_{l,\xi,t} = 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{hold}^{f}_{l,\xi,t} ``` -**`Link_com_ext_p_lower_nonneg`** +**`Link_com_transition_shut_down`** ```math -f_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \mathrm{nonneg}^{f}_{l} +\mathit{dn}^{f}_{l,\xi,t} \ge \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Link_com_mod_p_lower`** +**`Link_com_transition_start_up`** ```math -f_{l,\xi,t} \ge \underline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mathit{up}^{f}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} ``` -**`Link_com_mod_p_upper`** +**`Link_com_up_time`** ```math -f_{l,\xi,t} \le \overline{\mathrm{f}}_{l,\xi,t} \cdot \mathrm{f}^{\mathrm{mod}}_{l} \cdot \left( u^{f}_{l,\xi,t} - \gamma^{f}_{l,\xi} \cdot \mu^{f,u}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{f}} \mathit{up}^{f}_{l,\xi,t'} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{UT}^{f}_{l,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Link_status_p_fixed_upper`** +**`Link_shut_down_p_fixed_upper`** ```math -u^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mathit{dn}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_start_up_p_fixed_upper`** +**`Link_shut_down_p_nom_variable_upper`** ```math -\mathit{up}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mathit{dn}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_shut_down_p_fixed_upper`** +**`Link_start_up_p_fixed_upper`** ```math -\mathit{dn}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mathit{up}^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_status_p_nom_variable_upper`** +**`Link_start_up_p_nom_variable_upper`** ```math -u^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mathit{up}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_start_up_p_nom_variable_upper`** +**`Link_status_p_fixed_upper`** ```math -\mathit{up}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +u^{f}_{l,\xi,t} \le \mathrm{N}^{f,\mathrm{fix}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \left( \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_shut_down_p_nom_variable_upper`** +**`Link_status_p_nom_variable_upper`** ```math -\mathit{dn}^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +u^{f}_{l,\xi,t} \le N^{f}_{l} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{ext}^{f}_{l} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` diff --git a/docs/examples/pypsa/link_maintenance.md b/docs/examples/pypsa/link_maintenance.md index c3a50665..18b897bb 100644 --- a/docs/examples/pypsa/link_maintenance.md +++ b/docs/examples/pypsa/link_maintenance.md @@ -248,33 +248,33 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$, data another file declares | +| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | | $`\mathrm{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$, data another file declares | +| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$, data another file declares | +| $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\mathcal{L} \times \Xi`$, data another file declares | +| $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\mathcal{L} \times \Xi`$, data another file declares | | $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, data another file declares | -| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | -| $`\underline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_min` over $`\mathcal{L} \times \Xi`$, data another file declares | -| $`\overline{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_max` over $`\mathcal{L} \times \Xi`$, data another file declares | -| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ | +| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`\mathrm{on}^{f,\mathrm{com}}`$ | `Link_committed` over $`\mathcal{L} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| +| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `Link_maintenance_cover` is `absent` where the data has no row — controllable connections, each from one bus to the buses it delivers to | | $`\Xi`$ | index $`\xi`$ — `scenario` with $`\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `Link_maintenance_cover` is `absent` where the data has no row — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `Link_maintenance_cover` is `absent` where the data has no row — dispatch periods | -| $`\mathcal{L}`$ | index $`l`$ — `link` with $`\mathrm{Link\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{L} \times \Xi \times \mathcal{T}`$, `Link_maintenance_cover` is `absent` where the data has no row — controllable connections, each from one bus to the buses it delivers to | #### Parameters | Symbol | Meaning | |---|---| | $`\mathrm{mnt}^{f}`$ | `Link_maintainable` over $`\mathcal{L}`$ — whether a link must be taken off for maintenance within the horizon — in any scenario, as PyPSA takes the union over them (`components.py:1016-1019`) | -| $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\mathcal{L} \times \Xi`$ — how many maintenance events the horizon holds | | $`\tau^{f,\mathrm{mnt}}`$ | `Link_maintenance_duration` over $`\mathcal{L} \times \Xi`$, `neutral` 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{n}^{f,\mathrm{mnt}}`$ | `Link_maintenance_events` over $`\mathcal{L} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma^{f}`$ | `Link_maintenance_pu` over $`\mathcal{L} \times \Xi`$ — the share of the build a maintenance event takes off | | $`\mathrm{blk}^{f}`$ | `Link_maintenance_start_blocked` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — true where no maintenance event may start, 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 | #### Conditions @@ -288,8 +288,8 @@ assumptions: | Symbol | Meaning | |---|---| | $`\mu^{f}`$ | `Link_maintenance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance` — whether a maintainable link is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{f,\mathrm{up}}`$ | `Link_maintenance_start` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{f,\mathrm{nom}}`$ | `Link_maintenance_capacity` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{f,\mathrm{up}}`$ | `Link_maintenance_start` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{f,u}`$ | `Link_maintenance_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Link-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | #### Conditions @@ -308,16 +308,16 @@ assumptions: 0 \le \mu^{f}_{l,\xi,t} \le 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_maintenance_start`** +**`Link_maintenance_capacity`** ```math -\mu^{f,\mathrm{up}}_{l,\xi,t} \in \{0, 1\} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -**`Link_maintenance_capacity`** +**`Link_maintenance_start`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +\mu^{f,\mathrm{up}}_{l,\xi,t} \in \{0, 1\} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` **`Link_maintenance_status`** @@ -334,40 +334,40 @@ assumptions: \sum_{t \in \mathcal{T}} \mu^{f,\mathrm{up}}_{l,\xi,t} = \mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` -**`Link_maint_window`** +**`Link_maint_modstatus_lb`** ```math -\mu^{f}_{l,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ l,\ \xi,\ t' \right) \in \mathrm{Link\_maintenance\_cover}} \mu^{f,\mathrm{up}}_{l,\xi,t'} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} +\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_maint_start_horizon`** +**`Link_maint_modstatus_le_maint`** ```math -\mu^{f,\mathrm{up}}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \wedge \mathrm{blk}^{f}_{l,\xi,t} +\mu^{f,u}_{l,\xi,t} \le \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_maintcap_upper`** +**`Link_maint_modstatus_le_status`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \le F_{l} - \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 ``` -**`Link_maintcap_upper_nommax`** +**`Link_maint_start_horizon`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +\mu^{f,\mathrm{up}}_{l,\xi,t} = 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} \wedge \mathrm{blk}^{f}_{l,\xi,t} ``` -**`Link_maintcap_lower_nommax`** +**`Link_maint_status_lb`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge F_{l} - \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} +\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} + \mu^{f}_{l,\xi,t} - 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_maintcap_lower_nommin`** +**`Link_maint_status_le_maint`** ```math -\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} \wedge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} > 0 +\mu^{f,u}_{l,\xi,t} \le \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` **`Link_maint_status_le_status`** @@ -376,54 +376,54 @@ assumptions: \mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) ``` -**`Link_maint_status_le_maint`** +**`Link_maint_window`** ```math -\mu^{f,u}_{l,\xi,t} \le \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mu^{f}_{l,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ l,\ \xi,\ t' \right) \in \mathrm{Link\_maintenance\_cover}} \mu^{f,\mathrm{up}}_{l,\xi,t'} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_maint_status_lb`** +**`Link_maintcap_lower_nommax`** ```math -\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} + \mu^{f}_{l,\xi,t} - 1 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \neg \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge F_{l} - \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -**`Link_maint_modstatus_le_status`** +**`Link_maintcap_lower_nommin`** ```math -\mu^{f,u}_{l,\xi,t} \le u^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mu^{f,\mathrm{nom}}_{l,\xi,t} \ge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} \wedge \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} > 0 ``` -**`Link_maint_modstatus_le_maint`** +**`Link_maintcap_upper`** ```math -\mu^{f,u}_{l,\xi,t} \le \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mu^{f,\mathrm{nom}}_{l,\xi,t} \le F_{l} - \underline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` -**`Link_maint_modstatus_lb`** +**`Link_maintcap_upper_nommax`** ```math -\mu^{f,u}_{l,\xi,t} \ge u^{f}_{l,\xi,t} - \frac{\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi}}{\mathrm{f}^{\mathrm{mod}}_{l}} \cdot \left( 1 - \mu^{f}_{l,\xi,t} \right) \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{on}^{f,\mathrm{com}}_{l,t} \wedge \mathrm{f}^{\mathrm{mod}}_{l} > 0 +\mu^{f,\mathrm{nom}}_{l,\xi,t} \le \overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \mu^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{mnt,ext}}_{l,t} ``` #### Assumptions -**`Link_maintenance_events_positive`** +**`Link_maintenance_build_cap_is_finite`** ```math -\mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} < \infty \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} ``` -**`Link_maintenance_duration_positive`** +**`Link_maintenance_duration_fits_the_horizon`** ```math -\tau^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\tau^{f,\mathrm{mnt}}_{l,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` -**`Link_maintenance_duration_fits_the_horizon`** +**`Link_maintenance_duration_positive`** ```math -\tau^{f,\mathrm{mnt}}_{l,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} +\tau^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` **`Link_maintenance_events_fit_the_horizon`** @@ -432,10 +432,10 @@ assumptions: \tau^{f,\mathrm{mnt}}_{l,\xi} \cdot \mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` -**`Link_maintenance_build_cap_is_finite`** +**`Link_maintenance_events_positive`** ```math -\overline{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} < \infty \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} +\mathrm{n}^{f,\mathrm{mnt}}_{l,\xi} > 0 \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi \,:\, \mathrm{mnt}^{f}_{l} ``` **`Link_maintenance_module_count_is_finite`** diff --git a/docs/examples/pypsa/link_ramping.md b/docs/examples/pypsa/link_ramping.md index 301280f5..49147172 100644 --- a/docs/examples/pypsa/link_ramping.md +++ b/docs/examples/pypsa/link_ramping.md @@ -253,40 +253,40 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$, data another file declares | +| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\mathcal{L} \times \Xi`$, data another file declares | | $`\mathrm{com}^{f}`$ | `Link_committable` over $`\mathcal{L}`$, data another file declares | -| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$, data another file declares | +| $`\mathrm{ext}^{f}`$ | `Link_p_nom_extendable` over $`\mathcal{L}`$, data another file declares | | $`\mathrm{f}^{\mathrm{mod}}`$ | `Link_p_nom_mod` over $`\mathcal{L}`$, data another file declares | -| $`\mathrm{M}^{f}`$ | `Link_big_m` over $`\mathcal{L} \times \Xi`$, data another file declares | -| $`\mathrm{on}^{f}`$ | `Link_active` over $`\mathcal{L} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{u}^{f,0}`$ | `Link_status_initial` over $`\mathcal{L} \times \Xi`$, data another file declares | | $`f`$ | `Link_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | -| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{dn}^{f}`$ | `Link_shut_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | | $`F`$ | `Link_p_nom_ext` over $`\mathcal{L}`$ | +| $`\mathit{dn}^{f}`$ | `Link_shut_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{up}^{f}`$ | `Link_start_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | +| $`u^{f}`$ | `Link_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ | +| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$, an expression another file defines | | $`\widetilde{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_effective` over $`\mathcal{L} \times \Xi`$, an expression another file defines | | $`\overleftarrow{u}^{f}`$ | `Link_previous_status` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, an expression another file defines | -| $`\widehat{\mathrm{f}}^{\mathrm{nom}}`$ | `Link_p_nom_committed` over $`\mathcal{L} \times \Xi`$, an expression another file defines | | $`\mathrm{on}^{f,\mathrm{com,ext}}`$ | `Link_com_ext` over $`\mathcal{L} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{L}`$ | index $`l`$ — `link` — controllable connections, each from one bus to the buses it delivers to | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{ru}^{f}`$ | `Link_ramp_limit_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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{f}^{0}`$ | `Link_p_init` over $`\mathcal{L} \times \Xi`$, `neutral` 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 | | $`\mathrm{rd}^{f}`$ | `Link_ramp_limit_down` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 $`\mathcal{L} \times \Xi`$, `neutral` 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 | +| $`\mathrm{ru}^{f,\mathrm{up}}`$ | `Link_ramp_limit_start_up` over $`\mathcal{L} \times \Xi`$, `neutral` 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{ru}^{f}`$ | `Link_ramp_limit_up` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$, `neutral` 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 | #### Conditions @@ -299,12 +299,12 @@ assumptions: | Symbol | Meaning | |---|---| | $`\overleftarrow{f}`$ | `Link_previous_p` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the flow a link carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | -| $`\widetilde{\mathrm{ru}}^{f}`$ | `Link_ramp_up_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\Delta^{f,-}`$ | `Link_ramp_down_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may lower flow between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}^{f}`$ | `Link_ramp_down_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{f,\mathrm{up}}`$ | `Link_start_up_rate` over $`\mathcal{L} \times \Xi`$ — the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}`$ | `Link_shut_down_rate` over $`\mathcal{L} \times \Xi`$ — the shut-down ramp a link's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | | $`\Delta^{f,+}`$ | `Link_ramp_up_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may raise flow between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{f,-}`$ | `Link_ramp_down_allowance` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — how far a link may lower flow between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}^{f}`$ | `Link_ramp_up_rate` over $`\mathcal{L} \times \Xi \times \mathcal{T}`$ — the ramp limit a link's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}`$ | `Link_shut_down_rate` over $`\mathcal{L} \times \Xi`$ — the shut-down ramp a link's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{f,\mathrm{up}}`$ | `Link_start_up_rate` over $`\mathcal{L} \times \Xi`$ — the start-up ramp a link's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | #### Notation @@ -329,10 +329,10 @@ assumptions: \overleftarrow{f}_{l,\xi,t} = \begin{cases} \mathrm{u}^{f,0}_{l,\xi} \cdot \mathrm{f}^{0}_{l,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ f_{l,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_ramp_up_rate`** +**`Link_ramp_down_allowance`** ```math -\widetilde{\mathrm{ru}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{ru}^{f}_{l,\xi,t} & \text{if } \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\Delta^{f,-}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot u^{f}_{l,\xi,t} + \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Link_ramp_down_rate`** @@ -341,42 +341,36 @@ assumptions: \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{rd}^{f}_{l,\xi,t} & \text{if } \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_start_up_rate`** +**`Link_ramp_up_allowance`** ```math -\widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} = \begin{cases} \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} & \text{if } \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\Delta^{f,+}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} + \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_shut_down_rate`** +**`Link_ramp_up_rate`** ```math -\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} = \begin{cases} \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} & \text{if } \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi +\widetilde{\mathrm{ru}}^{f}_{l,\xi,t} = \begin{cases} \mathrm{ru}^{f}_{l,\xi,t} & \text{if } \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Link_ramp_up_allowance`** +**`Link_shut_down_rate`** ```math -\Delta^{f,+}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} + \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( u^{f}_{l,\xi,t} - \overleftarrow{u}^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} = \begin{cases} \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} & \text{if } \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` -**`Link_ramp_down_allowance`** +**`Link_start_up_rate`** ```math -\Delta^{f,-}_{l,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot u^{f}_{l,\xi,t} + \widetilde{\mathrm{rd}}^{f,\mathrm{dn}}_{l,\xi} \cdot \widehat{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} \cdot \left( \overleftarrow{u}^{f}_{l,\xi,t} - u^{f}_{l,\xi,t} \right) & \text{if } \mathrm{com}^{f}_{l} \\ \widetilde{\mathrm{rd}}^{f}_{l,\xi,t} \cdot \widetilde{\mathrm{f}}^{\mathrm{nom}}_{l,\xi} & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} = \begin{cases} \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} & \text{if } \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi ``` #### Subject to -**`Link_p_ramp_limit_up_run_big_m`** - -```math -f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} -``` - -**`Link_p_ramp_limit_up_start_big_m`** +**`Link_p_ramp_limit_down`** ```math -f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{up}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \Delta^{f,-}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} ``` **`Link_p_ramp_limit_down_run_big_m`** @@ -397,10 +391,16 @@ f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f,\mathrm f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \Delta^{f,+}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} ``` -**`Link_p_ramp_limit_down`** +**`Link_p_ramp_limit_up_run_big_m`** ```math -\overleftarrow{f}_{l,\xi,t} - f_{l,\xi,t} \le \Delta^{f,-}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{rd}^{f,\mathrm{dn}}_{l,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{f}_{l} \wedge \mathrm{ext}^{f}_{l} \wedge \neg \left( \mathrm{f}^{\mathrm{mod}}_{l} > 0 \right) \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} \wedge \mathrm{on}^{f}_{l,t} +f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f}_{l,\xi,t} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \overleftarrow{u}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} +``` + +**`Link_p_ramp_limit_up_start_big_m`** + +```math +f_{l,\xi,t} - \overleftarrow{f}_{l,\xi,t} \le \widetilde{\mathrm{ru}}^{f,\mathrm{up}}_{l,\xi} \cdot F_{l} + \mathrm{M}^{f}_{l,\xi} - \mathrm{M}^{f}_{l,\xi} \cdot \mathit{up}^{f}_{l,\xi,t} \qquad \forall\, l \in \mathcal{L},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{f,\mathrm{com,ext}}_{l,t} \wedge \left( \mathrm{ru}^{f}_{l,\xi,t} \text{ is defined} \vee \mathrm{ru}^{f,\mathrm{up}}_{l,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{f}_{l,\xi,t} ``` #### Assumptions diff --git a/docs/examples/pypsa/load.md b/docs/examples/pypsa/load.md index e2ae730c..90d514d7 100644 --- a/docs/examples/pypsa/load.md +++ b/docs/examples/pypsa/load.md @@ -74,18 +74,18 @@ expressions: | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N}`$ — network nodes | | $`\mathcal{D}`$ | index $`d`$ — `load` with $`\mathrm{Load\_bus}: \mathcal{D} \to \mathcal{N}`$ — demands, each on one bus | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| +| $`\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`) | | $`\mathrm{load}`$ | `Load_p_set` over $`\mathcal{D} \times \Xi \times \mathcal{T}`$ — 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`) | #### Definitions diff --git a/docs/examples/pypsa/network.md b/docs/examples/pypsa/network.md index d3d1715a..62c1e544 100644 --- a/docs/examples/pypsa/network.md +++ b/docs/examples/pypsa/network.md @@ -55,9 +55,9 @@ constraints: | Symbol | Meaning | |---|---| +| $`\mathcal{N}`$ | index $`n`$ — `bus` — network nodes | | $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | -| $`\mathcal{N}`$ | index $`n`$ — `bus` — network nodes | #### Subject to diff --git a/docs/examples/pypsa/power_flow.md b/docs/examples/pypsa/power_flow.md index f9ff2e55..56eefd98 100644 --- a/docs/examples/pypsa/power_flow.md +++ b/docs/examples/pypsa/power_flow.md @@ -57,9 +57,9 @@ constraints: | Symbol | Meaning | |---|---| +| $`\mathcal{C}`$ | index $`c`$ — `cycle` — independent cycles of the passive network graph — the cycle basis, data prep. Each period has its own basis, of the branches that stand in it; a label is a position in that period's basis, so one label names a different cycle in another period | | $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | -| $`\mathcal{C}`$ | index $`c`$ — `cycle` — independent cycles of the passive network graph — the cycle basis, data prep. Each period has its own basis, of the branches that stand in it; a label is a position in that period's basis, so one label names a different cycle in another period | #### Subject to diff --git a/docs/examples/pypsa/process.md b/docs/examples/pypsa/process.md index 50a7df88..fc46fbcc 100644 --- a/docs/examples/pypsa/process.md +++ b/docs/examples/pypsa/process.md @@ -334,59 +334,59 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$, data another file declares | | $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\mathcal{J} \times \Xi`$, data another file declares | -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | -| $`\omega`$ | `CVaR_omega` (scalar), data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu^{z}`$ | `Process_maintenance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`\mu^{z,\mathrm{nom}}`$ | `Process_maintenance_capacity` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Process_tech_capacity_expansion` to | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Process_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Process_additions` to | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Process_opex` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Process_tech_capacity_expansion` to | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Process_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Process_additions` to | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Process_injection` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J}`$ — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | -| $`\mathcal{R}`$ | index $`r`$ — `process_output` with $`\mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J},\ \mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N}`$ — a process's ports, one label per port a process declares — PyPSA's `bus0`, `bus1`, … each carry a signed `rate`, so a process of any number of ports is one term in the balance, data prep | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_carrier}: \mathcal{J} \to \mathcal{I},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J}`$ — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | +| $`\mathcal{R}`$ | index $`r`$ — `process_output` with $`\mathrm{Process\_output\_bus}: \mathcal{R} \to \mathcal{N},\ \mathrm{Process\_output\_process}: \mathcal{R} \to \mathcal{J}`$ — a process's ports, one label per port a process declares — PyPSA's `bus0`, `bus1`, … each carry a signed `rate`, so a process of any number of ports is one term in the balance, data prep | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{z}^{\mathrm{nom}}`$ | `Process_p_nom` over $`\mathcal{J} \times \Xi`$ — nominal internal power | -| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$ — whether the nominal internal power is a decision | -| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — least internal power, per unit of nominal power — negative for a process that runs both ways | -| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — most internal power, per unit of nominal power | -| $`\alpha`$ | `Process_rate` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — the energy a port draws or delivers per unit of internal power, PyPSA's `rate0`, `rate1`, … read long — negative where the port withdraws, positive where it injects; a link is a process whose `bus0` rate is minus one and whose output rates are its efficiencies. Read at the snapshot the transfer arrives, so a delayed port transfers at its arrival snapshot's rate (`constraints.py:1498`) | -| $`\mathrm{d}^{z}`$ | `Process_output_delay` over $`\mathcal{R}`$ — snapshots a port's transfer lags its process's internal power — PyPSA's `delay0`, `delay1`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that transfers at once. A port has the same delay in every scenario, as a link's port has | -| $`\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 $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one unit of internal power | -| $`\mathrm{c}^{z,(2)}`$ | `Process_marginal_cost_quadratic` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of the square of one unit of internal power | -| $`\mathrm{z}^{\mathrm{set}}`$ | `Process_p_set` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — least nominal power an extendable process may be built at | -| $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\mathcal{J} \times \Xi`$ — most nominal power an extendable process may be built at | -| $`\mathrm{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\mathcal{J} \times \Xi`$ — 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}`$, `neutral` 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}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$ — 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 | | $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$ — whether a process stands in a snapshot's period — PyPSA's `active`, data prep | | $`\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{c}^{\mathrm{cap},z}`$ | `Process_capital_cost` over $`\mathcal{J} \times \Xi`$ — 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{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{c}^{z}`$ | `Process_marginal_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one unit of internal power | +| $`\mathrm{c}^{z,(2)}`$ | `Process_marginal_cost_quadratic` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of the square of one unit of internal power | +| $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\mathcal{J} \times \Xi`$ — 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{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{d}^{z}`$ | `Process_output_delay` over $`\mathcal{R}`$ — snapshots a port's transfer lags its process's internal power — PyPSA's `delay0`, `delay1`, … read long, divided by the `snapshot_weightings.generators` value and rounded up in data prep; zero for a port that transfers at once. A port has the same delay in every scenario, as a link's port has | +| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — most internal power, per unit of nominal power | +| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — least internal power, per unit of nominal power — negative for a process that runs both ways | +| $`\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{z}^{\mathrm{nom}}`$ | `Process_p_nom` over $`\mathcal{J} \times \Xi`$ — nominal internal power | +| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$ — whether the nominal internal power is a decision | +| $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\mathcal{J} \times \Xi`$ — most nominal power an extendable process may be built at | +| $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\mathcal{J} \times \Xi`$ — least nominal power an extendable process may be built at | +| $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{z}^{\mathrm{nom,set}}`$ | `Process_p_nom_set` over $`\mathcal{J}`$, `neutral` 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{set}}`$ | `Process_p_set` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the data has no row — a given internal power schedule; a process without one has no row here | +| $`\alpha`$ | `Process_rate` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — the energy a port draws or delivers per unit of internal power, PyPSA's `rate0`, `rate1`, … read long — negative where the port withdraws, positive where it injects; a link is a process whose `bus0` rate is minus one and whose output rates are its efficiencies. Read at the snapshot the transfer arrives, so a delayed port transfers at its arrival snapshot's rate (`constraints.py:1498`) | | $`\mathrm{m}^{z}`$ | `Process_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{J}`$, `neutral` 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 | #### Conditions @@ -399,22 +399,22 @@ assumptions: | Symbol | Meaning | |---|---| -| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-p` — PyPSA's internal power `p`: a positive value drives every port at its own rate, withdrawing where the rate is negative and injecting where it is positive | | $`N^{z}`$ | `Process_n_mod` over $`\mathcal{J}`$ — `Process-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-p` — PyPSA's internal power `p`: a positive value drives every port at its own rate, withdrawing where the rate is negative and injecting where it is positive | | $`Z`$ | `Process_p_nom_ext` over $`\mathcal{J}`$ — `Process-p_nom` — nominal internal power where it is a decision, for a process that is active; the parameter of the same PyPSA name carries the fixed regime | #### Definitions | Symbol | Meaning | |---|---| -| $`\widetilde{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_effective` over $`\mathcal{J} \times \Xi`$ — the build a process's limits are taken against — the chosen one where it is extendable, the given one otherwise | -| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$ — the build a committed process's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | -| $`\overrightarrow{z}`$ | `Process_output_arrival` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — what a process transfers at a port at a snapshot — its internal power delayed by the port's `delay` within its investment period, times the port's rate at the snapshot the transfer arrives; where the port is `cyclic_delay` the delayed transfer wraps from the period's end, and where it is not the energy still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) transfers at once, cyclic or not | -| $`\mathit{Process\_tech\_capacity\_expansion}`$ | `Process_tech_capacity_expansion` over $`\mathcal{G}`$ | -| $`\mathit{Process\_opex}`$ | `Process_opex` over $`\Xi`$ | -| $`\mathit{Process\_capex}`$ | `Process_capex` (scalar) | | $`\mathit{Process\_additions}`$ | `Process_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Process\_capex}`$ | `Process_capex` (scalar) | | $`\mathit{Process\_injection}`$ | `Process_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Process\_opex}`$ | `Process_opex` over $`\Xi`$ | +| $`\overrightarrow{z}`$ | `Process_output_arrival` over $`\mathcal{R} \times \Xi \times \mathcal{T}`$ — what a process transfers at a port at a snapshot — its internal power delayed by the port's `delay` within its investment period, times the port's rate at the snapshot the transfer arrives; where the port is `cyclic_delay` the delayed transfer wraps from the period's end, and where it is not the energy still in transit at the period's first snapshots is lost. A port that does not delay (`delay` zero) transfers at once, cyclic or not | +| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$ — the build a committed process's ramp rows are taken against — one module where the build is extendable and modular, the given build otherwise | +| $`\widetilde{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_effective` over $`\mathcal{J} \times \Xi`$ — the build a process's limits are taken against — the chosen one where it is extendable, the given one otherwise | +| $`\mathit{Process\_tech\_capacity\_expansion}`$ | `Process_tech_capacity_expansion` over $`\mathcal{G}`$ | #### Notation @@ -434,16 +434,16 @@ assumptions: #### Variable domains -**`Process_p`** +**`Process_n_mod`** ```math -z_{j,\xi,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z}_{j,t} +N^{z}_{j} \ge 0, N^{z}_{j} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} ``` -**`Process_n_mod`** +**`Process_p`** ```math -N^{z}_{j} \ge 0, N^{z}_{j} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} +z_{j,\xi,t} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z}_{j,t} ``` **`Process_p_nom_ext`** @@ -454,72 +454,72 @@ Z_{j} \in \mathbb{R} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{ #### Definitions -**`Process_p_nom_effective`** +**`Process_additions`** ```math -\widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} Z_{j} & \text{if } \mathrm{ext}^{z}_{j} \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\mathit{Process\_additions}_{i,y} = \sum_{j \in \mathcal{J} \,:\, \mathrm{Process\_carrier}(j) = i} Z_{j} \cdot \mathrm{new}^{z}_{y,j} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -**`Process_p_nom_committed`** +**`Process_capex`** ```math -\widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} \mathrm{z}^{\mathrm{mod}}_{j} & \text{if } \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\mathit{Process\_capex} = \sum_{j \in \mathcal{J},\ \xi \in \Xi} \pi_{\xi} \cdot Z_{j} \cdot \mathrm{c}^{\mathrm{cap},z}_{j,\xi} \cdot \mathrm{W}^{z}_{j} ``` -**`Process_output_arrival`** +**`Process_injection`** ```math -\overrightarrow{z}_{r,\xi,t} = \begin{cases} z_{\mathrm{Process\_output\_process}(r),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{if } \mathrm{cyc}^{z}_{r} \\ z_{\mathrm{Process\_output\_process}(r),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, r \in \mathcal{R},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Process\_injection}_{n,\xi,t} = \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_tech_capacity_expansion`** +**`Process_opex`** ```math -\mathit{Process\_tech\_capacity\_expansion}_{g} = \sum_{j \in \mathcal{J}} Z_{j} \cdot \mathrm{m}^{z}_{g,j} \qquad \forall\, g \in \mathcal{G} +\mathit{Process\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot \mathrm{c}^{z}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot z_{j,\xi,t} \cdot \mathrm{c}^{z,(2)}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -**`Process_opex`** +**`Process_output_arrival`** ```math -\mathit{Process\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot \mathrm{c}^{z}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} z_{j,\xi,t} \cdot z_{j,\xi,t} \cdot \mathrm{c}^{z,(2)}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\overrightarrow{z}_{r,\xi,t} = \begin{cases} z_{\mathrm{Process\_output\_process}(r),\xi,t \ominus^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{if } \mathrm{cyc}^{z}_{r} \\ z_{\mathrm{Process\_output\_process}(r),\xi,t \boxminus_{0}^{\mathrm{snapshot\_period}(t)} \mathrm{d}^{z}} \cdot \alpha_{r,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, r \in \mathcal{R},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_capex`** +**`Process_p_nom_committed`** ```math -\mathit{Process\_capex} = \sum_{j \in \mathcal{J},\ \xi \in \Xi} \pi_{\xi} \cdot Z_{j} \cdot \mathrm{c}^{\mathrm{cap},z}_{j,\xi} \cdot \mathrm{W}^{z}_{j} +\widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} \mathrm{z}^{\mathrm{mod}}_{j} & \text{if } \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -**`Process_additions`** +**`Process_p_nom_effective`** ```math -\mathit{Process\_additions}_{i,y} = \sum_{j \in \mathcal{J} \,:\, \mathrm{Process\_carrier}(j) = i} Z_{j} \cdot \mathrm{new}^{z}_{y,j} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} = \begin{cases} Z_{j} & \text{if } \mathrm{ext}^{z}_{j} \\ \mathrm{z}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -**`Process_injection`** +**`Process_tech_capacity_expansion`** ```math -\mathit{Process\_injection}_{n,\xi,t} = \sum_{r \in \mathcal{R} \,:\, \mathrm{Process\_output\_bus}(r) = n} \overrightarrow{z}_{r,\xi,t} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Process\_tech\_capacity\_expansion}_{g} = \sum_{j \in \mathcal{J}} Z_{j} \cdot \mathrm{m}^{z}_{g,j} \qquad \forall\, g \in \mathcal{G} ``` #### Subject to -**`Process_fix_p_lower`** +**`Process_ext_p_lower`** ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_fix_p_upper`** +**`Process_ext_p_nom_lower`** ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +Z_{j} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} ``` -**`Process_ext_p_lower`** +**`Process_ext_p_nom_upper`** ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +Z_{j} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \text{ is defined} ``` **`Process_ext_p_upper`** @@ -528,28 +528,28 @@ z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z} z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_ext_p_nom_lower`** +**`Process_fix_p_lower`** ```math -Z_{j} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_ext_p_nom_upper`** +**`Process_fix_p_upper`** ```math -Z_{j} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \text{ is defined} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \gamma^{z}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{z}_{j} \wedge \neg \mathrm{com}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_p_nom_set`** +**`Process_p_nom_modularity`** ```math -Z_{j} = \mathrm{z}^{\mathrm{nom,set}}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \mathrm{z}^{\mathrm{nom,set}}_{j} \text{ is defined} +Z_{j} = \mathrm{z}^{\mathrm{mod}}_{j} \cdot N^{z}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} ``` -**`Process_p_nom_modularity`** +**`Process_p_nom_set`** ```math -Z_{j} = \mathrm{z}^{\mathrm{mod}}_{j} \cdot N^{z}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \wedge \mathrm{act}^{z}_{j} +Z_{j} = \mathrm{z}^{\mathrm{nom,set}}_{j} \qquad \forall\, j \in \mathcal{J} \,:\, \mathrm{ext}^{z}_{j} \wedge \mathrm{act}^{z}_{j} \wedge \mathrm{z}^{\mathrm{nom,set}}_{j} \text{ is defined} ``` **`Process_p_set`** @@ -560,15 +560,15 @@ z_{j,\xi,t} = \mathrm{z}^{\mathrm{set}}_{j,\xi,t} \qquad \forall\, j \in \mathca #### Assumptions -**`Process_output_delay_under_uniform_weighting`** +**`Process_marginal_cost_quadratic_without_risk_preference`** ```math -\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, r \in \mathcal{R},\ t \in \mathcal{T} \,:\, \mathrm{d}^{z}_{r} > 0 +\mathrm{c}^{z,(2)}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} ``` -**`Process_marginal_cost_quadratic_without_risk_preference`** +**`Process_output_delay_under_uniform_weighting`** ```math -\mathrm{c}^{z,(2)}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \omega \text{ is defined} +\mathrm{w}^{\mathrm{gen}}_{t} = \mathrm{w}^{\mathrm{gen}}_{t \ominus 1} \qquad \forall\, r \in \mathcal{R},\ t \in \mathcal{T} \,:\, \mathrm{d}^{z}_{r} > 0 ``` diff --git a/docs/examples/pypsa/process_commitment.md b/docs/examples/pypsa/process_commitment.md index 4bf7f4a8..341a603d 100644 --- a/docs/examples/pypsa/process_commitment.md +++ b/docs/examples/pypsa/process_commitment.md @@ -308,21 +308,21 @@ constraints: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | +| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | +| $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\mathcal{J} \times \Xi`$, data another file declares | +| $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\mathcal{J} \times \Xi`$, data another file declares | +| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\mathrm{nonneg}^{z}`$ | `Process_p_min_pu_nonneg` over $`\mathcal{J}`$, data another file declares | | $`\mathrm{z}^{\mathrm{nom}}`$ | `Process_p_nom` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$, data another file declares | -| $`\underline{\mathrm{z}}`$ | `Process_p_min_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, data another file declares | -| $`\overline{\mathrm{z}}`$ | `Process_p_max_pu` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, data another file declares | -| $`\mathrm{N}^{z,\mathrm{fix}}`$ | `Process_modules_installed` over $`\mathcal{J} \times \Xi`$, data another file declares | -| $`\mathrm{nonneg}^{z}`$ | `Process_p_min_pu_nonneg` over $`\mathcal{J}`$, data another file declares | -| $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | -| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | -| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | -| $`N^{z}`$ | `Process_n_mod` over $`\mathcal{J}`$ | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mu^{z,\mathrm{nom}}`$ | `Process_maintenance_capacity` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`\mu^{z,u}`$ | `Process_maintenance_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | +| $`N^{z}`$ | `Process_n_mod` over $`\mathcal{J}`$ | +| $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`Z`$ | `Process_p_nom_ext` over $`\mathcal{J}`$ | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Process_commitment_opex` to | | $`\mathrm{on}^{z,\mathrm{com}}`$ | `Process_committed` over $`\mathcal{J} \times \mathcal{T}`$, a condition another file defines | @@ -331,25 +331,25 @@ constraints: | Symbol | Meaning | |---|---| +| $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\mathcal{J}`$ | index $`j`$ — `process` — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | | $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | -| $`\mathcal{J}`$ | index $`j`$ — `process` — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | -| $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | #### Parameters | Symbol | Meaning | |---|---| +| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\mathcal{J} \times \Xi`$, `neutral` 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{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$ — whether internal power is gated by an on/off status decision | -| $`\mathrm{UT}^{z}`$ | `Process_min_up_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays on once started | | $`\mathrm{DT}^{z}`$ | `Process_min_down_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays off once stopped | -| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$ — one where the process was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | -| $`\mathrm{hold}^{z}`$ | `Process_must_stay_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the up time a process brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | +| $`\mathrm{UT}^{z}`$ | `Process_min_up_time` over $`\mathcal{J} \times \Xi`$ — least snapshots a process stays on once started | | $`\mathrm{rest}^{z}`$ | `Process_must_stay_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the down time a process brought into the horizon still binds — PyPSA's `min_down_time - down_time_before` snapshots, where `down_time_before > 0`, data prep for the same reason | -| $`\mathrm{c}^{z,\mathrm{up}}`$ | `Process_start_up_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{hold}^{z}`$ | `Process_must_stay_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — true while the up time a process brought into the horizon still binds — data prep, since `position()` compares against a literal rather than a parameter | | $`\mathrm{c}^{z,\mathrm{dn}}`$ | `Process_shut_down_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one stop in this snapshot | | $`\mathrm{c}^{z,\mathrm{on}}`$ | `Process_stand_by_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one snapshot spent on | -| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\mathcal{J} \times \Xi`$, `neutral` 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{c}^{z,\mathrm{up}}`$ | `Process_start_up_cost` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — cost of one start in this snapshot | +| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$ — one where the process was on before the first snapshot, zero where off — PyPSA's `up_time_before > 0`, data prep | #### Conditions @@ -361,17 +361,17 @@ constraints: | Symbol | Meaning | |---|---| -| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-status` — how much of a committable process is on: an integer the rows below cap at one, or at the module count where the build is modular | -| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-start_up` — how much of a committable process turns on this snapshot, capped as the status is | | $`\mathit{dn}^{z}`$ | `Process_shut_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-shut_down` — how much of a committable process turns off this snapshot, capped as the status is | +| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-start_up` — how much of a committable process turns on this snapshot, capped as the status is | +| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — `Process-status` — how much of a committable process is on: an integer the rows below cap at one, or at the module count where the build is modular | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{Process\_commitment\_opex}`$ | `Process_commitment_opex` over $`\Xi`$ | | $`\overleftarrow{u}^{z}`$ | `Process_previous_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the commitment state a process carries into a snapshot — off at the first snapshot it stands in past the first of the horizon, as PyPSA reads a status it did not build (`constraints.py:298`), and the state carried over otherwise | | $`\overleftarrow{u}^{\circ z}`$ | `Process_status_carried_over` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the state a process carries over into a snapshot — the state it brought into the horizon at the first, the previous snapshot's after that | -| $`\mathit{Process\_commitment\_opex}`$ | `Process_commitment_opex` over $`\Xi`$ | #### Notation @@ -389,10 +389,10 @@ constraints: #### Variable domains -**`Process_status`** +**`Process_shut_down`** ```math -u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +\mathit{dn}^{z}_{j,\xi,t} \ge 0, \mathit{dn}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` **`Process_start_up`** @@ -401,151 +401,151 @@ u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \ma \mathit{up}^{z}_{j,\xi,t} \ge 0, \mathit{up}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Process_shut_down`** +**`Process_status`** ```math -\mathit{dn}^{z}_{j,\xi,t} \ge 0, \mathit{dn}^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +u^{z}_{j,\xi,t} \ge 0, u^{z}_{j,\xi,t} \in \mathbb{Z} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` #### Definitions -**`Process_previous_status`** +**`Process_commitment_opex`** ```math -\overleftarrow{u}^{z}_{j,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{z}_{j,t - 1} \\ \overleftarrow{u}^{\circ z}_{j,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Process\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} u^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{on}}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{up}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{up}}_{j,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{dn}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{dn}}_{j,\xi,t} \qquad \forall\, \xi \in \Xi ``` -**`Process_status_carried_over`** +**`Process_previous_status`** ```math -\overleftarrow{u}^{\circ z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{z}_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\overleftarrow{u}^{z}_{j,\xi,t} = \begin{cases} 0 & \text{if } \mathrm{pos}(t) > 0 \wedge \neg \mathrm{on}^{z}_{j,t - 1} \\ \overleftarrow{u}^{\circ z}_{j,\xi,t} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_commitment_opex`** +**`Process_status_carried_over`** ```math -\mathit{Process\_commitment\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} u^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{on}}_{j,\xi,t} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{up}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{up}}_{j,\xi,t} + \sum_{t \in \mathcal{T}} \sum_{j \in \mathcal{J}} \mathit{dn}^{z}_{j,\xi,t} \cdot \mathrm{c}^{z,\mathrm{dn}}_{j,\xi,t} \qquad \forall\, \xi \in \Xi +\overleftarrow{u}^{\circ z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ u^{z}_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` #### Subject to -**`Process_com_p_lower`** +**`Process_com_down_time`** ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{z}} \mathit{dn}^{z}_{j,\xi,t'} \le 1 - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{DT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Process_com_p_upper`** +**`Process_com_ext_p_lower`** ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) + \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} - \mathrm{M}^{z}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -**`Process_com_transition_start_up`** +**`Process_com_ext_p_lower_nonneg`** ```math -\mathit{up}^{z}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +z_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \mathrm{nonneg}^{z}_{j} ``` -**`Process_com_transition_shut_down`** +**`Process_com_ext_p_upper_big_m`** ```math -\mathit{dn}^{z}_{j,\xi,t} \ge \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} +z_{j,\xi,t} \le \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -**`Process_com_up_time`** +**`Process_com_ext_p_upper_cap`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{z}} \mathit{up}^{z}_{j,\xi,t'} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{UT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} ``` -**`Process_com_down_time`** +**`Process_com_mod_p_lower`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{DT}^{z}} \mathit{dn}^{z}_{j,\xi,t'} \le 1 - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{DT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_com_status_must_stay_up`** +**`Process_com_mod_p_upper`** ```math -u^{z}_{j,\xi,t} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{hold}^{z}_{j,\xi,t} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_com_status_must_stay_down`** +**`Process_com_p_lower`** ```math -u^{z}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{rest}^{z}_{j,\xi,t} +z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_com_ext_p_upper_cap`** +**`Process_com_p_upper`** ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_com_ext_p_upper_big_m`** +**`Process_com_status_must_stay_down`** ```math -z_{j,\xi,t} \le \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +u^{z}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{rest}^{z}_{j,\xi,t} ``` -**`Process_com_ext_p_lower`** +**`Process_com_status_must_stay_up`** ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \left( Z_{j} - \gamma^{z}_{j,\xi} \cdot \mu^{z,\mathrm{nom}}_{j,\xi,t} \right) + \mathrm{M}^{z}_{j,\xi} \cdot u^{z}_{j,\xi,t} - \mathrm{M}^{z}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} +u^{z}_{j,\xi,t} = 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{hold}^{z}_{j,\xi,t} ``` -**`Process_com_ext_p_lower_nonneg`** +**`Process_com_transition_shut_down`** ```math -z_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \mathrm{nonneg}^{z}_{j} +\mathit{dn}^{z}_{j,\xi,t} \ge \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Process_com_mod_p_lower`** +**`Process_com_transition_start_up`** ```math -z_{j,\xi,t} \ge \underline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mathit{up}^{z}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} ``` -**`Process_com_mod_p_upper`** +**`Process_com_up_time`** ```math -z_{j,\xi,t} \le \overline{\mathrm{z}}_{j,\xi,t} \cdot \mathrm{z}^{\mathrm{mod}}_{j} \cdot \left( u^{z}_{j,\xi,t} - \gamma^{z}_{j,\xi} \cdot \mu^{z,u}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < \mathrm{UT}^{z}} \mathit{up}^{z}_{j,\xi,t'} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{UT}^{z}_{j,\xi} > 0 \wedge \mathrm{pos}(t) > 0 ``` -**`Process_status_p_fixed_upper`** +**`Process_shut_down_p_fixed_upper`** ```math -u^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mathit{dn}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_start_up_p_fixed_upper`** +**`Process_shut_down_p_nom_variable_upper`** ```math -\mathit{up}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mathit{dn}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_shut_down_p_fixed_upper`** +**`Process_start_up_p_fixed_upper`** ```math -\mathit{dn}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mathit{up}^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_status_p_nom_variable_upper`** +**`Process_start_up_p_nom_variable_upper`** ```math -u^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mathit{up}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_start_up_p_nom_variable_upper`** +**`Process_status_p_fixed_upper`** ```math -\mathit{up}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +u^{z}_{j,\xi,t} \le \mathrm{N}^{z,\mathrm{fix}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \left( \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_shut_down_p_nom_variable_upper`** +**`Process_status_p_nom_variable_upper`** ```math -\mathit{dn}^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +u^{z}_{j,\xi,t} \le N^{z}_{j} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{ext}^{z}_{j} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` diff --git a/docs/examples/pypsa/process_maintenance.md b/docs/examples/pypsa/process_maintenance.md index 141dfa3f..e331a9c3 100644 --- a/docs/examples/pypsa/process_maintenance.md +++ b/docs/examples/pypsa/process_maintenance.md @@ -251,33 +251,33 @@ assumptions: | Symbol | Meaning | |---|---| +| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$, data another file declares | | $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$, data another file declares | -| $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`\overline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_max` over $`\mathcal{J} \times \Xi`$, data another file declares | -| $`\mathrm{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$, data another file declares | +| $`\underline{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_min` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, data another file declares | -| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$, data another file declares | -| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`Z`$ | `Process_p_nom_ext` over $`\mathcal{J}`$ | +| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`\mathrm{on}^{z,\mathrm{com}}`$ | `Process_committed` over $`\mathcal{J} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| +| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Process_maintenance_cover` is `absent` where the data has no row — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | | $`\Xi`$ | index $`\xi`$ — `scenario` with $`\mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Process_maintenance_cover` is `absent` where the data has no row — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Process_maintenance_cover` is `absent` where the data has no row — dispatch periods | -| $`\mathcal{J}`$ | index $`j`$ — `process` with $`\mathrm{Process\_maintenance\_cover} \subseteq \mathcal{T} \times \mathcal{J} \times \Xi \times \mathcal{T}`$, `Process_maintenance_cover` is `absent` where the data has no row — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | #### Parameters | Symbol | Meaning | |---|---| | $`\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 $`\mathcal{J} \times \Xi`$ — the share of the build a maintenance event takes off | -| $`\mathrm{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\mathcal{J} \times \Xi`$ — how many maintenance events the horizon holds | | $`\tau^{z,\mathrm{mnt}}`$ | `Process_maintenance_duration` over $`\mathcal{J} \times \Xi`$, `neutral` 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{n}^{z,\mathrm{mnt}}`$ | `Process_maintenance_events` over $`\mathcal{J} \times \Xi`$ — how many maintenance events the horizon holds | +| $`\gamma^{z}`$ | `Process_maintenance_pu` over $`\mathcal{J} \times \Xi`$ — the share of the build a maintenance event takes off | | $`\mathrm{blk}^{z}`$ | `Process_maintenance_start_blocked` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — 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 | #### Conditions @@ -291,8 +291,8 @@ assumptions: | Symbol | Meaning | |---|---| | $`\mu^{z}`$ | `Process_maintenance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance` — whether a maintainable process is in maintenance: continuous, and one exactly where an event covers the snapshot | -| $`\mu^{z,\mathrm{up}}`$ | `Process_maintenance_start` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{z,\mathrm{nom}}`$ | `Process_maintenance_capacity` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_capacity` — the chosen build while in maintenance, zero otherwise: the product the `maintcap` rows linearize | +| $`\mu^{z,\mathrm{up}}`$ | `Process_maintenance_start` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_start` — whether a maintenance event starts in this snapshot | | $`\mu^{z,u}`$ | `Process_maintenance_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` where the mask leaves it out — `Process-maintenance_status` — the status while in maintenance, zero otherwise: the product the `maint-status` rows linearize, so a unit in maintenance may also be off | #### Conditions @@ -311,16 +311,16 @@ assumptions: 0 \le \mu^{z}_{j,\xi,t} \le 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_maintenance_start`** +**`Process_maintenance_capacity`** ```math -\mu^{z,\mathrm{up}}_{j,\xi,t} \in \{0, 1\} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -**`Process_maintenance_capacity`** +**`Process_maintenance_start`** ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mu^{z,\mathrm{up}}_{j,\xi,t} \in \{0, 1\} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` **`Process_maintenance_status`** @@ -337,40 +337,40 @@ assumptions: \sum_{t \in \mathcal{T}} \mu^{z,\mathrm{up}}_{j,\xi,t} = \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -**`Process_maint_window`** +**`Process_maint_modstatus_lb`** ```math -\mu^{z}_{j,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ j,\ \xi,\ t' \right) \in \mathrm{Process\_maintenance\_cover}} \mu^{z,\mathrm{up}}_{j,\xi,t'} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} +\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_maint_start_horizon`** +**`Process_maint_modstatus_le_maint`** ```math -\mu^{z,\mathrm{up}}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \wedge \mathrm{blk}^{z}_{j,\xi,t} +\mu^{z,u}_{j,\xi,t} \le \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_maintcap_upper`** +**`Process_maint_modstatus_le_status`** ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \le Z_{j} - \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 ``` -**`Process_maintcap_upper_nommax`** +**`Process_maint_start_horizon`** ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mu^{z,\mathrm{up}}_{j,\xi,t} = 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} \wedge \mathrm{blk}^{z}_{j,\xi,t} ``` -**`Process_maintcap_lower_nommax`** +**`Process_maint_status_lb`** ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge Z_{j} - \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} +\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} + \mu^{z}_{j,\xi,t} - 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_maintcap_lower_nommin`** +**`Process_maint_status_le_maint`** ```math -\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} \wedge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} > 0 +\mu^{z,u}_{j,\xi,t} \le \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` **`Process_maint_status_le_status`** @@ -379,54 +379,54 @@ assumptions: \mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) ``` -**`Process_maint_status_le_maint`** +**`Process_maint_window`** ```math -\mu^{z,u}_{j,\xi,t} \le \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mu^{z}_{j,\xi,t} = \sum_{t' \in \mathcal{T} \,:\, \left( t,\ j,\ \xi,\ t' \right) \in \mathrm{Process\_maintenance\_cover}} \mu^{z,\mathrm{up}}_{j,\xi,t'} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_maint_status_lb`** +**`Process_maintcap_lower_nommax`** ```math -\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} + \mu^{z}_{j,\xi,t} - 1 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \neg \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) +\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge Z_{j} - \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -**`Process_maint_modstatus_le_status`** +**`Process_maintcap_lower_nommin`** ```math -\mu^{z,u}_{j,\xi,t} \le u^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mu^{z,\mathrm{nom}}_{j,\xi,t} \ge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} \wedge \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} > 0 ``` -**`Process_maint_modstatus_le_maint`** +**`Process_maintcap_upper`** ```math -\mu^{z,u}_{j,\xi,t} \le \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mu^{z,\mathrm{nom}}_{j,\xi,t} \le Z_{j} - \underline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` -**`Process_maint_modstatus_lb`** +**`Process_maintcap_upper_nommax`** ```math -\mu^{z,u}_{j,\xi,t} \ge u^{z}_{j,\xi,t} - \frac{\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi}}{\mathrm{z}^{\mathrm{mod}}_{j}} \cdot \left( 1 - \mu^{z}_{j,\xi,t} \right) \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{on}^{z,\mathrm{com}}_{j,t} \wedge \mathrm{z}^{\mathrm{mod}}_{j} > 0 +\mu^{z,\mathrm{nom}}_{j,\xi,t} \le \overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \mu^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{mnt,ext}}_{j,t} ``` #### Assumptions -**`Process_maintenance_events_positive`** +**`Process_maintenance_build_cap_is_finite`** ```math -\mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} < \infty \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} ``` -**`Process_maintenance_duration_positive`** +**`Process_maintenance_duration_fits_the_horizon`** ```math -\tau^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\tau^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -**`Process_maintenance_duration_fits_the_horizon`** +**`Process_maintenance_duration_positive`** ```math -\tau^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} +\tau^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` **`Process_maintenance_events_fit_the_horizon`** @@ -435,10 +435,10 @@ assumptions: \tau^{z,\mathrm{mnt}}_{j,\xi} \cdot \mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} \le \sum_{t \in \mathcal{T}} \mathrm{w}^{\mathrm{gen}}_{t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` -**`Process_maintenance_build_cap_is_finite`** +**`Process_maintenance_events_positive`** ```math -\overline{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} < \infty \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} +\mathrm{n}^{z,\mathrm{mnt}}_{j,\xi} > 0 \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi \,:\, \mathrm{mnt}^{z}_{j} ``` **`Process_maintenance_module_count_is_finite`** diff --git a/docs/examples/pypsa/process_ramping.md b/docs/examples/pypsa/process_ramping.md index c2021721..806c806c 100644 --- a/docs/examples/pypsa/process_ramping.md +++ b/docs/examples/pypsa/process_ramping.md @@ -259,40 +259,40 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$, data another file declares | +| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`\mathrm{com}^{z}`$ | `Process_committable` over $`\mathcal{J}`$, data another file declares | -| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$, data another file declares | +| $`\mathrm{ext}^{z}`$ | `Process_p_nom_extendable` over $`\mathcal{J}`$, data another file declares | | $`\mathrm{z}^{\mathrm{mod}}`$ | `Process_p_nom_mod` over $`\mathcal{J}`$, data another file declares | -| $`\mathrm{M}^{z}`$ | `Process_big_m` over $`\mathcal{J} \times \Xi`$, data another file declares | -| $`\mathrm{on}^{z}`$ | `Process_active` over $`\mathcal{J} \times \mathcal{T}`$, data another file declares | +| $`\mathrm{u}^{z,0}`$ | `Process_status_initial` over $`\mathcal{J} \times \Xi`$, data another file declares | | $`z`$ | `Process_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | -| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{dn}^{z}`$ | `Process_shut_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | | $`Z`$ | `Process_p_nom_ext` over $`\mathcal{J}`$ | +| $`\mathit{dn}^{z}`$ | `Process_shut_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{up}^{z}`$ | `Process_start_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | +| $`u^{z}`$ | `Process_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ | +| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$, an expression another file defines | | $`\widetilde{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_effective` over $`\mathcal{J} \times \Xi`$, an expression another file defines | | $`\overleftarrow{u}^{z}`$ | `Process_previous_status` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, an expression another file defines | -| $`\widehat{\mathrm{z}}^{\mathrm{nom}}`$ | `Process_p_nom_committed` over $`\mathcal{J} \times \Xi`$, an expression another file defines | | $`\mathrm{on}^{z,\mathrm{com,ext}}`$ | `Process_com_ext` over $`\mathcal{J} \times \mathcal{T}`$, a condition another file defines | #### Sets | Symbol | Meaning | |---|---| +| $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\mathcal{J}`$ | index $`j`$ — `process` — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | | $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | | $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | -| $`\mathcal{J}`$ | index $`j`$ — `process` — generalized multi-port converters, each with an internal power that every port draws or delivers at its own rate | -| $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{ru}^{z}`$ | `Process_ramp_limit_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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{z}^{0}`$ | `Process_p_init` over $`\mathcal{J} \times \Xi`$, `neutral` 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 | | $`\mathrm{rd}^{z}`$ | `Process_ramp_limit_down` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 $`\mathcal{J} \times \Xi`$, `neutral` 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 $`\mathcal{J} \times \Xi`$, `neutral` 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 $`\mathcal{J} \times \Xi`$, `neutral` 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 | +| $`\mathrm{ru}^{z,\mathrm{up}}`$ | `Process_ramp_limit_start_up` over $`\mathcal{J} \times \Xi`$, `neutral` 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{ru}^{z}`$ | `Process_ramp_limit_up` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$, `neutral` 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 | #### Conditions @@ -305,12 +305,12 @@ assumptions: | Symbol | Meaning | |---|---| | $`\overleftarrow{z}`$ | `Process_previous_p` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the internal power a process carries into a snapshot — at the first, the `p_init` it brought in where it came in running and nothing where it came in off; the previous snapshot's after that | -| $`\widetilde{\mathrm{ru}}^{z}`$ | `Process_ramp_up_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\Delta^{z,-}`$ | `Process_ramp_down_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may lower internal power between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | | $`\widetilde{\mathrm{rd}}^{z}`$ | `Process_ramp_down_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's down row reads — PyPSA's `ramp_limit_down`, or the full build where it has none, since a shut-down ramp alone builds the row | -| $`\widetilde{\mathrm{ru}}^{z,\mathrm{up}}`$ | `Process_start_up_rate` over $`\mathcal{J} \times \Xi`$ — the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | -| $`\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}`$ | `Process_shut_down_rate` over $`\mathcal{J} \times \Xi`$ — the shut-down ramp a process's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | | $`\Delta^{z,+}`$ | `Process_ramp_up_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may raise internal power between two snapshots — its ramp limit of the build while it stays on, plus its start-up ramp in the snapshot it turns on | -| $`\Delta^{z,-}`$ | `Process_ramp_down_allowance` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — how far a process may lower internal power between two snapshots — its ramp limit of the build while it stays on, plus its shut-down ramp in the snapshot it turns off | +| $`\widetilde{\mathrm{ru}}^{z}`$ | `Process_ramp_up_rate` over $`\mathcal{J} \times \Xi \times \mathcal{T}`$ — the ramp limit a process's up row reads — PyPSA's `ramp_limit_up`, or the full build where it has none, since a start-up ramp alone builds the row | +| $`\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}`$ | `Process_shut_down_rate` over $`\mathcal{J} \times \Xi`$ — the shut-down ramp a process's down row reads — PyPSA's `ramp_limit_shut_down`, or the full build where it has none | +| $`\widetilde{\mathrm{ru}}^{z,\mathrm{up}}`$ | `Process_start_up_rate` over $`\mathcal{J} \times \Xi`$ — the start-up ramp a process's up row reads — PyPSA's `ramp_limit_start_up`, or the full build where it has none | #### Notation @@ -335,10 +335,10 @@ assumptions: \overleftarrow{z}_{j,\xi,t} = \begin{cases} \mathrm{u}^{z,0}_{j,\xi} \cdot \mathrm{z}^{0}_{j,\xi} & \text{if } \mathrm{pos}(t) = 0 \\ z_{j,\xi,t - 1} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_ramp_up_rate`** +**`Process_ramp_down_allowance`** ```math -\widetilde{\mathrm{ru}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{ru}^{z}_{j,\xi,t} & \text{if } \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\Delta^{z,-}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot u^{z}_{j,\xi,t} + \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` **`Process_ramp_down_rate`** @@ -347,42 +347,36 @@ assumptions: \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{rd}^{z}_{j,\xi,t} & \text{if } \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_start_up_rate`** +**`Process_ramp_up_allowance`** ```math -\widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} = \begin{cases} \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} & \text{if } \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\Delta^{z,+}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} + \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_shut_down_rate`** +**`Process_ramp_up_rate`** ```math -\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} = \begin{cases} \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} & \text{if } \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi +\widetilde{\mathrm{ru}}^{z}_{j,\xi,t} = \begin{cases} \mathrm{ru}^{z}_{j,\xi,t} & \text{if } \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Process_ramp_up_allowance`** +**`Process_shut_down_rate`** ```math -\Delta^{z,+}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} + \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( u^{z}_{j,\xi,t} - \overleftarrow{u}^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} = \begin{cases} \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} & \text{if } \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` -**`Process_ramp_down_allowance`** +**`Process_start_up_rate`** ```math -\Delta^{z,-}_{j,\xi,t} = \begin{cases} \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot u^{z}_{j,\xi,t} + \widetilde{\mathrm{rd}}^{z,\mathrm{dn}}_{j,\xi} \cdot \widehat{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} \cdot \left( \overleftarrow{u}^{z}_{j,\xi,t} - u^{z}_{j,\xi,t} \right) & \text{if } \mathrm{com}^{z}_{j} \\ \widetilde{\mathrm{rd}}^{z}_{j,\xi,t} \cdot \widetilde{\mathrm{z}}^{\mathrm{nom}}_{j,\xi} & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} +\widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} = \begin{cases} \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} & \text{if } \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \\ 1 & \text{otherwise} \end{cases} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi ``` #### Subject to -**`Process_p_ramp_limit_up_run_big_m`** - -```math -z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} -``` - -**`Process_p_ramp_limit_up_start_big_m`** +**`Process_p_ramp_limit_down`** ```math -z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{up}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \Delta^{z,-}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} ``` **`Process_p_ramp_limit_down_run_big_m`** @@ -403,10 +397,16 @@ z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z,\mathrm z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \Delta^{z,+}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} ``` -**`Process_p_ramp_limit_down`** +**`Process_p_ramp_limit_up_run_big_m`** ```math -\overleftarrow{z}_{j,\xi,t} - z_{j,\xi,t} \le \Delta^{z,-}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \left( \mathrm{rd}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{rd}^{z,\mathrm{dn}}_{j,\xi} \text{ is defined} \right) \wedge \neg \left( \mathrm{com}^{z}_{j} \wedge \mathrm{ext}^{z}_{j} \wedge \neg \left( \mathrm{z}^{\mathrm{mod}}_{j} > 0 \right) \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} \wedge \mathrm{on}^{z}_{j,t} +z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z}_{j,\xi,t} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \overleftarrow{u}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} +``` + +**`Process_p_ramp_limit_up_start_big_m`** + +```math +z_{j,\xi,t} - \overleftarrow{z}_{j,\xi,t} \le \widetilde{\mathrm{ru}}^{z,\mathrm{up}}_{j,\xi} \cdot Z_{j} + \mathrm{M}^{z}_{j,\xi} - \mathrm{M}^{z}_{j,\xi} \cdot \mathit{up}^{z}_{j,\xi,t} \qquad \forall\, j \in \mathcal{J},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{on}^{z,\mathrm{com,ext}}_{j,t} \wedge \left( \mathrm{ru}^{z}_{j,\xi,t} \text{ is defined} \vee \mathrm{ru}^{z,\mathrm{up}}_{j,\xi} \text{ is defined} \right) \wedge \mathrm{prev}^{z}_{j,\xi,t} ``` #### Assumptions diff --git a/docs/examples/pypsa/security.md b/docs/examples/pypsa/security.md index 1360018f..c524ecd6 100644 --- a/docs/examples/pypsa/security.md +++ b/docs/examples/pypsa/security.md @@ -196,12 +196,12 @@ constraints: | Symbol | Meaning | |---|---| +| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{s}^{\mathrm{nom}}`$ | `Line_s_nom` over $`\mathcal{K} \times \Xi`$, data another file declares | | $`\mathrm{ext}^{s}`$ | `Line_s_nom_extendable` over $`\mathcal{K}`$, data another file declares | -| $`\overline{\mathrm{s}}`$ | `Line_s_max_pu` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, data another file declares | +| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, data another file declares | | $`\sigma^{\mathrm{nom}}`$ | `Transformer_s_nom` over $`\Xi \times \mathcal{M}`$, data another file declares | | $`\mathrm{ext}^{\sigma}`$ | `Transformer_s_nom_extendable` over $`\mathcal{M}`$, data another file declares | -| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, data another file declares | | $`S`$ | `Line_s_nom_ext` over $`\mathcal{K}`$ | | $`\Sigma`$ | `Transformer_s_nom_ext` over $`\mathcal{M}`$ | | $`\check{s}`$ | `Line_s_monitored` over $`\mathcal{K} \times \Xi \times \mathcal{T}`$, an expression another file defines | @@ -211,12 +211,12 @@ constraints: | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{K}`$ | index $`k`$ — `line` with $`\mathrm{Outage\_line}: \mathcal{K}^{\mathrm{out}} \to \mathcal{K}`$, `Outage_line` is `absent` where the data has no row — passive branches, each between two buses, their flow set by impedance | -| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M}`$, `Outage_transformer` is `absent` where the data has no row — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | | $`\mathcal{K}^{\mathrm{out}}`$ | index $`\kappa`$ — `outage` with $`\mathrm{Outage\_line}: \mathcal{K}^{\mathrm{out}} \to \mathcal{K},\ \mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M}`$, `Outage_line` is `absent` where the data has no row, `Outage_transformer` is `absent` where the data has no row — the passive branches a security-constrained run takes out one at a time — PyPSA's `branch_outages`, each a line or a transformer; none on a plain run | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | +| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Outage\_transformer}: \mathcal{K}^{\mathrm{out}} \to \mathcal{M}`$, `Outage_transformer` is `absent` where the data has no row — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | #### Parameters @@ -241,18 +241,6 @@ constraints: #### Subject to -**`Line_fix_s_lower_security`** - -```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} -``` - -**`Line_fix_s_upper_security`** - -```math -\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} -``` - **`Line_ext_s_lower_security`** ```math @@ -265,16 +253,16 @@ constraints: \check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot S_{k} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -**`Transformer_fix_s_lower_security`** +**`Line_fix_s_lower_security`** ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` -**`Transformer_fix_s_upper_security`** +**`Line_fix_s_upper_security`** ```math -\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +\check{s}_{k,\xi,t} + \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\mathrm{s}}_{k,\xi,t} \cdot \mathrm{s}^{\mathrm{nom}}_{k,\xi} \qquad \forall\, k \in \mathcal{K},\ \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T} \,:\, \neg \mathrm{ext}^{s}_{k} \wedge \beta_{k,\kappa,\mathrm{snapshot\_period}(t)} \text{ is defined} ``` **`Transformer_ext_s_lower_security`** @@ -288,4 +276,16 @@ constraints: ```math \check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} ``` + +**`Transformer_fix_s_lower_security`** + +```math +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +``` + +**`Transformer_fix_s_upper_security`** + +```math +\check{\sigma}_{\xi,t,m} + \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \cdot \hat{s}_{\kappa,\xi,t} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \kappa \in \mathcal{K}^{\mathrm{out}},\ \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \beta^{\sigma}_{\kappa,\mathrm{snapshot\_period}(t),m} \text{ is defined} +``` diff --git a/docs/examples/pypsa/settings.md b/docs/examples/pypsa/settings.md index 6fe8aa54..65477c95 100644 --- a/docs/examples/pypsa/settings.md +++ b/docs/examples/pypsa/settings.md @@ -158,38 +158,38 @@ objective: | Symbol | Meaning | |---|---| -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `primary_energy` row totals — weighted generator energy over the snapshots it counts, less the charge left in weighted storage at the close; the initial charge it is compared against is folded into the row's constant | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression another file defines — what a carrier adds in a period — every extendable component of that carrier, counting each build in the first period it stands in. Like PyPSA, it sums only the components that carry a carrier attribute, so a transformer, which has none, counts in no carrier | | $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what an `operational_limit` row totals — the weighted energy its generators deliver over the snapshots it counts, plus what its non-cyclic storage draws down; the initial charge it draws from is folded into the row's constant | -| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `transmission_volume_expansion_limit` row totals — length times the chosen build of the row's branches | -| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `transmission_expansion_cost_limit` row totals — capital cost times the chosen build of the row's branches | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression another file defines — what a `tech_capacity_expansion_limit` row totals — the chosen build of the row's carrier-and-bus set | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `primary_energy` row totals — weighted generator energy over the snapshots it counts, less the charge left in weighted storage at the close; the initial charge it is compared against is folded into the row's constant | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression another file defines — what a future costs to run — every operating term, weighted by the snapshot's hours and its period, before the scenario's own weight; a start and a stop cost what they cost, unweighted, as PyPSA adds them (`optimize.py:415-432`) | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression another file defines — what a `tech_capacity_expansion_limit` row totals — the chosen build of the row's carrier-and-bus set | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression another file defines — what the system costs — capacity once per active period at its expected cost over the scenarios, operation in expectation over the scenarios, and a share of it at the tail | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression another file defines — what a carrier adds in a period — every extendable component of that carrier, counting each build in the first period it stands in. Like PyPSA, it sums only the components that carry a carrier attribute, so a transformer, which has none, counts in no carrier | +| $`\mathit{transmission\_expansion\_cost}`$ | `transmission_expansion_cost` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `transmission_expansion_cost_limit` row totals — capital cost times the chosen build of the row's branches | +| $`\mathit{transmission\_volume\_expansion}`$ | `transmission_volume_expansion` over $`\mathcal{G} \times \Xi`$, an expression another file defines — what a `transmission_volume_expansion_limit` row totals — length times the chosen build of the row's branches | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` — energy carriers, what a growth limit is set per | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.objective` — hours a snapshot stands for in the cost | -| $`\pi`$ | `scenario_weight` over $`\Xi`$ — PyPSA's `scenario_weightings.weight` — the probability of a future | | $`\omega`$ | `CVaR_omega` (scalar), `neutral` 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 | +| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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{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{w}^{\mathrm{sto}}`$ | `snapshot_weightings_stores` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.stores` — hours a snapshot stands for in a storage balance | +| $`\pi`$ | `scenario_weight` over $`\Xi`$ — PyPSA's `scenario_weightings.weight` — the probability of a future | | $`\mathrm{w}^{\mathrm{gen}}`$ | `snapshot_weightings_generators` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.generators` — hours a snapshot stands for in an energy total | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$ — PyPSA's `snapshot_weightings.objective` — hours a snapshot stands for in the cost | +| $`\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{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 | -| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, `neutral` 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`) | #### Definitions diff --git a/docs/examples/pypsa/storage_unit.md b/docs/examples/pypsa/storage_unit.md index f4524ce7..6d9580a5 100644 --- a/docs/examples/pypsa/storage_unit.md +++ b/docs/examples/pypsa/storage_unit.md @@ -541,32 +541,32 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\omega`$ | `CVaR_omega` (scalar), data another file declares | +| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | | $`\mathrm{w}^{\mathrm{yr}}`$ | `period_weight_years` over $`\mathcal{Y}`$, data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mathrm{w}^{\mathrm{sto}}`$ | `snapshot_weightings_stores` over $`\mathcal{T}`$, data another file declares | -| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression this file adds `StorageUnit_primary_energy` to | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `StorageUnit_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `StorageUnit_additions` to | | $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{G} \times \Xi`$, an expression this file adds `StorageUnit_operational_limit` to | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `StorageUnit_tech_capacity_expansion` to | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression this file adds `StorageUnit_primary_energy` to | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `StorageUnit_opex` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `StorageUnit_tech_capacity_expansion` to | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `StorageUnit_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `StorageUnit_additions` to | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `StorageUnit_injection` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{S}`$ | index $`s`$ — `storage_unit` with $`\mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I},\ \mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N}`$ — storage units, dispatch and store behind one bus connection | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | +| $`\mathcal{S}`$ | index $`s`$ — `storage_unit` with $`\mathrm{StorageUnit\_bus}: \mathcal{S} \to \mathcal{N},\ \mathrm{StorageUnit\_carrier}: \mathcal{S} \to \mathcal{I}`$ — storage units, dispatch and store behind one bus connection | #### Parameters @@ -574,73 +574,73 @@ assumptions: |---|---| | $`\mathrm{on}^{h}`$ | `StorageUnit_active` over $`\mathcal{T} \times \mathcal{S}`$ — whether a storage unit stands in a snapshot's period — PyPSA's `active`, data prep | | $`\mathrm{act}^{h}`$ | `StorageUnit_active_asset` over $`\mathcal{S}`$ — whether a storage unit 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}^{h}`$ | `StorageUnit_capital_weight` over $`\mathcal{S}`$ — the sum of period weights a storage unit stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\mathrm{new}^{h}`$ | `StorageUnit_first_active` over $`\mathcal{Y} \times \mathcal{S}`$ — one in the first period a storage unit stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | -| $`\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}`$, `neutral` 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\underline{\mathrm{h}}`$ | `StorageUnit_p_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most storing, per unit of nominal power and negated | -| $`\overline{\mathrm{h}}`$ | `StorageUnit_p_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most dispatch, per unit of nominal power | -| $`\mathrm{T}^{h}`$ | `StorageUnit_max_hours` over $`\Xi \times \mathcal{S}`$ — energy capacity, as hours of dispatch at nominal power | -| $`\eta^{-}`$ | `StorageUnit_efficiency_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the power drawn from the bus that becomes charge | -| $`\eta^{+}`$ | `StorageUnit_efficiency_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the charge drawn down that reaches the bus | -| $`\mathrm{sgn}^{h}`$ | `StorageUnit_sign` over $`\mathcal{S}`$ — the sign net dispatch enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | -| $`\rho`$ | `StorageUnit_retention` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of charge kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | -| $`\mathrm{inflow}`$ | `StorageUnit_inflow` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — energy arriving per hour, a river into a reservoir | -| $`\mathrm{soc}^{0}`$ | `StorageUnit_state_of_charge_initial` over $`\Xi \times \mathcal{S}`$ — charge held before the first snapshot | +| $`\mathrm{W}^{h}`$ | `StorageUnit_capital_weight` over $`\mathcal{S}`$ — the sum of period weights a storage unit stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{cyc}`$ | `StorageUnit_cyclic_state_of_charge` over $`\Xi \times \mathcal{S}`$ — whether the horizon closes on itself instead of opening on the initial charge | | $`\mathrm{cyc}^{y}`$ | `StorageUnit_cyclic_state_of_charge_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period closes on itself instead of carrying its charge on to the next; it overrides `cyclic_state_of_charge` and `state_of_charge_initial_per_period`. PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{reset}`$ | `StorageUnit_state_of_charge_initial_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period opens on the initial charge instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{open}`$ | `StorageUnit_opens_late` over $`\mathcal{T} \times \mathcal{S}`$ — whether a snapshot is the first a storage unit stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every unit stands throughout | +| $`\eta^{+}`$ | `StorageUnit_efficiency_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the charge drawn down that reaches the bus | +| $`\eta^{-}`$ | `StorageUnit_efficiency_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of the power drawn from the bus that becomes charge | +| $`\mathrm{new}^{h}`$ | `StorageUnit_first_active` over $`\mathcal{Y} \times \mathcal{S}`$ — one in the first period a storage unit stands in, zero elsewhere, data prep. PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:265`) | | $`\mathrm{idle}`$ | `StorageUnit_inactive_snapshots` over $`\mathcal{S}`$ — how many snapshots a storage unit does not stand in — PyPSA's `(~active).sum()`, data prep. A cyclic unit reaches back this many snapshots further, so it closes on the last snapshot it stands in | +| $`\mathrm{inflow}`$ | `StorageUnit_inflow` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — energy arriving per hour, a river into a reservoir | | $`\mathrm{c}^{h}`$ | `StorageUnit_marginal_cost` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — cost of one unit of dispatch | | $`\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}`$, `neutral` where the data has no row — a given net dispatch schedule; a unit without one has no row here | +| $`\mathrm{T}^{h}`$ | `StorageUnit_max_hours` over $`\Xi \times \mathcal{S}`$ — energy capacity, as hours of dispatch at nominal power | +| $`\mathrm{open}`$ | `StorageUnit_opens_late` over $`\mathcal{T} \times \mathcal{S}`$ — whether a snapshot is the first a storage unit stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every unit stands throughout | +| $`\mathrm{b}^{h}`$ | `StorageUnit_operational_limit_weight` over $`\mathcal{G} \times \Xi \times \mathcal{S}`$, `neutral` 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{h}^{+,\mathrm{set}}`$ | `StorageUnit_p_dispatch_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the data has no row — a given dispatch schedule; a unit without one has no row here | +| $`\overline{\mathrm{h}}`$ | `StorageUnit_p_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most dispatch, per unit of nominal power | +| $`\underline{\mathrm{h}}`$ | `StorageUnit_p_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — most storing, per unit of nominal power and negated | +| $`\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 | +| $`\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 | +| $`\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 | +| $`\mathrm{h}^{\mathrm{mod}}`$ | `StorageUnit_p_nom_mod` over $`\mathcal{S}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{h}^{\mathrm{nom,set}}`$ | `StorageUnit_p_nom_set` over $`\mathcal{S}`$, `neutral` 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{set}}`$ | `StorageUnit_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` 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_store_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` 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}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{S}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{S}`$, `neutral` 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 | +| $`\rho`$ | `StorageUnit_retention` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — share of charge kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | +| $`\mathrm{sgn}^{h}`$ | `StorageUnit_sign` over $`\mathcal{S}`$ — the sign net dispatch enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | +| $`\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{soc}^{0}`$ | `StorageUnit_state_of_charge_initial` over $`\Xi \times \mathcal{S}`$ — charge held before the first snapshot | +| $`\mathrm{reset}`$ | `StorageUnit_state_of_charge_initial_per_period` over $`\Xi \times \mathcal{S}`$ — whether each investment period opens on the initial charge instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | +| $`\mathrm{soc}^{\mathrm{set}}`$ | `StorageUnit_state_of_charge_set` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the data has no row — a given charge schedule; a unit without one has no row here | | $`\mathrm{m}^{h}`$ | `StorageUnit_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{S}`$, `neutral` 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 | #### Conditions | Symbol | Meaning | |---|---| -| $`\mathrm{on}^{h,\mathrm{fix}}`$ | `StorageUnit_fix` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with a fixed build that stands in the snapshot's period — PyPSA's `fix` rows | | $`\mathrm{on}^{h,\mathrm{ext}}`$ | `StorageUnit_ext` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with an extendable build that stands in the snapshot's period — PyPSA's `ext` rows | +| $`\mathrm{on}^{h,\mathrm{fix}}`$ | `StorageUnit_fix` over $`\mathcal{T} \times \mathcal{S}`$ — a storage unit with a fixed build that stands in the snapshot's period — PyPSA's `fix` rows | #### Variables | Symbol | Meaning | |---|---| +| $`N^{h}`$ | `StorageUnit_n_mod` over $`\mathcal{S}`$ — `StorageUnit-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | | $`h^{+}`$ | `StorageUnit_p_dispatch` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_dispatch` — power delivered to the bus | +| $`H`$ | `StorageUnit_p_nom_ext` over $`\mathcal{S}`$ — `StorageUnit-p_nom` — nominal power where it is a decision, for a storage unit that is active; the parameter of the same PyPSA name carries the fixed regime | | $`h^{-}`$ | `StorageUnit_p_store` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-p_store` — power drawn from the bus into charge | -| $`\mathit{soc}`$ | `StorageUnit_state_of_charge` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-state_of_charge` — energy held at the end of a snapshot | | $`\mathit{spill}`$ | `StorageUnit_spill` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$, `neutral` where the mask leaves it out — `StorageUnit-spill` — inflow passed on unused. Zero where there is no inflow, so the balance keeps its row there; the bounds are PyPSA's, on the variable rather than as rows | -| $`H`$ | `StorageUnit_p_nom_ext` over $`\mathcal{S}`$ — `StorageUnit-p_nom` — nominal power where it is a decision, for a storage unit that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`N^{h}`$ | `StorageUnit_n_mod` over $`\mathcal{S}`$ — `StorageUnit-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`\mathit{soc}`$ | `StorageUnit_state_of_charge` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — `StorageUnit-state_of_charge` — energy held at the end of a snapshot | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{StorageUnit\_additions}`$ | `StorageUnit_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{StorageUnit\_capex}`$ | `StorageUnit_capex` (scalar) | | $`\overleftarrow{\mathit{soc}}`$ | `StorageUnit_charge_carried_in` over $`\Xi \times \mathcal{T} \times \mathcal{S}`$ — the charge a unit opens a snapshot with — at the first snapshot it stands in, its last such snapshot's less standing loss where it is cyclic and the given initial charge, which no standing loss has touched yet, where it is not; the previous snapshot's less standing loss otherwise. A unit built in a later period opens in that period, and a cyclic one that retires closes on its own last snapshot. Per period, the same holds with each investment period as the horizon | -| $`\mathit{last}^{h}`$ | `StorageUnit_last_counted_active` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — one at the last snapshot a row counts where a unit stands, and zero elsewhere — a unit that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:455-458`) | | $`\mathit{w}^{h}`$ | `StorageUnit_closing_weight` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — what the charge a unit holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the unit reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | -| $`\mathit{StorageUnit\_primary\_energy}`$ | `StorageUnit_primary_energy` over $`\mathcal{G} \times \Xi`$ | +| $`\mathit{StorageUnit\_injection}`$ | `StorageUnit_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{last}^{h}`$ | `StorageUnit_last_counted_active` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{S}`$ — one at the last snapshot a row counts where a unit stands, and zero elsewhere — a unit that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:455-458`) | | $`\mathit{StorageUnit\_operational\_limit}`$ | `StorageUnit_operational_limit` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{StorageUnit\_tech\_capacity\_expansion}`$ | `StorageUnit_tech_capacity_expansion` over $`\mathcal{G}`$ | | $`\mathit{StorageUnit\_opex}`$ | `StorageUnit_opex` over $`\Xi`$ | -| $`\mathit{StorageUnit\_capex}`$ | `StorageUnit_capex` (scalar) | -| $`\mathit{StorageUnit\_additions}`$ | `StorageUnit_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{StorageUnit\_injection}`$ | `StorageUnit_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{StorageUnit\_primary\_energy}`$ | `StorageUnit_primary_energy` over $`\mathcal{G} \times \Xi`$ | +| $`\mathit{StorageUnit\_tech\_capacity\_expansion}`$ | `StorageUnit_tech_capacity_expansion` over $`\mathcal{G}`$ | #### Notation @@ -654,36 +654,42 @@ assumptions: #### Conditions -**`StorageUnit_fix`** +**`StorageUnit_ext`** ```math -\mathrm{on}^{h,\mathrm{fix}}_{t,s} \iff \neg \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} +\mathrm{on}^{h,\mathrm{ext}}_{t,s} \iff \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} ``` -**`StorageUnit_ext`** +**`StorageUnit_fix`** ```math -\mathrm{on}^{h,\mathrm{ext}}_{t,s} \iff \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} +\mathrm{on}^{h,\mathrm{fix}}_{t,s} \iff \neg \mathrm{ext}^{h}_{s} \wedge \mathrm{on}^{h}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} ``` #### Variable domains +**`StorageUnit_n_mod`** + +```math +N^{h}_{s} \ge 0, N^{h}_{s} \in \mathbb{Z} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} +``` + **`StorageUnit_p_dispatch`** ```math h^{+}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_p_store`** +**`StorageUnit_p_nom_ext`** ```math -h^{-}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +H_{s} \in \mathbb{R} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} ``` -**`StorageUnit_state_of_charge`** +**`StorageUnit_p_store`** ```math -\mathit{soc}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +h^{-}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` **`StorageUnit_spill`** @@ -692,54 +698,54 @@ h^{-}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T}, 0 \le \mathit{spill}_{\xi,t,s} \le \mathrm{inflow}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{inflow}_{\xi,t,s} > 0 \wedge \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_p_nom_ext`** +**`StorageUnit_state_of_charge`** ```math -H_{s} \in \mathbb{R} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} +\mathit{soc}_{\xi,t,s} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_n_mod`** +#### Definitions + +**`StorageUnit_additions`** ```math -N^{h}_{s} \ge 0, N^{h}_{s} \in \mathbb{Z} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} +\mathit{StorageUnit\_additions}_{i,y} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_carrier}(s) = i} H_{s} \cdot \mathrm{new}^{h}_{y,s} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -#### Definitions - -**`StorageUnit_charge_carried_in`** +**`StorageUnit_capex`** ```math -\overleftarrow{\mathit{soc}}_{\xi,t,s} = \begin{cases} \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,\left( t \ominus \mathrm{idle} \right) \ominus 1,s} & \text{if } \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \neg \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,s} & \text{if } \mathrm{cyc}^{y}_{\xi,s} \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \mathrm{reset}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t - 1,s} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\mathit{StorageUnit\_capex} = \sum_{\xi \in \Xi,\ s \in \mathcal{S}} \pi_{\xi} \cdot H_{s} \cdot \mathrm{c}^{\mathrm{cap},h}_{\xi,s} \cdot \mathrm{W}^{h}_{s} ``` -**`StorageUnit_last_counted_active`** +**`StorageUnit_charge_carried_in`** ```math -\mathit{last}^{h}_{g,\xi,t,s} = \begin{cases} 1 & \text{if } \mathrm{in}_{g,\xi,t} \wedge \mathrm{on}^{h}_{t,s} \wedge \neg \left( \mathrm{in}_{g,\xi,t + 1} \wedge \mathrm{on}^{h}_{t + 1,s} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\overleftarrow{\mathit{soc}}_{\xi,t,s} = \begin{cases} \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,\left( t \ominus \mathrm{idle} \right) \ominus 1,s} & \text{if } \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \neg \mathrm{cyc}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}_{t,s} \right) \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,s} & \text{if } \mathrm{cyc}^{y}_{\xi,s} \\ \mathrm{soc}^{0}_{\xi,s} & \text{if } \mathrm{reset}_{\xi,s} \wedge \neg \mathrm{cyc}^{y}_{\xi,s} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho_{\xi,t,s} \cdot \mathit{soc}_{\xi,t - 1,s} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` **`StorageUnit_closing_weight`** ```math -\mathit{w}^{h}_{g,\xi,t,s} = \begin{cases} \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{g,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ \mathit{last}^{h}_{g,\xi,t,s} & \text{if } \neg \mathrm{reset}_{\xi,s} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} +\mathit{w}^{h}_{g,\xi,t,s} = \begin{cases} \mathit{last}^{h}_{g,\xi,t,s} & \text{if } \neg \mathrm{reset}_{\xi,s} \\ \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{g,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` -**`StorageUnit_primary_energy`** +**`StorageUnit_injection`** ```math -\mathit{StorageUnit\_primary\_energy}_{g,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{g,\xi,t,s} \cdot \mathrm{a}^{h}_{g,\xi,s} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{StorageUnit\_injection}_{n,\xi,t} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`StorageUnit_operational_limit`** +**`StorageUnit_last_counted_active`** ```math -\mathit{StorageUnit\_operational\_limit}_{g,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{g,\xi,t,s} \cdot \mathrm{b}^{h}_{g,\xi,s} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{last}^{h}_{g,\xi,t,s} = \begin{cases} 1 & \text{if } \mathrm{in}_{g,\xi,t} \wedge \mathrm{on}^{h}_{t,s} \wedge \neg \left( \mathrm{in}_{g,\xi,t + 1} \wedge \mathrm{on}^{h}_{t + 1,s} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} ``` -**`StorageUnit_tech_capacity_expansion`** +**`StorageUnit_operational_limit`** ```math -\mathit{StorageUnit\_tech\_capacity\_expansion}_{g} = \sum_{s \in \mathcal{S}} H_{s} \cdot \mathrm{m}^{h}_{g,s} \qquad \forall\, g \in \mathcal{G} +\mathit{StorageUnit\_operational\_limit}_{g,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{g,\xi,t,s} \cdot \mathrm{b}^{h}_{g,\xi,s} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` **`StorageUnit_opex`** @@ -748,114 +754,114 @@ N^{h}_{s} \ge 0, N^{h}_{s} \in \mathbb{Z} \qquad \forall\, s \in \mathcal{S} \,: \mathit{StorageUnit\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} h^{+}_{\xi,t,s} \cdot h^{+}_{\xi,t,s} \cdot \mathrm{c}^{h,(2)}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{soc}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{soc}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{s \in \mathcal{S}} \mathit{spill}_{\xi,t,s} \cdot \mathrm{c}^{\mathrm{spill}}_{\xi,t,s} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -**`StorageUnit_capex`** +**`StorageUnit_primary_energy`** ```math -\mathit{StorageUnit\_capex} = \sum_{\xi \in \Xi,\ s \in \mathcal{S}} \pi_{\xi} \cdot H_{s} \cdot \mathrm{c}^{\mathrm{cap},h}_{\xi,s} \cdot \mathrm{W}^{h}_{s} +\mathit{StorageUnit\_primary\_energy}_{g,\xi} = -\left( \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} \mathit{soc}_{\xi,t,s} \cdot \mathit{w}^{h}_{g,\xi,t,s} \cdot \mathrm{a}^{h}_{g,\xi,s} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`StorageUnit_additions`** +**`StorageUnit_tech_capacity_expansion`** ```math -\mathit{StorageUnit\_additions}_{i,y} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_carrier}(s) = i} H_{s} \cdot \mathrm{new}^{h}_{y,s} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{StorageUnit\_tech\_capacity\_expansion}_{g} = \sum_{s \in \mathcal{S}} H_{s} \cdot \mathrm{m}^{h}_{g,s} \qquad \forall\, g \in \mathcal{G} ``` -**`StorageUnit_injection`** +#### Subject to + +**`StorageUnit_energy_balance`** ```math -\mathit{StorageUnit\_injection}_{n,\xi,t} = \sum_{s \in \mathcal{S} \,:\, \mathrm{StorageUnit\_bus}(s) = n} \mathrm{sgn}^{h}_{s} \cdot \left( h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{soc}_{\xi,t,s} = \overleftarrow{\mathit{soc}}_{\xi,t,s} + \eta^{-}_{\xi,t,s} \cdot h^{-}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t} - \frac{h^{+}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t}}{\eta^{+}_{\xi,t,s}} + \left( \mathrm{inflow}_{\xi,t,s} - \mathit{spill}_{\xi,t,s} \right) \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} ``` -#### Subject to - -**`StorageUnit_fix_p_dispatch_lower`** +**`StorageUnit_ext_p_dispatch_lower`** ```math -h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_fix_p_dispatch_upper`** +**`StorageUnit_ext_p_dispatch_upper`** ```math -h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_fix_p_store_lower`** +**`StorageUnit_ext_p_nom_lower`** ```math -h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +H_{s} \ge \underline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} ``` -**`StorageUnit_fix_p_store_upper`** +**`StorageUnit_ext_p_nom_upper`** ```math -h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +H_{s} \le \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \text{ is defined} ``` -**`StorageUnit_fix_state_of_charge_lower`** +**`StorageUnit_ext_p_store_lower`** ```math -\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_fix_state_of_charge_upper`** +**`StorageUnit_ext_p_store_upper`** ```math -\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} +h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_ext_p_dispatch_lower`** +**`StorageUnit_ext_state_of_charge_lower`** ```math -h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_ext_p_dispatch_upper`** +**`StorageUnit_ext_state_of_charge_upper`** ```math -h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} ``` -**`StorageUnit_ext_p_store_lower`** +**`StorageUnit_fix_p_dispatch_lower`** ```math -h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +h^{+}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_ext_p_store_upper`** +**`StorageUnit_fix_p_dispatch_upper`** ```math -h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +h^{+}_{\xi,t,s} \le \overline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_ext_state_of_charge_lower`** +**`StorageUnit_fix_p_store_lower`** ```math -\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +h^{-}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_ext_state_of_charge_upper`** +**`StorageUnit_fix_p_store_upper`** ```math -\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot H_{s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{ext}}_{t,s} +h^{-}_{\xi,t,s} \le -\underline{\mathrm{h}}_{\xi,t,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_ext_p_nom_lower`** +**`StorageUnit_fix_state_of_charge_lower`** ```math -H_{s} \ge \underline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} +\mathit{soc}_{\xi,t,s} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_ext_p_nom_upper`** +**`StorageUnit_fix_state_of_charge_upper`** ```math -H_{s} \le \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \overline{\mathrm{h}}^{\mathrm{nom}}_{\xi,s} \text{ is defined} +\mathit{soc}_{\xi,t,s} \le \mathrm{T}^{h}_{\xi,s} \cdot \mathrm{h}^{\mathrm{nom}}_{\xi,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h,\mathrm{fix}}_{t,s} ``` -**`StorageUnit_p_nom_set`** +**`StorageUnit_p_dispatch_set`** ```math -H_{s} = \mathrm{h}^{\mathrm{nom,set}}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \mathrm{h}^{\mathrm{nom,set}}_{s} \text{ is defined} +h^{+}_{\xi,t,s} = \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` **`StorageUnit_p_nom_modularity`** @@ -864,10 +870,10 @@ H_{s} = \mathrm{h}^{\mathrm{nom,set}}_{s} \qquad \forall\, s \in \mathcal{S} \,: H_{s} = \mathrm{h}^{\mathrm{mod}}_{s} \cdot N^{h}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{h}^{\mathrm{mod}}_{s} > 0 \wedge \mathrm{act}^{h}_{s} ``` -**`StorageUnit_energy_balance`** +**`StorageUnit_p_nom_set`** ```math -\mathit{soc}_{\xi,t,s} = \overleftarrow{\mathit{soc}}_{\xi,t,s} + \eta^{-}_{\xi,t,s} \cdot h^{-}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t} - \frac{h^{+}_{\xi,t,s} \cdot \mathrm{w}^{\mathrm{sto}}_{t}}{\eta^{+}_{\xi,t,s}} + \left( \mathrm{inflow}_{\xi,t,s} - \mathit{spill}_{\xi,t,s} \right) \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} +H_{s} = \mathrm{h}^{\mathrm{nom,set}}_{s} \qquad \forall\, s \in \mathcal{S} \,:\, \mathrm{ext}^{h}_{s} \wedge \mathrm{act}^{h}_{s} \wedge \mathrm{h}^{\mathrm{nom,set}}_{s} \text{ is defined} ``` **`StorageUnit_p_set`** @@ -876,12 +882,6 @@ H_{s} = \mathrm{h}^{\mathrm{mod}}_{s} \cdot N^{h}_{s} \qquad \forall\, s \in \ma h^{+}_{\xi,t,s} - h^{-}_{\xi,t,s} = \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} ``` -**`StorageUnit_p_dispatch_set`** - -```math -h^{+}_{\xi,t,s} = \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{h}^{+,\mathrm{set}}_{\xi,t,s} \text{ is defined} \wedge \mathrm{on}^{h}_{t,s} -``` - **`StorageUnit_p_store_set`** ```math @@ -896,10 +896,10 @@ h^{-}_{\xi,t,s} = \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in #### Assumptions -**`StorageUnit_stands_in_one_run`** +**`StorageUnit_marginal_cost_quadratic_without_risk_preference`** ```math -\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \} \rvert \le 1 \qquad \forall\, s \in \mathcal{S} +\mathrm{c}^{h,(2)}_{\xi,t,s} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \omega \text{ is defined} ``` **`StorageUnit_opens_late_only_where_it_opens`** @@ -914,10 +914,10 @@ h^{-}_{\xi,t,s} = \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \mathrm{open}_{t,s} \qquad \forall\, t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \wedge \mathrm{pos}(t) > 0 ``` -**`StorageUnit_primary_energy_per_period_closes_over_the_horizon`** +**`StorageUnit_operational_limit_carried_over_has_unit_years`** ```math -\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{g,\xi,t} \} \rvert = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{g,\xi,s} \text{ is defined} \wedge \mathrm{reset}_{\xi,s} +\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{b}^{h}_{g,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{g,\xi,t} ``` **`StorageUnit_primary_energy_carried_over_has_unit_years`** @@ -926,15 +926,15 @@ h^{-}_{\xi,t,s} = \mathrm{h}^{-,\mathrm{set}}_{\xi,t,s} \qquad \forall\, \xi \in \mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, g \in \mathcal{G},\ y \in \mathcal{Y},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{g,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} ``` -**`StorageUnit_operational_limit_carried_over_has_unit_years`** +**`StorageUnit_primary_energy_per_period_closes_over_the_horizon`** ```math -\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \mathrm{b}^{h}_{g,\xi,s} \text{ is defined} \wedge \neg \mathrm{reset}_{\xi,s} \wedge \mathrm{in}_{g,\xi,t} +\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{g,\xi,t} \} \rvert = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ s \in \mathcal{S} \,:\, \mathrm{a}^{h}_{g,\xi,s} \text{ is defined} \wedge \mathrm{reset}_{\xi,s} ``` -**`StorageUnit_marginal_cost_quadratic_without_risk_preference`** +**`StorageUnit_stands_in_one_run`** ```math -\mathrm{c}^{h,(2)}_{\xi,t,s} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ s \in \mathcal{S} \,:\, \omega \text{ is defined} +\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{h}_{t,s} \wedge \neg \mathrm{on}^{h}_{t - 1,s} \} \rvert \le 1 \qquad \forall\, s \in \mathcal{S} ``` diff --git a/docs/examples/pypsa/store.md b/docs/examples/pypsa/store.md index 845276d6..86b68ed6 100644 --- a/docs/examples/pypsa/store.md +++ b/docs/examples/pypsa/store.md @@ -424,32 +424,32 @@ assumptions: | Symbol | Meaning | |---|---| -| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | -| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\omega`$ | `CVaR_omega` (scalar), data another file declares | +| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | | $`\mathrm{w}^{y}`$ | `period_weight_objective` over $`\mathcal{Y}`$, data another file declares | | $`\mathrm{w}^{\mathrm{yr}}`$ | `period_weight_years` over $`\mathcal{Y}`$, data another file declares | +| $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | +| $`\mathrm{w}`$ | `snapshot_weightings_objective` over $`\mathcal{T}`$, data another file declares | | $`\mathrm{w}^{\mathrm{sto}}`$ | `snapshot_weightings_stores` over $`\mathcal{T}`$, data another file declares | -| $`\mathrm{in}`$ | `GlobalConstraint_counts_snapshot` over $`\mathcal{G} \times \Xi \times \mathcal{T}`$, data another file declares | -| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Store_primary_energy` to | +| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Store_injection` to | +| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Store_additions` to | | $`\mathit{operational\_limit}`$ | `operational_limit` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Store_operational_limit` to | -| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Store_tech_capacity_expansion` to | +| $`\mathit{primary\_energy}`$ | `primary_energy` over $`\mathcal{G} \times \Xi`$, an expression this file adds `Store_primary_energy` to | | $`\mathit{scenario\_opex}`$ | `scenario_opex` over $`\Xi`$, an expression this file adds `Store_opex` to | +| $`\mathit{tech\_capacity\_expansion}`$ | `tech_capacity_expansion` over $`\mathcal{G}`$, an expression this file adds `Store_tech_capacity_expansion` to | | $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Store_capex` to | -| $`\mathit{Carrier\_additions}`$ | `Carrier_additions` over $`\mathcal{I} \times \mathcal{Y}`$, an expression this file adds `Store_additions` to | -| $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Store_injection` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{V}`$ | index $`v`$ — `store` with $`\mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I},\ \mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N}`$ — pure energy stores, each on one bus | +| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | | $`\mathcal{G}`$ | index $`g`$ — `global_constraint` — PyPSA's `GlobalConstraint` rows, one label per declared limit | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | -| $`\mathcal{I}`$ | index $`i`$ — `carrier` with $`\mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — energy carriers, what a growth limit is set per | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | +| $`\mathcal{V}`$ | index $`v`$ — `store` with $`\mathrm{Store\_bus}: \mathcal{V} \to \mathcal{N},\ \mathrm{Store\_carrier}: \mathcal{V} \to \mathcal{I}`$ — pure energy stores, each on one bus | #### Parameters @@ -457,32 +457,32 @@ assumptions: |---|---| | $`\mathrm{on}^{e}`$ | `Store_active` over $`\mathcal{T} \times \mathcal{V}`$ — whether a store stands in a snapshot's period — PyPSA's `active`, data prep | | $`\mathrm{act}^{e}`$ | `Store_active_asset` over $`\mathcal{V}`$ — whether a store 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}^{e}`$ | `Store_capital_weight` over $`\mathcal{V}`$ — the sum of period weights a store stands in — PyPSA's `active * period_weighting`, summed, data prep | -| $`\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`) | -| $`\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}`$, `neutral` 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}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\underline{\mathrm{e}}`$ | `Store_e_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — least energy held, per unit of nominal capacity — negative for a store that may go short | -| $`\overline{\mathrm{e}}`$ | `Store_e_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — most energy held, per unit of nominal capacity | -| $`\mathrm{sgn}^{q}`$ | `Store_sign` over $`\mathcal{V}`$ — the sign the power a store delivers enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | -| $`\rho^{e}`$ | `Store_retention` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — share of energy kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | -| $`\mathrm{e}^{0}`$ | `Store_e_initial` over $`\Xi \times \mathcal{V}`$ — energy held before the first snapshot | +| $`\mathrm{W}^{e}`$ | `Store_capital_weight` over $`\mathcal{V}`$ — the sum of period weights a store stands in — PyPSA's `active * period_weighting`, summed, data prep | | $`\mathrm{cyc}^{e}`$ | `Store_e_cyclic` over $`\Xi \times \mathcal{V}`$ — whether the horizon closes on itself instead of opening on the initial energy | | $`\mathrm{cyc}^{e,y}`$ | `Store_e_cyclic_per_period` over $`\Xi \times \mathcal{V}`$ — whether each investment period closes on itself instead of carrying its energy on to the next; it overrides `e_cyclic` and `e_initial_per_period`. PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | +| $`\mathrm{e}^{0}`$ | `Store_e_initial` over $`\Xi \times \mathcal{V}`$ — energy held before the first snapshot | | $`\mathrm{reset}^{e}`$ | `Store_e_initial_per_period` over $`\Xi \times \mathcal{V}`$ — whether each investment period opens on the initial energy instead of carrying the previous period's; PyPSA reads it only under `multi_investment_periods`, so data prep feeds false otherwise | -| $`\mathrm{open}^{e}`$ | `Store_opens_late` over $`\mathcal{T} \times \mathcal{V}`$ — whether a snapshot is the first a store stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every store stands throughout | +| $`\overline{\mathrm{e}}`$ | `Store_e_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — most energy held, per unit of nominal capacity | +| $`\underline{\mathrm{e}}`$ | `Store_e_min_pu` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — least energy held, per unit of nominal capacity — negative for a store that may go short | +| $`\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 | +| $`\overline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_max` over $`\Xi \times \mathcal{V}`$ — most nominal capacity an extendable store may be built at | +| $`\underline{\mathrm{e}}^{\mathrm{nom}}`$ | `Store_e_nom_min` over $`\Xi \times \mathcal{V}`$ — least nominal capacity an extendable store may be built at | +| $`\mathrm{e}^{\mathrm{mod}}`$ | `Store_e_nom_mod` over $`\mathcal{V}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | +| $`\mathrm{e}^{\mathrm{nom,set}}`$ | `Store_e_nom_set` over $`\mathcal{V}`$, `neutral` 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{set}}`$ | `Store_e_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `neutral` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\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{idle}^{e}`$ | `Store_inactive_snapshots` over $`\mathcal{V}`$ — how many snapshots a store does not stand in — PyPSA's `(~active).sum()`, data prep. A cyclic store reaches back this many snapshots further, so it closes on the last snapshot it stands in | | $`\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}`$, `neutral` where the data has no row — a given energy schedule; a store without one has no row here | +| $`\mathrm{open}^{e}`$ | `Store_opens_late` over $`\mathcal{T} \times \mathcal{V}`$ — whether a snapshot is the first a store stands in, where that is not the first of the horizon — PyPSA's `active.cumsum() == 1` over the snapshots it stands in, past the first snapshot, data prep; false in a run where every store stands throughout | +| $`\mathrm{b}^{e}`$ | `Store_operational_limit_weight` over $`\mathcal{G} \times \Xi \times \mathcal{V}`$, `neutral` 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{q}^{\mathrm{set}}`$ | `Store_p_set` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{V}`$, `neutral` 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 $`\mathcal{G} \times \Xi \times \mathcal{V}`$, `neutral` where the data has no row — one where the store is in the row's set — data prep; one outside it has no row | +| $`\rho^{e}`$ | `Store_retention` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — share of energy kept over a snapshot — PyPSA's `(1 - standing_loss) ** elapsed hours`, data prep | +| $`\mathrm{sgn}^{q}`$ | `Store_sign` over $`\mathcal{V}`$ — the sign the power a store delivers enters its bus's balance with — PyPSA's `sign`, `1` unless given. PyPSA refuses one that differs by scenario (`constants.py:43`) | | $`\mathrm{m}^{e}`$ | `Store_tech_capacity_weight` over $`\mathcal{G} \times \mathcal{V}`$, `neutral` 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 @@ -490,24 +490,24 @@ assumptions: | Symbol | Meaning | |---|---| | $`e`$ | `Store_e` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-e` — energy held at the end of a snapshot | -| $`q`$ | `Store_p` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-p` — power delivered to the bus; charging is negative | | $`E`$ | `Store_e_nom_ext` over $`\mathcal{V}`$ — `Store-e_nom` — nominal capacity where it is a decision, for a store that is active; the parameter of the same PyPSA name carries the fixed regime | | $`N^{e}`$ | `Store_n_mod` over $`\mathcal{V}`$ — `Store-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | +| $`q`$ | `Store_p` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — `Store-p` — power delivered to the bus; charging is negative | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{Store\_additions}`$ | `Store_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | +| $`\mathit{Store\_capex}`$ | `Store_capex` (scalar) | +| $`\mathit{w}^{e}`$ | `Store_closing_weight` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — what the energy a store holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the store reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | | $`\overleftarrow{e}`$ | `Store_energy_carried_in` over $`\Xi \times \mathcal{T} \times \mathcal{V}`$ — the energy a store opens a snapshot with — at the first snapshot it stands in, its last such snapshot's less standing loss where it is cyclic and the given initial energy, which no standing loss has touched yet, where it is not; the previous snapshot's less standing loss otherwise. A store built in a later period opens in that period, and a cyclic one that retires closes on its own last snapshot. Per period, the same holds with each investment period as the horizon | +| $`\mathit{Store\_injection}`$ | `Store_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | | $`\mathit{last}^{e}`$ | `Store_last_counted_active` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — one at the last snapshot a row counts where a store stands, and zero elsewhere — a store that retires before the last counted snapshot closes on its last active level, as PyPSA forward-fills the level over the counted snapshots (`global_constraints.py:507-510`) | -| $`\mathit{w}^{e}`$ | `Store_closing_weight` over $`\mathcal{G} \times \Xi \times \mathcal{T} \times \mathcal{V}`$ — what the energy a store holds at a snapshot counts for in a row as its closing level — the years of the period at the last snapshot of each counted period where the store reopens per period, one at the last counted snapshot it stands in where it does not, and nothing elsewhere | -| $`\mathit{Store\_primary\_energy}`$ | `Store_primary_energy` over $`\mathcal{G} \times \Xi`$ | | $`\mathit{Store\_operational\_limit}`$ | `Store_operational_limit` over $`\mathcal{G} \times \Xi`$ | -| $`\mathit{Store\_tech\_capacity\_expansion}`$ | `Store_tech_capacity_expansion` over $`\mathcal{G}`$ | | $`\mathit{Store\_opex}`$ | `Store_opex` over $`\Xi`$ | -| $`\mathit{Store\_capex}`$ | `Store_capex` (scalar) | -| $`\mathit{Store\_additions}`$ | `Store_additions` over $`\mathcal{I} \times \mathcal{Y}`$ | -| $`\mathit{Store\_injection}`$ | `Store_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | +| $`\mathit{Store\_primary\_energy}`$ | `Store_primary_energy` over $`\mathcal{G} \times \Xi`$ | +| $`\mathit{Store\_tech\_capacity\_expansion}`$ | `Store_tech_capacity_expansion` over $`\mathcal{G}`$ | #### Notation @@ -527,12 +527,6 @@ assumptions: e_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} ``` -**`Store_p`** - -```math -q_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} -``` - **`Store_e_nom_ext`** ```math @@ -545,128 +539,134 @@ E_{v} \in \mathbb{R} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{ N^{e}_{v} \ge 0, N^{e}_{v} \in \mathbb{Z} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} ``` +**`Store_p`** + +```math +q_{\xi,t,v} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} +``` + #### Definitions -**`Store_energy_carried_in`** +**`Store_additions`** ```math -\overleftarrow{e}_{\xi,t,v} = \begin{cases} \rho^{e}_{\xi,t,v} \cdot e_{\xi,\left( t \ominus \mathrm{idle}^{e} \right) \ominus 1,v} & \text{if } \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \neg \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,v} & \text{if } \mathrm{cyc}^{e,y}_{\xi,v} \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t - 1,v} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\mathit{Store\_additions}_{i,y} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_carrier}(v) = i} E_{v} \cdot \mathrm{new}^{e}_{y,v} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} ``` -**`Store_last_counted_active`** +**`Store_capex`** ```math -\mathit{last}^{e}_{g,\xi,t,v} = \begin{cases} 1 & \text{if } \mathrm{in}_{g,\xi,t} \wedge \mathrm{on}^{e}_{t,v} \wedge \neg \left( \mathrm{in}_{g,\xi,t + 1} \wedge \mathrm{on}^{e}_{t + 1,v} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\mathit{Store\_capex} = \sum_{\xi \in \Xi,\ v \in \mathcal{V}} \pi_{\xi} \cdot E_{v} \cdot \mathrm{c}^{\mathrm{cap},e}_{\xi,v} \cdot \mathrm{W}^{e}_{v} ``` **`Store_closing_weight`** ```math -\mathit{w}^{e}_{g,\xi,t,v} = \begin{cases} \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{g,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ \mathit{last}^{e}_{g,\xi,t,v} & \text{if } \neg \mathrm{reset}^{e}_{\xi,v} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} +\mathit{w}^{e}_{g,\xi,t,v} = \begin{cases} \mathit{last}^{e}_{g,\xi,t,v} & \text{if } \neg \mathrm{reset}^{e}_{\xi,v} \\ \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{g,\xi,t} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = \lvert \mathcal{T}_{\mathrm{snapshot\_period}(t)} \rvert - 1 \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} ``` -**`Store_primary_energy`** +**`Store_energy_carried_in`** ```math -\mathit{Store\_primary\_energy}_{g,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{g,\xi,t,v} \cdot \mathrm{a}^{e}_{g,\xi,v} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\overleftarrow{e}_{\xi,t,v} = \begin{cases} \rho^{e}_{\xi,t,v} \cdot e_{\xi,\left( t \ominus \mathrm{idle}^{e} \right) \ominus 1,v} & \text{if } \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \neg \mathrm{cyc}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \left( \mathrm{pos}(t) = 0 \vee \mathrm{open}^{e}_{t,v} \right) \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t \ominus^{\mathrm{snapshot\_period}(t)} 1,v} & \text{if } \mathrm{cyc}^{e,y}_{\xi,v} \\ \mathrm{e}^{0}_{\xi,v} & \text{if } \mathrm{reset}^{e}_{\xi,v} \wedge \neg \mathrm{cyc}^{e,y}_{\xi,v} \wedge \mathrm{pos}_{\mathrm{snapshot\_period}(t)}(t) = 0 \\ \rho^{e}_{\xi,t,v} \cdot e_{\xi,t - 1,v} & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} ``` -**`Store_operational_limit`** +**`Store_injection`** ```math -\mathit{Store\_operational\_limit}_{g,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{g,\xi,t,v} \cdot \mathrm{b}^{e}_{g,\xi,v} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi +\mathit{Store\_injection}_{n,\xi,t} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Store_tech_capacity_expansion`** +**`Store_last_counted_active`** ```math -\mathit{Store\_tech\_capacity\_expansion}_{g} = \sum_{v \in \mathcal{V}} E_{v} \cdot \mathrm{m}^{e}_{g,v} \qquad \forall\, g \in \mathcal{G} +\mathit{last}^{e}_{g,\xi,t,v} = \begin{cases} 1 & \text{if } \mathrm{in}_{g,\xi,t} \wedge \mathrm{on}^{e}_{t,v} \wedge \neg \left( \mathrm{in}_{g,\xi,t + 1} \wedge \mathrm{on}^{e}_{t + 1,v} \right) \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} ``` -**`Store_opex`** +**`Store_operational_limit`** ```math -\mathit{Store\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot \mathrm{c}^{q}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot q_{\xi,t,v} \cdot \mathrm{c}^{q,(2)}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} e_{\xi,t,v} \cdot \mathrm{c}^{e}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi +\mathit{Store\_operational\_limit}_{g,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{g,\xi,t,v} \cdot \mathrm{b}^{e}_{g,\xi,v} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Store_capex`** +**`Store_opex`** ```math -\mathit{Store\_capex} = \sum_{\xi \in \Xi,\ v \in \mathcal{V}} \pi_{\xi} \cdot E_{v} \cdot \mathrm{c}^{\mathrm{cap},e}_{\xi,v} \cdot \mathrm{W}^{e}_{v} +\mathit{Store\_opex}_{\xi} = \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot \mathrm{c}^{q}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} q_{\xi,t,v} \cdot q_{\xi,t,v} \cdot \mathrm{c}^{q,(2)}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} + \sum_{t \in \mathcal{T}} \sum_{v \in \mathcal{V}} e_{\xi,t,v} \cdot \mathrm{c}^{e}_{\xi,t,v} \cdot \mathrm{w}_{t} \cdot \mathrm{w}^{y}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, \xi \in \Xi ``` -**`Store_additions`** +**`Store_primary_energy`** ```math -\mathit{Store\_additions}_{i,y} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_carrier}(v) = i} E_{v} \cdot \mathrm{new}^{e}_{y,v} \qquad \forall\, i \in \mathcal{I},\ y \in \mathcal{Y} +\mathit{Store\_primary\_energy}_{g,\xi} = -\left( \sum_{v \in \mathcal{V}} \sum_{t \in \mathcal{T}} e_{\xi,t,v} \cdot \mathit{w}^{e}_{g,\xi,t,v} \cdot \mathrm{a}^{e}_{g,\xi,v} \right) \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi ``` -**`Store_injection`** +**`Store_tech_capacity_expansion`** ```math -\mathit{Store\_injection}_{n,\xi,t} = \sum_{v \in \mathcal{V} \,:\, \mathrm{Store\_bus}(v) = n} \mathrm{sgn}^{q}_{v} \cdot q_{\xi,t,v} \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} +\mathit{Store\_tech\_capacity\_expansion}_{g} = \sum_{v \in \mathcal{V}} E_{v} \cdot \mathrm{m}^{e}_{g,v} \qquad \forall\, g \in \mathcal{G} ``` #### Subject to -**`Store_fix_e_lower`** +**`Store_e_nom_modularity`** ```math -e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +E_{v} = \mathrm{e}^{\mathrm{mod}}_{v} \cdot N^{e}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} ``` -**`Store_fix_e_upper`** +**`Store_e_nom_set`** ```math -e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +E_{v} = \mathrm{e}^{\mathrm{nom,set}}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \mathrm{e}^{\mathrm{nom,set}}_{v} \text{ is defined} ``` -**`Store_ext_e_lower`** +**`Store_e_set`** ```math -e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +e_{\xi,t,v} = \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \text{ is defined} \wedge \mathrm{on}^{e}_{t,v} ``` -**`Store_ext_e_upper`** +**`Store_energy_balance`** ```math -e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} +e_{\xi,t,v} = \overleftarrow{e}_{\xi,t,v} - q_{\xi,t,v} \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} ``` -**`Store_ext_e_nom_lower`** +**`Store_ext_e_lower`** ```math -E_{v} \ge \underline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} +e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -**`Store_ext_e_nom_upper`** +**`Store_ext_e_nom_lower`** ```math -E_{v} \le \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \text{ is defined} +E_{v} \ge \underline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} ``` -**`Store_e_nom_set`** +**`Store_ext_e_nom_upper`** ```math -E_{v} = \mathrm{e}^{\mathrm{nom,set}}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \mathrm{e}^{\mathrm{nom,set}}_{v} \text{ is defined} +E_{v} \le \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{act}^{e}_{v} \wedge \overline{\mathrm{e}}^{\mathrm{nom}}_{\xi,v} \text{ is defined} ``` -**`Store_e_nom_modularity`** +**`Store_ext_e_upper`** ```math -E_{v} = \mathrm{e}^{\mathrm{mod}}_{v} \cdot N^{e}_{v} \qquad \forall\, v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{e}^{\mathrm{mod}}_{v} > 0 \wedge \mathrm{act}^{e}_{v} +e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot E_{v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -**`Store_energy_balance`** +**`Store_fix_e_lower`** ```math -e_{\xi,t,v} = \overleftarrow{e}_{\xi,t,v} - q_{\xi,t,v} \cdot \mathrm{w}^{\mathrm{sto}}_{t} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} +e_{\xi,t,v} \ge \underline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` -**`Store_e_set`** +**`Store_fix_e_upper`** ```math -e_{\xi,t,v} = \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{e}^{\mathrm{set}}_{\xi,t,v} \text{ is defined} \wedge \mathrm{on}^{e}_{t,v} +e_{\xi,t,v} \le \overline{\mathrm{e}}_{\xi,t,v} \cdot \mathrm{e}^{\mathrm{nom}}_{\xi,v} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \neg \mathrm{ext}^{e}_{v} \wedge \mathrm{on}^{e}_{t,v} ``` **`Store_p_set`** @@ -677,10 +677,10 @@ q_{\xi,t,v} = \mathrm{q}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ #### Assumptions -**`Store_stands_in_one_run`** +**`Store_marginal_cost_quadratic_without_risk_preference`** ```math -\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \} \rvert \le 1 \qquad \forall\, v \in \mathcal{V} +\mathrm{c}^{q,(2)}_{\xi,t,v} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \omega \text{ is defined} ``` **`Store_opens_late_only_where_it_opens`** @@ -695,10 +695,10 @@ q_{\xi,t,v} = \mathrm{q}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ \mathrm{open}^{e}_{t,v} \qquad \forall\, t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \wedge \mathrm{pos}(t) > 0 ``` -**`Store_primary_energy_per_period_closes_over_the_horizon`** +**`Store_operational_limit_carried_over_has_unit_years`** ```math -\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{g,\xi,t} \} \rvert = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{g,\xi,v} \text{ is defined} \wedge \mathrm{reset}^{e}_{\xi,v} +\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{b}^{e}_{g,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{g,\xi,t} ``` **`Store_primary_energy_carried_over_has_unit_years`** @@ -707,15 +707,15 @@ q_{\xi,t,v} = \mathrm{q}^{\mathrm{set}}_{\xi,t,v} \qquad \forall\, \xi \in \Xi,\ \mathrm{w}^{\mathrm{yr}}_{y} = 1 \qquad \forall\, g \in \mathcal{G},\ y \in \mathcal{Y},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{g,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} ``` -**`Store_operational_limit_carried_over_has_unit_years`** +**`Store_primary_energy_per_period_closes_over_the_horizon`** ```math -\mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} = 1 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \mathrm{b}^{e}_{g,\xi,v} \text{ is defined} \wedge \neg \mathrm{reset}^{e}_{\xi,v} \wedge \mathrm{in}_{g,\xi,t} +\lvert \{ t \in \mathcal{T} \,:\, \neg \mathrm{in}_{g,\xi,t} \} \rvert = 0 \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ v \in \mathcal{V} \,:\, \mathrm{a}^{e}_{g,\xi,v} \text{ is defined} \wedge \mathrm{reset}^{e}_{\xi,v} ``` -**`Store_marginal_cost_quadratic_without_risk_preference`** +**`Store_stands_in_one_run`** ```math -\mathrm{c}^{q,(2)}_{\xi,t,v} = 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ v \in \mathcal{V} \,:\, \omega \text{ is defined} +\lvert \{ t \in \mathcal{T} \,:\, \mathrm{on}^{e}_{t,v} \wedge \neg \mathrm{on}^{e}_{t - 1,v} \} \rvert \le 1 \qquad \forall\, v \in \mathcal{V} ``` diff --git a/docs/examples/pypsa/transformer.md b/docs/examples/pypsa/transformer.md index a2251339..6a7f9d9a 100644 --- a/docs/examples/pypsa/transformer.md +++ b/docs/examples/pypsa/transformer.md @@ -374,21 +374,21 @@ constraints: |---|---| | $`\pi`$ | `scenario_weight` over $`\Xi`$, data another file declares | | $`\mathrm{lossy}`$ | `transmission_losses` (scalar), data another file declares | -| $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Transformer_capex` to | | $`\mathit{Bus\_injection}`$ | `Bus_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$, an expression this file adds `Transformer_injection` to | | $`\mathit{Cycle\_angle\_sum}`$ | `Cycle_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$, an expression this file adds `Transformer_angle_sum` to | +| $`\mathit{total\_cost}`$ | `total_cost` (scalar), an expression this file adds `Transformer_capex` to | #### Sets | Symbol | Meaning | |---|---| -| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | | $`\mathcal{N}`$ | index $`n`$ — `bus` with $`\mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$ — network nodes | -| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$ — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | | $`\mathcal{C}`$ | index $`c`$ — `cycle` — independent cycles of the passive network graph — the cycle basis, data prep. Each period has its own basis, of the branches that stand in it; a label is a position in that period's basis, so one label names a different cycle in another period | -| $`\mathcal{S}`$ | index $`s`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | | $`\mathcal{Y}`$ | index $`y`$ — `period` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — investment periods — PyPSA's `investment_periods` | +| $`\Xi`$ | index $`\xi`$ — `scenario` — the futures dispatch is chosen in, each with a weight | +| $`\mathcal{S}`$ | index $`s`$ — `segment` — the cuts a passive branch's loss curve is held above — PyPSA's tangents, as many as its `segments` count, or its secants, as many as its tolerance loop places; none in a lossless run | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` with $`\mathrm{snapshot\_period}: \mathcal{T} \to \mathcal{Y}`$ — dispatch periods | +| $`\mathcal{M}`$ | index $`m`$ — `transformer` with $`\mathrm{Transformer\_bus0}: \mathcal{M} \to \mathcal{N},\ \mathrm{Transformer\_bus1}: \mathcal{M} \to \mathcal{N}`$ — passive branches between two buses, their flow set by impedance and tap ratio, with a phase shift fixed or optimised | #### Parameters @@ -396,28 +396,28 @@ constraints: |---|---| | $`\mathrm{on}^{\sigma}`$ | `Transformer_active` over $`\mathcal{T} \times \mathcal{M}`$ — whether a transformer stands in a snapshot's period — PyPSA's `active`, data prep | | $`\mathrm{act}^{\sigma}`$ | `Transformer_active_asset` over $`\mathcal{M}`$ — whether a transformer 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{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 | | $`\mathrm{W}^{\sigma}`$ | `Transformer_capital_weight` over $`\mathcal{M}`$ — the sum of period weights a transformer stands in — PyPSA's `active * period_weighting`, summed, data prep | +| $`\mathrm{x}^{\sigma}`$ | `Transformer_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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 | +| $`\overline{\ell}^{\sigma}`$ | `Transformer_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the loss at a transformer's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, its `r_pu_eff` the resistance over the given `s_nom` times the tap ratio, data prep | +| $`\mathrm{b}^{\sigma}`$ | `Transformer_loss_offset` over $`\Xi \times \mathcal{S} \times \mathcal{T} \times \mathcal{M}`$ — 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{a}^{\sigma}`$ | `Transformer_loss_slope` over $`\Xi \times \mathcal{S} \times \mathcal{T} \times \mathcal{M}`$ — the slope of a cut to a transformer's loss curve — a tangent's `2 * r_pu_eff * p_k`, a secant's `r_pu_eff * (p_k + p_k+1)`, as a line's, over the transformer's own `r_pu_eff` and rating, data prep | +| $`\mathrm{Transformer\_phase\_shift\_cycle\_weight}`$ | `Transformer_phase_shift_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$ — the cycle sign for a varying transformer's phase shift, times π/180 so a shift in degrees enters the cycle sum in radians — data prep; zero for a fixed transformer or one in no cycle | +| $`\varphi^{\sigma}`$ | `Transformer_phase_shift_fixed` over $`\mathcal{T} \times \mathcal{M}`$ — a fixed transformer's phase shift at each snapshot, in degrees — PyPSA's `phase_shift`, zero by default; a varying transformer's shift is a decision instead | +| $`\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 | +| $`\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\_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) | +| $`\vartheta`$ | `Transformer_phase_shift_weight` over $`\mathcal{C} \times \mathcal{T} \times \mathcal{M}`$, `neutral` 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 | +| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — most flow either way, per unit of nominal apparent power | | $`\sigma^{\mathrm{nom}}`$ | `Transformer_s_nom` over $`\Xi \times \mathcal{M}`$ — nominal apparent power | | $`\mathrm{ext}^{\sigma}`$ | `Transformer_s_nom_extendable` over $`\mathcal{M}`$ — whether the nominal apparent power is a decision | -| $`\sigma^{\mathrm{mod}}`$ | `Transformer_s_nom_mod` over $`\mathcal{M}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | -| $`\overline{\sigma}`$ | `Transformer_s_max_pu` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — most flow either way, per unit of nominal apparent power | -| $`\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 | +| $`\underline{\sigma}^{\mathrm{nom}}`$ | `Transformer_s_nom_min` over $`\Xi \times \mathcal{M}`$ — least nominal apparent power an extendable transformer may be built at | +| $`\sigma^{\mathrm{mod}}`$ | `Transformer_s_nom_mod` over $`\mathcal{M}`$, `neutral` where the data has no row — the module size a build comes in whole numbers of; no value means the build is continuous | | $`\sigma^{\mathrm{nom,set}}`$ | `Transformer_s_nom_set` over $`\mathcal{M}`$, `neutral` 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}`$, `neutral` 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}`$, `neutral` 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{C} \times \mathcal{Y} \times \mathcal{M}`$, `neutral` 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{C} \times \mathcal{T} \times \mathcal{M}`$, `neutral` 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 | -| $`\varphi^{\sigma}`$ | `Transformer_phase_shift_fixed` over $`\mathcal{T} \times \mathcal{M}`$ — a fixed transformer's phase shift at each snapshot, in degrees — PyPSA's `phase_shift`, zero by default; a varying transformer's shift is a decision instead | -| $`\mathrm{Transformer\_phase\_shift\_cycle\_weight}`$ | `Transformer_phase_shift_cycle_weight` over $`\mathcal{C} \times \mathcal{Y} \times \mathcal{M}`$ — the cycle sign for a varying transformer's phase shift, times π/180 so a shift in degrees enters the cycle sum in radians — data prep; zero for a fixed transformer or one in no cycle | -| $`\overline{\ell}^{\sigma}`$ | `Transformer_loss_max` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the loss at a transformer's rating — PyPSA's `r_pu_eff * (s_max_pu * s_nom_max)**2`, its `r_pu_eff` the resistance over the given `s_nom` times the tap ratio, data prep | -| $`\mathrm{a}^{\sigma}`$ | `Transformer_loss_slope` over $`\Xi \times \mathcal{S} \times \mathcal{T} \times \mathcal{M}`$ — the slope of a cut to a transformer's loss curve — a tangent's `2 * r_pu_eff * p_k`, a secant's `r_pu_eff * (p_k + p_k+1)`, as a line's, over the transformer's own `r_pu_eff` and rating, data prep | -| $`\mathrm{b}^{\sigma}`$ | `Transformer_loss_offset` over $`\Xi \times \mathcal{S} \times \mathcal{T} \times \mathcal{M}`$ — 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 | #### Conditions @@ -429,20 +429,20 @@ constraints: | Symbol | Meaning | |---|---| -| $`\sigma`$ | `Transformer_s` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — `Transformer-s` — PyPSA's `p0`, the flow measured at the `Transformer_bus0` end: a positive value withdraws there and injects at `Transformer_bus1`, lossless | | $`\ell^{\sigma}`$ | `Transformer_loss` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-loss` — what a transformer dissipates carrying its flow, as a line does; absent, and zero in the balance, where the network is lossless | +| $`N^{\sigma}`$ | `Transformer_n_mod` over $`\mathcal{M}`$ — `Transformer-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | | $`\mathit{Transformer\_phase\_shift}`$ | `Transformer_phase_shift` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$, `neutral` where the mask leaves it out — `Transformer-phase_shift` — a phase-shifting transformer's voltage angle shift in degrees, chosen per snapshot to redistribute the flows around its cycles without moving active power; absent, and zero in the cycle sum, where the shift is fixed | +| $`\sigma`$ | `Transformer_s` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — `Transformer-s` — PyPSA's `p0`, the flow measured at the `Transformer_bus0` end: a positive value withdraws there and injects at `Transformer_bus1`, lossless | | $`\Sigma`$ | `Transformer_s_nom_ext` over $`\mathcal{M}`$ — `Transformer-s_nom` — nominal apparent power where it is a decision, for a transformer that is active; the parameter of the same PyPSA name carries the fixed regime | -| $`N^{\sigma}`$ | `Transformer_n_mod` over $`\mathcal{M}`$ — `Transformer-n_mod` — how many modules of an extendable modular build; none for a unit that is not active | #### Definitions | Symbol | Meaning | |---|---| +| $`\mathit{Transformer\_angle\_sum}`$ | `Transformer_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | | $`\mathit{Transformer\_capex}`$ | `Transformer_capex` (scalar) | -| $`\check{\sigma}`$ | `Transformer_s_monitored` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the flow a transformer's post-contingency rows read, as a line's | | $`\mathit{Transformer\_injection}`$ | `Transformer_injection` over $`\mathcal{N} \times \Xi \times \mathcal{T}`$ | -| $`\mathit{Transformer\_angle\_sum}`$ | `Transformer_angle_sum` over $`\mathcal{C} \times \Xi \times \mathcal{T}`$ | +| $`\check{\sigma}`$ | `Transformer_s_monitored` over $`\Xi \times \mathcal{T} \times \mathcal{M}`$ — the flow a transformer's post-contingency rows read, as a line's | #### Conditions @@ -454,16 +454,16 @@ constraints: #### Variable domains -**`Transformer_s`** +**`Transformer_loss`** ```math -\sigma_{\xi,t,m} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma}_{t,m} +\ell^{\sigma}_{\xi,t,m} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -**`Transformer_loss`** +**`Transformer_n_mod`** ```math -\ell^{\sigma}_{\xi,t,m} \ge 0 \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} ``` **`Transformer_phase_shift`** @@ -472,30 +472,30 @@ constraints: \mathrm{Transformer\_phase\_shift\_min}_{m} \le \mathit{Transformer\_phase\_shift}_{\xi,t,m} \le \mathrm{Transformer\_phase\_shift\_max}_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_s_nom_ext`** +**`Transformer_s`** ```math -\Sigma_{m} \in \mathbb{R} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} +\sigma_{\xi,t,m} \in \mathbb{R} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_n_mod`** +**`Transformer_s_nom_ext`** ```math -N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} +\Sigma_{m} \in \mathbb{R} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} ``` #### Definitions -**`Transformer_capex`** +**`Transformer_angle_sum`** ```math -\mathit{Transformer\_capex} = \sum_{\xi \in \Xi,\ m \in \mathcal{M}} \pi_{\xi} \cdot \Sigma_{m} \cdot \mathrm{c}^{\mathrm{cap},\sigma}_{\xi,m} \cdot \mathrm{W}^{\sigma}_{m} +\mathit{Transformer\_angle\_sum}_{c,\xi,t} = \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Transformer_s_monitored`** +**`Transformer_capex`** ```math -\check{\sigma}_{\xi,t,m} = \begin{cases} \sigma_{\xi,t,m} & \text{if } \mathrm{on}^{\sigma}_{t,m} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} +\mathit{Transformer\_capex} = \sum_{\xi \in \Xi,\ m \in \mathcal{M}} \pi_{\xi} \cdot \Sigma_{m} \cdot \mathrm{c}^{\mathrm{cap},\sigma}_{\xi,m} \cdot \mathrm{W}^{\sigma}_{m} ``` **`Transformer_injection`** @@ -504,30 +504,30 @@ N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \math \mathit{Transformer\_injection}_{n,\xi,t} = -\left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \sigma_{\xi,t,m} \right) + \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \sigma_{\xi,t,m} - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus0}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) - 0.5 \cdot \left( \sum_{m \in \mathcal{M} \,:\, \mathrm{Transformer\_bus1}(m) = n} \ell^{\sigma}_{\xi,t,m} \right) \qquad \forall\, n \in \mathcal{N},\ \xi \in \Xi,\ t \in \mathcal{T} ``` -**`Transformer_angle_sum`** +**`Transformer_s_monitored`** ```math -\mathit{Transformer\_angle\_sum}_{c,\xi,t} = \sum_{m \in \mathcal{M}} \sigma_{\xi,t,m} \cdot \mathrm{x}^{\sigma}_{c,\mathrm{snapshot\_period}(t),m} + \sum_{m \in \mathcal{M}} \vartheta_{c,t,m} + \sum_{m \in \mathcal{M}} \mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \mathrm{Transformer\_phase\_shift\_cycle\_weight}_{c,\mathrm{snapshot\_period}(t),m} \qquad \forall\, c \in \mathcal{C},\ \xi \in \Xi,\ t \in \mathcal{T} +\check{\sigma}_{\xi,t,m} = \begin{cases} \sigma_{\xi,t,m} & \text{if } \mathrm{on}^{\sigma}_{t,m} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} ``` #### Subject to -**`Transformer_fix_s_lower`** +**`Transformer_ext_s_lower`** ```math -\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_fix_s_upper`** +**`Transformer_ext_s_nom_lower`** ```math -\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\Sigma_{m} \ge \underline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} ``` -**`Transformer_ext_s_lower`** +**`Transformer_ext_s_nom_upper`** ```math -\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\Sigma_{m} \le \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \text{ is defined} ``` **`Transformer_ext_s_upper`** @@ -536,75 +536,75 @@ N^{\sigma}_{m} \ge 0, N^{\sigma}_{m} \in \mathbb{Z} \qquad \forall\, m \in \math \sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \Sigma_{m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_ext_s_nom_lower`** +**`Transformer_fix_s_lower`** ```math -\Sigma_{m} \ge \underline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} +\sigma_{\xi,t,m} - \ell^{\sigma}_{\xi,t,m} \ge -\overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_ext_s_nom_upper`** +**`Transformer_fix_s_upper`** ```math -\Sigma_{m} \le \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \overline{\sigma}^{\mathrm{nom}}_{\xi,m} \text{ is defined} +\sigma_{\xi,t,m} + \ell^{\sigma}_{\xi,t,m} \le \overline{\sigma}_{\xi,t,m} \cdot \sigma^{\mathrm{nom}}_{\xi,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \neg \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_s_nom_set`** +**`Transformer_loss_tangents_forward`** ```math -\Sigma_{m} = \sigma^{\mathrm{nom,set}}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \sigma^{\mathrm{nom,set}}_{m} \text{ is defined} +\ell^{\sigma}_{\xi,t,m} + \mathrm{a}^{\sigma}_{\xi,s,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,s,t,m} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -**`Transformer_s_nom_modularity`** +**`Transformer_loss_tangents_reverse`** ```math -\Sigma_{m} = \sigma^{\mathrm{mod}}_{m} \cdot N^{\sigma}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} +\ell^{\sigma}_{\xi,t,m} - \mathrm{a}^{\sigma}_{\xi,s,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,s,t,m} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -**`Transformer_s_set`** +**`Transformer_loss_upper`** ```math -\sigma_{\xi,t,m} = \sigma^{\mathrm{set}}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \sigma^{\mathrm{set}}_{\xi,t,m} \text{ is defined} \wedge \mathrm{on}^{\sigma}_{t,m} +\ell^{\sigma}_{\xi,t,m} \le \overline{\ell}^{\sigma}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} ``` -**`Transformer_v_ang_lower`** +**`Transformer_s_nom_modularity`** ```math -\sigma_{\xi,t,m} \ge \frac{-\left( \overline{\delta}^{\sigma}_{\xi,m} + \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\Sigma_{m} = \sigma^{\mathrm{mod}}_{m} \cdot N^{\sigma}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \sigma^{\mathrm{mod}}_{m} > 0 \wedge \mathrm{act}^{\sigma}_{m} ``` -**`Transformer_v_ang_upper`** +**`Transformer_s_nom_set`** ```math -\sigma_{\xi,t,m} \le \frac{\left( \overline{\delta}^{\sigma}_{\xi,m} - \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\Sigma_{m} = \sigma^{\mathrm{nom,set}}_{m} \qquad \forall\, m \in \mathcal{M} \,:\, \mathrm{ext}^{\sigma}_{m} \wedge \mathrm{act}^{\sigma}_{m} \wedge \sigma^{\mathrm{nom,set}}_{m} \text{ is defined} ``` -**`Transformer_v_ang_var_lower`** +**`Transformer_s_set`** ```math -\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \ge \frac{-\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\sigma_{\xi,t,m} = \sigma^{\mathrm{set}}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \sigma^{\mathrm{set}}_{\xi,t,m} \text{ is defined} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_v_ang_var_upper`** +**`Transformer_v_ang_lower`** ```math -\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \le \frac{\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} +\sigma_{\xi,t,m} \ge \frac{-\left( \overline{\delta}^{\sigma}_{\xi,m} + \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_loss_upper`** +**`Transformer_v_ang_upper`** ```math -\ell^{\sigma}_{\xi,t,m} \le \overline{\ell}^{\sigma}_{\xi,t,m} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +\sigma_{\xi,t,m} \le \frac{\left( \overline{\delta}^{\sigma}_{\xi,m} - \varphi^{\sigma}_{t,m} \right) \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \neg \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_loss_tangents_forward`** +**`Transformer_v_ang_var_lower`** ```math -\ell^{\sigma}_{\xi,t,m} + \mathrm{a}^{\sigma}_{\xi,s,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,s,t,m} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \ge \frac{-\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` -**`Transformer_loss_tangents_reverse`** +**`Transformer_v_ang_var_upper`** ```math -\ell^{\sigma}_{\xi,t,m} - \mathrm{a}^{\sigma}_{\xi,s,t,m} \cdot \sigma_{\xi,t,m} \ge \mathrm{b}^{\sigma}_{\xi,s,t,m} \qquad \forall\, \xi \in \Xi,\ s \in \mathcal{S},\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \mathrm{on}^{\sigma,\mathrm{lossy}}_{t,m} +\sigma_{\xi,t,m} + \frac{\mathit{Transformer\_phase\_shift}_{\xi,t,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \le \frac{\overline{\delta}^{\sigma}_{\xi,m} \cdot \frac{3.141592653589793}{180}}{\mathrm{x}^{\mathrm{eff},\sigma}_{\xi,m}} \qquad \forall\, \xi \in \Xi,\ t \in \mathcal{T},\ m \in \mathcal{M} \,:\, \overline{\delta}^{\sigma}_{\xi,m} \text{ is defined} \wedge \mathrm{Transformer\_phase\_shift\_varying}_{m} \wedge \mathrm{on}^{\sigma}_{t,m} ``` diff --git a/docs/first-spec.md b/docs/first-spec.md index e215b25e..6f8c3313 100644 --- a/docs/first-spec.md +++ b/docs/first-spec.md @@ -155,22 +155,22 @@ python -m mathspec markdown dispatch.yaml | Symbol | Meaning | |---|---| - | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units | + | $`\mathcal{T}`$ | index $`t`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| | $`\mathrm{capacity}`$ | `capacity` over $`\mathcal{G}`$ — installed capacity | - | $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | | $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$ — marginal cost | + | $`\mathrm{load}`$ | `load` over $`\mathcal{T}`$ — demand to be met | #### Variables | Symbol | Meaning | |---|---| - | $`\mathit{dispatch}`$ | `dispatch` over $`\mathcal{T} \times \mathcal{G}`$ — output of a generator in a snapshot | + | $`\mathit{dispatch}`$ | `dispatch` over $`\mathcal{G} \times \mathcal{T}`$ — output of a generator in a snapshot | #### Variable domains diff --git a/docs/howto/see-an-expansion.md b/docs/howto/see-an-expansion.md index bb6f1a11..67b3556f 100644 --- a/docs/howto/see-an-expansion.md +++ b/docs/howto/see-an-expansion.md @@ -125,16 +125,16 @@ names each row the expansion adds. _Subject to_ - **`pick_pick`** + **`pick_nonzero`** ```math - \sum_{g \in \mathcal{G}} \mathit{pick\_seg}_{g} \le 1 + p_{g} \le 10 \cdot \mathit{pick\_seg}_{g} \qquad \forall\, g \in \mathcal{G} ``` - **`pick_nonzero`** + **`pick_pick`** ```math - p_{g} \le 10 \cdot \mathit{pick\_seg}_{g} \qquad \forall\, g \in \mathcal{G} + \sum_{g \in \mathcal{G}} \mathit{pick\_seg}_{g} \le 1 ``` @@ -256,22 +256,22 @@ the set out too. _Variable domains_ - **`x`** + **`curve_lam`** ```math - x \ge 0 + 0 \le \mathit{curve\_lam}_{b} \le 1 \qquad \forall\, b \in \mathcal{B} ``` - **`y`** + **`x`** ```math - y \ge 0 + x \ge 0 ``` - **`curve_lam`** + **`y`** ```math - 0 \le \mathit{curve\_lam}_{b} \le 1 \qquad \forall\, b \in \mathcal{B} + y \ge 0 ``` _Subject to_ @@ -362,32 +362,38 @@ the set out too. _Variable domains_ - **`x`** + **`curve_lam`** ```math - x \ge 0 + 0 \le \mathit{curve\_lam}_{b} \le 1 \qquad \forall\, b \in \mathcal{B} ``` - **`y`** + **`curve_seg`** ```math - y \ge 0 + \mathit{curve\_seg}_{b} \in \{0, 1\} \qquad \forall\, b \in \mathcal{B} ``` - **`curve_lam`** + **`x`** ```math - 0 \le \mathit{curve\_lam}_{b} \le 1 \qquad \forall\, b \in \mathcal{B} + x \ge 0 ``` - **`curve_seg`** + **`y`** ```math - \mathit{curve\_seg}_{b} \in \{0, 1\} \qquad \forall\, b \in \mathcal{B} + y \ge 0 ``` _Subject to_ + **`curve_adjacency`** + + ```math + \mathit{curve\_lam}_{b} \le \mathit{curve\_seg}_{b} + \mathit{curve\_seg}_{b \boxminus_{0} 1} \qquad \forall\, b \in \mathcal{B} + ``` + **`curve_convexity`** ```math @@ -412,12 +418,6 @@ the set out too. \sum_{b \in \mathcal{B}} \mathit{curve\_seg}_{b} \le 1 ``` - **`curve_adjacency`** - - ```math - \mathit{curve\_lam}_{b} \le \mathit{curve\_seg}_{b} + \mathit{curve\_seg}_{b \boxminus_{0} 1} \qquad \forall\, b \in \mathcal{B} - ``` - _Assumptions_ **`curve_complete`** diff --git a/docs/index.md b/docs/index.md index 6a3bfbbb..2aecc2af 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,16 +56,16 @@ the **How** tab shows the call. | Symbol | Meaning | |---|---| - | $`\mathcal{S}`$ | index $`s`$ — `snapshot` — dispatch periods | | $`\mathcal{G}`$ | index $`g`$ — `generator` — generating units | + | $`\mathcal{S}`$ | index $`s`$ — `snapshot` — dispatch periods | #### Parameters | Symbol | Meaning | |---|---| | $`\bar p`$ | `capacity` over $`\mathcal{G}`$ — installed capacity | - | $`\ell`$ | `load` over $`\mathcal{S}`$ — demand to be met | | $`c`$ | `cost` over $`\mathcal{G}`$ — marginal cost | + | $`\ell`$ | `load` over $`\mathcal{S}`$ — demand to be met | #### Variables @@ -102,15 +102,15 @@ the **How** tab shows the call. \paragraph{Sets} \begin{description} - \item[{$\mathcal{S}$}] index $s$ --- \texttt{snapshot} --- dispatch periods \item[{$\mathcal{G}$}] index $g$ --- \texttt{generator} --- generating units + \item[{$\mathcal{S}$}] index $s$ --- \texttt{snapshot} --- dispatch periods \end{description} \paragraph{Parameters} \begin{description} \item[{$\bar p$}] \texttt{capacity} over $\mathcal{G}$ --- installed capacity - \item[{$\ell$}] \texttt{load} over $\mathcal{S}$ --- demand to be met \item[{$c$}] \texttt{cost} over $\mathcal{G}$ --- marginal cost + \item[{$\ell$}] \texttt{load} over $\mathcal{S}$ --- demand to be met \end{description} \paragraph{Variables} diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index 25015140..92c8644e 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -13,8 +13,8 @@ Unlike constructs like `parameter` or `macro` (defined in their respective [lang **Spec** : Short for specification. A spec is the optimisation problem that a file states: its dimensions, the data it expects, its decisions and its rules, but -no data. In Python it is a `Spec`, the file as written and checked, its lists -of dimensions sorted, which +no data. In Python it is a `Spec`, the file as written and checked, its entries +and its lists of dimensions sorted by name, which `to_spec` returns ([reading a spec and its program](reading.md#spec-and-program)). diff --git a/docs/reference/language/dimensions.md b/docs/reference/language/dimensions.md index ebea3820..26b649f2 100644 --- a/docs/reference/language/dimensions.md +++ b/docs/reference/language/dimensions.md @@ -19,16 +19,12 @@ dimensions: Every dimension named anywhere in the file is declared here. -The order of a `dims:` list changes nothing. An entry is indexed by its -dimensions sorted by name, and the indices print in that order: a variable `p` -with `dims: [snapshot, generator]` prints as $`p_{g,t}`$. - -The order of the entries under `dimensions:` changes nothing in the program. -The typeset document reads it in two places. The legend lists the dimensions in -that order, and where two dimensions start with the same letter, the one -declared first takes that letter as its index. With `period` declared before -`plant`, a variable `x` over both prints as $`x_{p,l}`$. With `plant` first, it -prints as $`x_{e,p}`$. +The order of the entries under `dimensions:`, and the order of a `dims:` list, +change nothing. An entry is indexed by its dimensions sorted by name, and the +indices print in that order: a variable `p` with `dims: [snapshot, generator]` +prints as $`p_{g,t}`$. The legend lists the dimensions sorted by name too, and +where two dimensions start with the same letter, the first by name takes that +letter as its index: `period` prints as $`p`$ and `plant` as $`l`$. | Field | | | | ------------- | ----------------------------------------------------- | --------------- | diff --git a/docs/reference/language/file.md b/docs/reference/language/file.md index ca469836..f1277b24 100644 --- a/docs/reference/language/file.md +++ b/docs/reference/language/file.md @@ -27,6 +27,12 @@ A spec file is a YAML mapping with **thirteen section keys**, plus A file with no `objective` is a **feasibility problem**: it asks whether the constraints can all be met. +The order of the sections, and the order of the entries in a section, change +nothing. `to_spec` sorts the entries of each section by name, and the entries +under each kind of `given:` too. The program, the typeset document and +`to_yaml()` list them in that order, so a file that declares `p` before `flow` +under `variables:` prints `flow` first. + ## `description` `description` is free text that says what the spec is. It is optional, and a diff --git a/docs/reference/language/named.md b/docs/reference/language/named.md index b2a8a667..c79e5a69 100644 --- a/docs/reference/language/named.md +++ b/docs/reference/language/named.md @@ -84,7 +84,8 @@ constraints: <= ramp_limit * previous_status + start_up_limit * (1 - previous_status) ``` -Each case prints as one row of the definition, and `otherwise:` as the last: +Each case prints as one row of the definition, sorted by name, and +`otherwise:` as the last: $$\mathit{previous\_status}_{g,t} = \begin{cases} 1 & \text{if } \neg \mathrm{committable}_{g} \cr \mathrm{status}^{\mathrm{initial}}_{g} & \text{if } \mathrm{committable}_{g} \wedge \mathrm{pos}(t) = 0 \cr \mathit{status}_{g,t - 1} & \text{otherwise} \end{cases} \qquad \forall\thinspace g \in \mathcal{G},\enspace t \in \mathcal{T}$$ @@ -106,7 +107,7 @@ A named expression carries **exactly one** of `expression:` and `cases:`. > Narrow one of the two `when:` strings by the negation of the other, or drop > the wider one and let `otherwise:` cover that region. - The cases carry no order. + The cases carry no order, so `to_spec` sorts them by name. - A `when:` must be a question the data answers. `True`, `False`, and a mask that folds to one of them, such as `committable OR True`, are refused. diff --git a/docs/reference/notation.md b/docs/reference/notation.md index 38a4ed9d..3e41e5c3 100644 --- a/docs/reference/notation.md +++ b/docs/reference/notation.md @@ -69,34 +69,34 @@ parameters: | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` (`int` coordinates) with $`\mathrm{season\_of}: \mathcal{T} \to \mathcal{S},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T}`$ | -| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$, `connection` is `absent` where the data has no row | -| $`\mathcal{B}`$ | index $`b`$ — `bus` with $`\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row | -| $`\mathcal{Z}`$ | index $`z`$ — `zone` with $`\mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row | +| $`\mathcal{B}`$ | index $`b`$ — `bp` | +| $`\mathcal{U}`$ | index $`u`$ — `bus` with $`\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row | +| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}`$, `connection` is `absent` where the data has no row | | $`\mathcal{S}`$ | index $`s`$ — `season` with $`\mathrm{season\_of}: \mathcal{T} \to \mathcal{S}`$ | -| $`\mathcal{E}`$ | index $`e`$ — `technology` with $`\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$ | -| $`\mathcal{A}`$ | index $`a`$ — `bp` | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` (`int` coordinates) with $`\mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T},\ \mathrm{season\_of}: \mathcal{T} \to \mathcal{S}`$ | +| $`\mathcal{E}`$ | index $`e`$ — `technology` with $`\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E}`$ | +| $`\mathcal{Z}`$ | index $`z`$ — `zone` with $`\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{p}^{\mathrm{max}}`$ | `p_max` over $`\mathcal{G}`$, $`\infty`$ where the data has no row | -| $`\mathrm{p}^{\mathrm{min}}`$ | `p_min` over $`\mathcal{G}`$ | +| $`\mathrm{bp\_heat}`$ | `bp_heat` over $`\mathcal{B} \times \mathcal{G}`$ | +| $`\mathrm{bp\_run}`$ | `bp_run` over $`\mathcal{B} \times \mathcal{G}`$ | +| $`\mathrm{bp\_x}`$ | `bp_x` over $`\mathcal{B} \times \mathcal{G}`$, `neutral` where the data has no row | +| $`\mathrm{bp\_y}`$ | `bp_y` over $`\mathcal{B} \times \mathcal{G}`$, `neutral` where the data has no row | +| $`\mathrm{budget}`$ | `budget` (scalar) | | $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{load}`$ | `load` over $`\mathcal{B} \times \mathcal{T}`$ | -| $`\mathrm{is\_flexible}`$ | `is_flexible` over $`\mathcal{G}`$, `false` where the data has no row | -| $`\mathrm{zone\_cap}`$ | `zone_cap` over $`\mathcal{Z}`$ | -| $`\mathrm{tech\_cap}`$ | `tech_cap` over $`\mathcal{B} \times \mathcal{E}`$, `absent` where the data has no row | -| $`\mathrm{min\_up}`$ | `min_up` over $`\mathcal{G}`$ | | $`\mathrm{eta}`$ | `eta` over $`\mathcal{G}`$ | -| $`\mathrm{lead}`$ | `lead` over $`\mathcal{G}`$ | -| $`\mathrm{budget}`$ | `budget` (scalar) | | $`\mathrm{growth}`$ | `growth` (scalar) | -| $`\mathrm{bp\_x}`$ | `bp_x` over $`\mathcal{A} \times \mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{bp\_y}`$ | `bp_y` over $`\mathcal{A} \times \mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{bp\_heat}`$ | `bp_heat` over $`\mathcal{A} \times \mathcal{G}`$ | -| $`\mathrm{bp\_run}`$ | `bp_run` over $`\mathcal{A} \times \mathcal{G}`$ | +| $`\mathrm{is\_flexible}`$ | `is_flexible` over $`\mathcal{G}`$, `false` where the data has no row | +| $`\mathrm{lead}`$ | `lead` over $`\mathcal{G}`$ | +| $`\mathrm{load}`$ | `load` over $`\mathcal{U} \times \mathcal{T}`$ | +| $`\mathrm{min\_up}`$ | `min_up` over $`\mathcal{G}`$ | +| $`\mathrm{p}^{\mathrm{max}}`$ | `p_max` over $`\mathcal{G}`$, $`\infty`$ where the data has no row | +| $`\mathrm{p}^{\mathrm{min}}`$ | `p_min` over $`\mathcal{G}`$ | +| $`\mathrm{tech\_cap}`$ | `tech_cap` over $`\mathcal{U} \times \mathcal{E}`$, `absent` where the data has no row | +| $`\mathrm{zone\_cap}`$ | `zone_cap` over $`\mathcal{Z}`$ | #### Conditions @@ -109,31 +109,31 @@ parameters: | Symbol | Meaning | |---|---| -| $`p`$ | `p` over $`\mathcal{G} \times \mathcal{T}`$ | -| $`\mathit{spill}`$ | `spill` over $`\mathcal{T}`$ | -| $`\mathit{slack}`$ | `slack` over $`\mathcal{T}`$ | -| $`\theta`$ | `theta` over $`\mathcal{B}`$ | -| $`\mathit{on}`$ | `on` over $`\mathcal{G} \times \mathcal{T}`$ | -| $`\mathit{units}`$ | `units` over $`\mathcal{G}`$ | -| $`\mathit{spare}`$ | `spare` over $`\mathcal{G}`$ | -| $`\mathit{reserve}`$ | `reserve` (scalar) | -| $`\mathit{headroom}`$ | `headroom` (scalar), `neutral` where the mask leaves it out | -| $`\mathit{weight}`$ | `weight` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{fuel}`$ | `fuel` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{headroom}`$ | `headroom` (scalar), `neutral` where the mask leaves it out | | $`\mathit{heat}`$ | `heat` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{on}`$ | `on` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{op\_cost}`$ | `op_cost` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`p`$ | `p` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{reserve}`$ | `reserve` (scalar) | +| $`\mathit{slack}`$ | `slack` over $`\mathcal{T}`$ | +| $`\mathit{spare}`$ | `spare` over $`\mathcal{G}`$ | +| $`\mathit{spill}`$ | `spill` over $`\mathcal{T}`$ | +| $`\theta`$ | `theta` over $`\mathcal{U}`$ | +| $`\mathit{units}`$ | `units` over $`\mathcal{G}`$ | | $`\mathit{warm}`$ | `warm` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{weight}`$ | `weight` over $`\mathcal{G} \times \mathcal{T}`$ | #### Definitions | Symbol | Meaning | |---|---| -| $`\mathrm{spend}^{\mathrm{cap}}`$ | `spend_cap` over $`\mathcal{G}`$ | -| $`\mathit{spend}`$ | `spend` over $`\mathcal{T}`$ — what a snapshot's dispatch costs | -| $`\mathrm{rating}`$ | `rating` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{lcoe}`$ | `lcoe` (scalar) | +| $`\mathit{marginal\_price}`$ | `marginal_price` over $`\mathcal{U} \times \mathcal{T}`$ | | $`\mathit{net}`$ | `net` over $`\mathcal{T}`$ — what a snapshot spills, less what it lacks | -| $`\mathit{marginal\_price}`$ | `marginal_price` over $`\mathcal{B} \times \mathcal{T}`$ | +| $`\mathrm{rating}`$ | `rating` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{spend}`$ | `spend` over $`\mathcal{T}`$ — what a snapshot's dispatch costs | +| $`\mathrm{spend}^{\mathrm{cap}}`$ | `spend_cap` over $`\mathcal{G}`$ | | $`\mathrm{startup\_cost}`$ | `startup_cost` over $`\mathcal{G} \times \mathcal{T}`$ — what starting a unit in this snapshot costs, which the horizon's edge changes | #### Notation @@ -200,7 +200,7 @@ variables: ``` ```math -\theta_{b} \in \mathbb{R} \qquad \forall\, b \in \mathcal{B} +\theta_{u} \in \mathbb{R} \qquad \forall\, u \in \mathcal{U} ``` #### Binary domain @@ -385,7 +385,7 @@ constraints: ``` ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} = \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} = \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` #### Sum over every dimension @@ -415,7 +415,7 @@ constraints: ``` ```math -\mathit{spill}_{t} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\mathit{spill}_{t} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` #### Sum into two value columns @@ -430,7 +430,7 @@ constraints: ``` ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = b \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} \le \mathrm{tech\_cap}_{b,e} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T},\ e \in \mathcal{E} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = u \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} \le \mathrm{tech\_cap}_{u,e} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T},\ e \in \mathcal{E} ``` #### `at` through two value columns @@ -476,7 +476,7 @@ constraints: ``` ```math -\sum_{g \in \mathcal{G} \,:\, \left( b,\ g \right) \in \mathrm{connection}} p_{g,t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \left( u,\ g \right) \in \mathrm{connection}} p_{g,t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` #### Bare relation as a condition @@ -492,7 +492,7 @@ constraints: ``` ```math -p_{g,t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( b,\ g \right) \in \mathrm{connection} +p_{g,t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( u,\ g \right) \in \mathrm{connection} ``` #### Map into its own dimension @@ -617,7 +617,7 @@ constraints: ``` ```math -\theta_{b} \le \infty \qquad \forall\, b \in \mathcal{B} +\theta_{u} \le \infty \qquad \forall\, u \in \mathcal{U} ``` ### Named expressions @@ -649,7 +649,7 @@ constraints: ``` ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{net}_{t} = \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{net}_{t} = \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` #### Cased expression in a constraint @@ -708,7 +708,7 @@ expressions: ``` ```math -\mathrm{rating}_{g,t} = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{b \in \mathcal{B}} \mathrm{load}_{b,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathrm{rating}_{g,t} = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{u \in \mathcal{U}} \mathrm{load}_{u,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` #### Plain expression that is a signed sum @@ -795,7 +795,7 @@ expressions: ``` ```math -\mathit{marginal\_price}_{b,t} = \lambda_{\mathrm{balance},b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\mathit{marginal\_price}_{u,t} = \lambda_{\mathrm{balance},u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` ### Named conditions @@ -1072,6 +1072,10 @@ Written out by `spec.expand()`: \delta_{b,m,p} \in \{0, 1\} \qquad \forall\, b \in \mathcal{B},\ m \in \mathcal{M},\ p \in \mathcal{P} ``` +```math +\lambda_{b,m,p} \le \delta_{b,m,p} + \delta_{b \boxminus_{0} 1,m,p} \qquad \forall\, b \in \mathcal{B},\ m \in \mathcal{M},\ p \in \mathcal{P} +``` + ```math \sum_{b \in \mathcal{B}} \lambda_{b,m,p} = 1 \qquad \forall\, m \in \mathcal{M},\ p \in \mathcal{P} ``` @@ -1088,10 +1092,6 @@ Written out by `spec.expand()`: \sum_{b \in \mathcal{B}} \delta_{b,m,p} \le 1 \qquad \forall\, m \in \mathcal{M},\ p \in \mathcal{P} ``` -```math -\lambda_{b,m,p} \le \delta_{b,m,p} + \delta_{b \boxminus_{0} 1,m,p} \qquad \forall\, b \in \mathcal{B},\ m \in \mathcal{M},\ p \in \mathcal{P} -``` - ```math \mathrm{x}_{b} \text{ is defined} \wedge \mathrm{y}_{b} \text{ is defined} \qquad \forall\, b \in \mathcal{B} ``` @@ -1203,11 +1203,11 @@ Written out by `spec.expand()`: ``` ```math -\mathrm{x}_{b \boxminus_{0} 1,g} < \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 +\lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{y}_{b,g} - \mathrm{y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{x}_{b \boxplus_{0} 1,g} - \mathrm{x}_{b,g} \right) > \left( \mathrm{y}_{b \boxplus_{0} 1,g} - \mathrm{y}_{b,g} \right) \cdot \left( \mathrm{x}_{b,g} - \mathrm{x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \vee \lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{y}_{b,g} - \mathrm{y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{x}_{b \boxplus_{0} 1,g} - \mathrm{x}_{b,g} \right) < \left( \mathrm{y}_{b \boxplus_{0} 1,g} - \mathrm{y}_{b,g} \right) \cdot \left( \mathrm{x}_{b,g} - \mathrm{x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \qquad \forall\, g \in \mathcal{G} ``` ```math -\lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{y}_{b,g} - \mathrm{y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{x}_{b \boxplus_{0} 1,g} - \mathrm{x}_{b,g} \right) > \left( \mathrm{y}_{b \boxplus_{0} 1,g} - \mathrm{y}_{b,g} \right) \cdot \left( \mathrm{x}_{b,g} - \mathrm{x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \vee \lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{y}_{b,g} - \mathrm{y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{x}_{b \boxplus_{0} 1,g} - \mathrm{x}_{b,g} \right) < \left( \mathrm{y}_{b \boxplus_{0} 1,g} - \mathrm{y}_{b,g} \right) \cdot \left( \mathrm{x}_{b,g} - \mathrm{x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \qquad \forall\, g \in \mathcal{G} +\mathrm{x}_{b \boxminus_{0} 1,g} < \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 ``` #### LP method @@ -1245,19 +1245,19 @@ Written out by `spec.expand()`: ``` ```math -\mathit{dispatch}_{g,t} \ge \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(b) = 0 +\mathit{dispatch}_{g,t} \le \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(b) = \lvert \mathcal{B} \rvert - 1 ``` ```math -\mathit{dispatch}_{g,t} \le \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(b) = \lvert \mathcal{B} \rvert - 1 +\mathit{dispatch}_{g,t} \ge \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(b) = 0 ``` ```math -\mathrm{x}_{b,g} \text{ is defined} \wedge \mathrm{y}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} +\lvert \{ b \in \mathcal{B} \,:\, \mathrm{x}_{b,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} ``` ```math -\mathrm{x}_{b \boxminus_{0} 1,g} < \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 +\mathrm{x}_{b,g} \text{ is defined} \wedge \mathrm{y}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} ``` ```math @@ -1265,7 +1265,7 @@ Written out by `spec.expand()`: ``` ```math -\lvert \{ b \in \mathcal{B} \,:\, \mathrm{x}_{b,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} +\mathrm{x}_{b \boxminus_{0} 1,g} < \mathrm{x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 ``` ### Special ordered sets @@ -1295,11 +1295,11 @@ Written out by `spec.expand()`: ``` ```math -\sum_{g \in \mathcal{G}} \mathit{adjacent\_seg}_{g,t} \le 1 \qquad \forall\, t \in \mathcal{T} +\mathit{weight}_{g,t} \le \mathit{adjacent\_seg}_{g,t} + \mathit{adjacent\_seg}_{g \boxminus_{0} 1,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` ```math -\mathit{weight}_{g,t} \le \mathit{adjacent\_seg}_{g,t} + \mathit{adjacent\_seg}_{g \boxminus_{0} 1,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G}} \mathit{adjacent\_seg}_{g,t} \le 1 \qquad \forall\, t \in \mathcal{T} ``` ### Assumptions @@ -1353,7 +1353,7 @@ assumptions: ``` ```math -\mathrm{zone\_of}(b) = \mathrm{area\_of}(b) \qquad \forall\, b \in \mathcal{B} +\mathrm{zone\_of}(u) = \mathrm{area\_of}(u) \qquad \forall\, u \in \mathcal{U} ``` #### Reduction in an assumption @@ -1381,7 +1381,7 @@ assumptions: ``` ```math -\mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 +\mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 ``` #### Assumption with a boolean condition @@ -1411,7 +1411,7 @@ assumptions: ``` ```math -\mathrm{load}_{b,t} \ge 0 \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} +\mathrm{load}_{u,t} \ge 0 \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} ``` ### Where conditions @@ -1445,7 +1445,7 @@ constraints: ``` ```math -\theta_{b} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \theta_{b} \text{ exists} \wedge t \ge 3 +\theta_{u} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \theta_{u} \text{ exists} \wedge t \ge 3 ``` #### Position in a dimension @@ -1493,7 +1493,7 @@ constraints: ``` ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(b) \neq \mathrm{area\_of}(b) \wedge \mathrm{zone\_of}(b) \text{ is defined} +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(u) \neq \mathrm{area\_of}(u) \wedge \mathrm{zone\_of}(u) \text{ is defined} ``` #### Constant true condition @@ -1573,7 +1573,7 @@ constraints: ``` ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \wedge \mathrm{pos}(t) > 0 +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \wedge \mathrm{pos}(t) > 0 ``` #### Reduction in a scalar condition @@ -1605,7 +1605,7 @@ constraints: ``` ```math -\theta_{b} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e} > 0 \} \rvert \ge 2 +\theta_{u} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e} > 0 \} \rvert \ge 2 ``` #### Count along a dimension of the frame @@ -1621,7 +1621,7 @@ constraints: ``` ```math -\theta_{b} \le \mathrm{tech\_cap}_{b,e} \qquad \forall\, b \in \mathcal{B},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e'} > 0 \} \rvert \ge 2 +\theta_{u} \le \mathrm{tech\_cap}_{u,e} \qquad \forall\, u \in \mathcal{U},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e'} > 0 \} \rvert \ge 2 ``` #### Condition at the previous coordinate @@ -1637,7 +1637,7 @@ constraints: ``` ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{b,t - 1} \text{ is defined} \right) +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{u,t - 1} \text{ is defined} \right) ``` #### Condition through a relation @@ -1653,6 +1653,6 @@ constraints: ``` ```math -\theta_{b} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \text{ is defined} +\theta_{u} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \text{ is defined} ``` diff --git a/docs/reference/reading.md b/docs/reference/reading.md index 05ad1be5..62705169 100644 --- a/docs/reference/reading.md +++ b/docs/reference/reading.md @@ -10,10 +10,10 @@ that builds models, a renderer or a checker. ## `Spec` and `Program` -A `Spec` holds the file as written: its `macros:`, its descriptions, its -entries in the order the file lists them, and a `piecewise:` entry as one -entry. It sorts by name what no order reaches: each `dims:` list, and each side -of a relation, the key's columns before the values'. A `Program` holds what the +A `Spec` holds the file as written: its `macros:`, its descriptions, and a +`piecewise:` entry as one entry. It sorts by name what no order reaches: the +entries of each section, each `dims:` list, and each side of a relation, the +key's columns before the values'. A `Program` holds what the file means: every macro expanded, every name typed, every operator resolved to a node, and every dimension and degree rule already checked. A curve stays one curve there @@ -360,9 +360,9 @@ spec.to_yaml(canonical=True) == to_spec(spec.to_yaml(canonical=True)).to_yaml(ca - A constant is never folded into another. `2 * 3` stays `2 * 3`, so a reviewer sees a changed coefficient in the diff. -Three things are left as the file wrote them: a condition in the `where` -grammar, the order of the regions under `cases:`, and the order of a piecewise -entry's links. A difference in any of them is a difference in the text. +Two things are left as the file wrote them: a condition in the `where` +grammar, and the order of a piecewise entry's links. A difference in either is +a difference in the text. The normal form sorts `dimensions:` and every `dims:` list by name. This changes no dims of the program, because the program sorts every dims by name. diff --git a/docs/reference/typeset.md b/docs/reference/typeset.md index 5a6014e2..d18ec5c0 100644 --- a/docs/reference/typeset.md +++ b/docs/reference/typeset.md @@ -63,7 +63,7 @@ a flag. The [Python API](api.md#typesetting) gives each signature. breakpoints. A spec that assumes nothing of its data prints no such heading. - A [named expression](language/named.md) prints its symbol where it is used - and its body once, under a **Definitions** heading, in file order. A + and its body once, under a **Definitions** heading, sorted by name. A cased expression, a [reported entry](language/named.md#reported-expressions) and a [term](language/parameters-variables-constraints.md#terms) keep their definition line under either `inline_expressions` setting. diff --git a/docs/several-files.md b/docs/several-files.md index caa808c4..7e04205b 100644 --- a/docs/several-files.md +++ b/docs/several-files.md @@ -230,22 +230,22 @@ print(ms.to_markdown(spec, legend=False)) #### Definitions - **`generation`** + **`consumption`** ```math - \mathit{generation}_{b,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} \mathit{dispatch}_{g,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} + \mathrm{consumption}_{b,t} = -\mathrm{demand}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} ``` - **`generation_cost`** + **`generation`** ```math - \mathit{generation}^{\mathrm{cost}} = \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} \mathit{dispatch}_{g,t} \cdot \mathrm{cost}_{g} + \mathit{generation}_{b,t} = \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} \mathit{dispatch}_{g,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} ``` - **`consumption`** + **`generation_cost`** ```math - \mathrm{consumption}_{b,t} = -\mathrm{demand}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} + \mathit{generation}^{\mathrm{cost}} = \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} \mathit{dispatch}_{g,t} \cdot \mathrm{cost}_{g} ``` **`injection`** diff --git a/src/mathspec/_advising.py b/src/mathspec/_advising.py index dd4f701b..6710eac5 100644 --- a/src/mathspec/_advising.py +++ b/src/mathspec/_advising.py @@ -34,7 +34,7 @@ def advice(spec: str | Path | Mapping[str, object] | Spec | Program) -> tuple[Ad nothing expanded. Returns: - The never-an-axis advice in file order, then one note per + The never-an-axis advice sorted by dimension name, then one note per entry the program reads and does not build, then the unboundedness advice; ``str()`` of each is its sentence. diff --git a/src/mathspec/_canonical.py b/src/mathspec/_canonical.py index 4dd10b1b..2d3e7898 100644 --- a/src/mathspec/_canonical.py +++ b/src/mathspec/_canonical.py @@ -201,15 +201,15 @@ def _canonical_links(links: list[list[object]]) -> list[list[object]]: return [[canonical_text(cast('str', link[0])), *link[1:]] for link in links] -def _sorted_entries(section: dict[str, object], *, bare_is_expression: bool = False) -> dict[str, object]: - """One section's entries sorted by name, each with its expressions in the normal form. +def _canonical_entries(section: dict[str, object], *, bare_is_expression: bool = False) -> dict[str, object]: + """One section's entries, each with its expressions in the normal form. A named expression written on one line serialises back as a bare string, which is the expression itself, so *bare_is_expression* normalises it too. """ return { name: canonical_text(entry) if bare_is_expression and isinstance(entry, str) else _canonical_entry(entry) - for name, entry in sorted(section.items()) + for name, entry in section.items() } @@ -223,11 +223,12 @@ def _canonical_field(key: str, value: object) -> object: def canonical_dict(spec: Spec) -> dict[str, object]: """The spec as plain data, in the form two files that state the same spec share. - Entries are sorted by name, the ones under each kind of ``given:`` - too, and every expression is printed from its parsed tree, so what is - left of a difference is a difference in the spec. A ``dims:`` list and - each side of a relation arrive sorted, as the spec holds them. A ``where`` string, the order of the regions under ``cases:`` and - the order of a piecewise entry's links are all left as written. + Every expression is printed from its parsed tree, so what is left of a + difference is a difference in the spec. The entries of each section, the + ones under each kind of ``given:`` too, a ``dims:`` list and each side of + a relation, and the regions under ``cases:`` arrive sorted by name, as the + spec holds them. A ``where`` string and the order of a piecewise entry's + links are left as written. Args: spec: The loaded spec. @@ -241,9 +242,9 @@ def canonical_dict(spec: Spec) -> dict[str, object]: built: dict[str, object] = {} for section, value in data.items(): if section == 'given' and isinstance(value, dict): - built[section] = {kind: _sorted_entries(entries) for kind, entries in sorted(value.items())} + built[section] = {kind: _canonical_entries(entries) for kind, entries in sorted(value.items())} elif isinstance(value, dict) and section != 'objective': - built[section] = _sorted_entries(value, bare_is_expression=section == 'expressions') + built[section] = _canonical_entries(value, bare_is_expression=section == 'expressions') else: built[section] = _canonical_entry(value) piecewise = built.get('piecewise') diff --git a/src/mathspec/_condition_resolver.py b/src/mathspec/_condition_resolver.py index 303a17ee..27d4d7da 100644 --- a/src/mathspec/_condition_resolver.py +++ b/src/mathspec/_condition_resolver.py @@ -186,7 +186,7 @@ def _bare_name(self, node: NameNode) -> Condition | UnresolvedConditionNode: if node.name == self.self_variable: self.errors.append( f"{context}: variable '{node.name}' tests itself in its own where. " - f'Test a parameter, or another variable declared before it.' + f'Test a parameter, or another variable.' ) else: return VariableDefined(node.name, ns.leaf_dims[node.name]) diff --git a/src/mathspec/_resolution.py b/src/mathspec/_resolution.py index 66de83b4..e02bd17b 100644 --- a/src/mathspec/_resolution.py +++ b/src/mathspec/_resolution.py @@ -580,7 +580,7 @@ def self_existence(where: Condition, variable: str, context: str) -> str | None: return ( f"{context}: variable '{variable}' asks whether it exists in its own `where:`, through a named condition, which " f'nothing can answer — its `where:` is what decides where it exists. Test a parameter, or another ' - f'variable declared before it.' + f'variable.' ) diff --git a/src/mathspec/_separability.py b/src/mathspec/_separability.py index 4b5b033a..374fe26f 100644 --- a/src/mathspec/_separability.py +++ b/src/mathspec/_separability.py @@ -154,7 +154,7 @@ def joined(kind: str, dimension: str) -> dict[str, str]: return {label: ', '.join(dict.fromkeys(found)) for label, found in reasons[kind][dimension].items()} def linking_rows(dimension: str) -> tuple[str, ...]: - """Each constraint no one window of *dimension* holds whole, in file order. + """Each constraint no one window of *dimension* holds whole, sorted by name. Two shapes reach the border by different routes, and a constraint that takes both is still one name: a row the axis does not index stands in diff --git a/src/mathspec/_typesetting/walk.py b/src/mathspec/_typesetting/walk.py index 631c07b3..80b6c79f 100644 --- a/src/mathspec/_typesetting/walk.py +++ b/src/mathspec/_typesetting/walk.py @@ -709,7 +709,7 @@ def _constraint(self, name: str) -> Line: ) def _definitions(self) -> list[Line]: - """One line per named expression, in file order, defining it. + """One line per named expression, sorted by name, defining it. A use prints the symbol and the entry prints here, as a paper states a quantity it names. Every declared one prints, used or not. Inlining diff --git a/src/mathspec/_validation.py b/src/mathspec/_validation.py index 34b29343..11bc186d 100644 --- a/src/mathspec/_validation.py +++ b/src/mathspec/_validation.py @@ -98,7 +98,7 @@ def undeclared_dimension(kind: str, name: str, dimension: str) -> str: def _flat_namespace(spec: Spec) -> list[tuple[str, Iterable[str]]]: - """Each kind of entry whose names share the one namespace an expression reads, in file order.""" + """Each kind of entry whose names share the one namespace an expression reads.""" return [ ('dimension', spec.dimensions), ('relation', spec.relations), diff --git a/src/mathspec/program.py b/src/mathspec/program.py index 62a2efd2..0b589d90 100644 --- a/src/mathspec/program.py +++ b/src/mathspec/program.py @@ -1064,8 +1064,8 @@ def resolved(self, least: Mapping[str, int]) -> Separability: class Program: """A complete declarative description of a mathematical program, with no data in it. - Every group of entries is keyed by the name the file wrote, in the - order it wrote them, and is read-only: the mappings are wrapped at + Every group of entries is keyed by the name the file wrote, sorted by + name, and is read-only: the mappings are wrapped at construction, so a consumer cannot rewrite what another consumer reads. Every ``dims`` and ``frame`` in it is sorted by name, whatever order the file writes them in. A whole program is not hashable — the entries and expression nodes diff --git a/src/mathspec/spec.py b/src/mathspec/spec.py index 184ff165..c880e033 100644 --- a/src/mathspec/spec.py +++ b/src/mathspec/spec.py @@ -551,6 +551,11 @@ class GivenConditionSpec(_GivenEntrySpec): description: str | None = None +def _by_name(section: object) -> object: + """*section*'s entries sorted by name, so the order a file lists them in reaches nothing a consumer reads.""" + return dict(sorted(section.items())) if isinstance(section, dict) else section + + class GivenSpec(_StrictSpec): """What this file reads and does not build, by kind. Closed at the five kinds.""" @@ -567,6 +572,11 @@ class GivenSpec(_StrictSpec): #: Named conditions another file defines ([`GivenConditionSpec`][]). conditions: dict[str, GivenConditionSpec] = {} + @field_validator('*') + @classmethod + def _entries_by_name(cls, v: object) -> object: + return _by_name(v) + def __bool__(self) -> bool: """Whether the file reads anything it does not build.""" return bool(self.parameters or self.variables or self.constraints or self.expressions or self.conditions) @@ -684,7 +694,8 @@ class ExpressionSpec(_StrictSpec): #: The dimensions the quantity ranges over. ``cases:`` needs it, and a plain #: entry that leaves it out takes the dims of its body. dims: Dims | None = None - #: The regions, keyed by the name labelling the row each prints; every ``when`` is proved apart from the others. + #: The regions, keyed by the name labelling the row each prints and sorted by that name as the spec loads; + #: every ``when`` is proved apart from the others, so their order means nothing. cases: Annotated[dict[str, ExpressionCaseSpec], Field(min_length=1)] = {} #: The value wherever no case's ``when`` holds, printed as the last row. otherwise: Expression | None = None @@ -697,6 +708,11 @@ class ExpressionSpec(_StrictSpec): def _from_string(cls, data: object) -> object: return {'expression': data} if isinstance(data, str) else data + @field_validator('cases') + @classmethod + def _regions_by_name(cls, v: dict[str, ExpressionCaseSpec]) -> object: + return _by_name(v) + @model_validator(mode='after') def _one_form_or_the_other(self) -> Self: """One ``expression:``, or ``cases:`` with the ``otherwise:`` and ``dims:`` they need.""" @@ -1128,6 +1144,11 @@ def model_validate( except ValidationError as exc: raise schema_error(exc) from None + @field_validator('*') + @classmethod + def _entries_by_name(cls, v: object) -> object: + return _by_name(v) + @field_validator('version') @classmethod def _check_version(cls, v: int) -> int: diff --git a/tests/fixtures.py b/tests/fixtures.py index 07d380e6..efbe9ea2 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -106,6 +106,18 @@ def dims_reversed(data: Any) -> Any: return data +def entries_reversed(data: dict[str, Any]) -> dict[str, Any]: + """*data* with the entries of every section, and of each kind under ``given:``, in reverse order.""" + + def backwards(section: Any) -> Any: + return dict(reversed(section.items())) if isinstance(section, dict) else section + + return { + key: {kind: backwards(entries) for kind, entries in value.items()} if key == 'given' else backwards(value) + for key, value in data.items() + } + + def _columns_reversed(relation: Any) -> Any: """A relation entry with its ``key`` and ``values`` columns in reverse order.""" if not isinstance(relation, dict): diff --git a/tests/test_canonical.py b/tests/test_canonical.py index c9d5efb8..be2a9814 100644 --- a/tests/test_canonical.py +++ b/tests/test_canonical.py @@ -197,6 +197,18 @@ def _commitment_with_its_cases_reversed() -> dict[str, object]: return varied(raw, **{'expressions.previous_status.cases': dict(reversed(cases.items()))}) +def test_the_order_of_the_regions_under_cases_is_no_difference(): + """The regions are proved apart rather than tried in turn, so their order means nothing. A spec held them + as the file wrote them, so two files that state one spec wrote two texts and printed two documents.""" + written, reordered = ( + ms.to_spec(raw_of(EXAMPLES / 'commitment.yaml')), + ms.to_spec(_commitment_with_its_cases_reversed()), + ) + assert reordered.to_yaml(canonical=True) == written.to_yaml(canonical=True), 'one canonical text' + assert reordered.to_yaml() == written.to_yaml(), 'the spec writes the regions back sorted by name' + assert ms.to_latex(reordered) == ms.to_latex(written), 'the rows print sorted by name, otherwise last' + + def _piecewise_with_its_links_reversed() -> dict[str, object]: raw = raw_of(EXAMPLES / 'piecewise.yaml') return varied(raw, **{'piecewise.cost_curve.links': raw['piecewise']['cost_curve']['links'][::-1]}) @@ -205,11 +217,6 @@ def _piecewise_with_its_links_reversed() -> dict[str, object]: @pytest.mark.parametrize( ('written', 'reordered'), [ - pytest.param( - raw_of(EXAMPLES / 'commitment.yaml'), - _commitment_with_its_cases_reversed(), - id='the-regions-under-cases', - ), pytest.param( raw_of(EXAMPLES / 'piecewise.yaml'), _piecewise_with_its_links_reversed(), diff --git a/tests/test_conditions.py b/tests/test_conditions.py index a7aa7928..d6619dbc 100644 --- a/tests/test_conditions.py +++ b/tests/test_conditions.py @@ -189,7 +189,7 @@ def test_cases_split_by_a_named_condition_are_proved_apart_through_its_condition 'cases': {'on': {'when': 'a', 'expression': 1}, 'off': {'when': 'flag', 'expression': 2}}, 'otherwise': 0, } - with pytest.raises(LanguageError, match=r"cases 'on' and 'off' both claim the value where flag is true"): + with pytest.raises(LanguageError, match=r"cases 'off' and 'on' both claim the value where flag is true"): to_spec(varied(SMALL_MODEL, **{'conditions.a': 'flag', 'expressions.e': case})) apart = varied(case, **{'cases.off.when': 'NOT a'}) assert to_spec(varied(SMALL_MODEL, **{'conditions.a': 'flag', 'expressions.e': apart})) diff --git a/tests/test_dimensions.py b/tests/test_dimensions.py index 38c2e73b..2473f94b 100644 --- a/tests/test_dimensions.py +++ b/tests/test_dimensions.py @@ -37,7 +37,17 @@ WindowSum, children, ) -from tests.fixtures import DISPATCH_MODEL, EXAMPLES, SPECS, dims_reversed, expression_of, spec_of, varied, where_of +from tests.fixtures import ( + DISPATCH_MODEL, + EXAMPLES, + SPECS, + dims_reversed, + entries_reversed, + expression_of, + spec_of, + varied, + where_of, +) #: Every class an expression node is an instance of. EXPRESSION_NODES = get_args(Expression) @@ -886,6 +896,30 @@ def test_the_order_a_file_writes_a_list_in_reaches_no_value_of_the_spec(path): assert backwards.to_yaml() == spec.to_yaml(), 'so the spec writes back one text' +@pytest.mark.parametrize('path', SPECS, ids=lambda path: str(path.relative_to(EXAMPLES))) +def test_the_order_a_file_lists_its_entries_in_reaches_no_value_of_the_spec(path): + """A spec held each section's entries in the order its file listed them, so two files that state one spec + wrote back two texts and lowered to programs that list their entries in two orders.""" + spec = to_spec(path) + backwards = to_spec(entries_reversed(spec.to_dict())) + assert backwards.to_yaml() == spec.to_yaml(), 'the entries of each section are sorted as the spec loads' + for section in ( + 'dimensions', + 'relations', + 'parameters', + 'conditions', + 'variables', + 'expressions', + 'constraints', + 'sos', + 'piecewise', + 'assumptions', + ): + assert list(getattr(backwards.program, section)) == list(getattr(spec.program, section)), ( + f'so the program lists its {section} in one order' + ) + + def _dims_tuples(root: object) -> Iterator[tuple[str, tuple[str, ...]]]: """Every ``dims`` and ``frame`` a program holds, at any depth, under the name of the class that holds it. diff --git a/tests/test_lowering.py b/tests/test_lowering.py index e84a2dab..9891b66f 100644 --- a/tests/test_lowering.py +++ b/tests/test_lowering.py @@ -132,7 +132,7 @@ def shapes_spec() -> Spec: def test_program_structure(dispatch_program): - assert list(dispatch_program.parameters) == ['capacity', 'load', 'cost'], 'keyed by name, in file order' + assert list(dispatch_program.parameters) == ['capacity', 'cost', 'load'], 'keyed by name, sorted by name' ((vname, v),) = dispatch_program.variables.items() assert vname == 'dispatch' assert v.dims == ('generator', 'snapshot'), 'the frame is the dims, sorted by name' @@ -504,8 +504,8 @@ def test_a_condition_read_through_a_relation_is_lowered_and_keeps_the_relation_i def test_assumptions_carry_the_file_s_entries_and_the_curves_behind_them(): """One mapping holds every fact about the data, so a consumer attaching it has one loop and one refusal. - The file's entries come first, in the order it wrote them; each - ``piecewise:`` entry's conditions follow under the name a refusal quotes. + The file's entries and each ``piecewise:`` entry's conditions, under the + name a refusal quotes, stand in one mapping sorted by name. """ program = expanded(EXAMPLES / 'piecewise_lp.yaml', 'piecewise').program derived = [name for name in program.assumptions if name.startswith('cost_curve_')] @@ -514,11 +514,11 @@ def test_assumptions_carry_the_file_s_entries_and_the_curves_behind_them(): 'a method states its conditions in the language the file writes, so one kind stands in the mapping' ) assert derived == [ + 'cost_curve_breakpoints', 'cost_curve_complete', - 'cost_curve_increasing', 'cost_curve_curvature', - 'cost_curve_breakpoints', - ], 'an lp curve over a whole axis assumes four things of its breakpoints, completeness first' + 'cost_curve_increasing', + ], 'an lp curve over a whole axis assumes four things of its breakpoints, sorted by name' def test_an_assumption_lowers_both_of_its_masks(): diff --git a/tests/test_piecewise.py b/tests/test_piecewise.py index be9c7ebd..c9aca9ed 100644 --- a/tests/test_piecewise.py +++ b/tests/test_piecewise.py @@ -630,12 +630,12 @@ def test_an_entry_assumes_of_its_data_what_the_method_implies(): program = expanded(LP_MASKED, 'piecewise').program assert list(program.assumptions) == [ - 'cost_curve_complete', - 'cost_curve_increasing', - 'cost_curve_curvature', 'cost_curve_breakpoints', + 'cost_curve_complete', 'cost_curve_contiguous', - ], 'an lp curve with a mask assumes all five, each named after the entry that implies it' + 'cost_curve_curvature', + 'cost_curve_increasing', + ], 'an lp curve with a mask assumes all five, each named after the entry that implies it, sorted by name' assert all(isinstance(a, Assumption) for a in program.assumptions.values()), ( 'a method states its conditions in the same language the file does, so a consumer has one kind to read' ) diff --git a/tests/typesetting/golden/latex.out b/tests/typesetting/golden/latex.out index 7989b3a2..d6d511b7 100644 --- a/tests/typesetting/golden/latex.out +++ b/tests/typesetting/golden/latex.out @@ -9,33 +9,33 @@ \paragraph{Sets} \begin{description} -\item[{$\mathcal{T}$}] index $t$ --- \texttt{snapshot} (\texttt{int} coordinates) with $\mathrm{season\_of}: \mathcal{T} \to \mathcal{S},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T}$ -\item[{$\mathcal{G}$}] index $g$ --- \texttt{generator} with $\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}$, \texttt{connection} is \texttt{absent} where the data has no row -\item[{$\mathcal{B}$}] index $b$ --- \texttt{bus} with $\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}$, \texttt{area\_of} is \texttt{absent} where the data has no row, \texttt{connection} is \texttt{absent} where the data has no row -\item[{$\mathcal{Z}$}] index $z$ --- \texttt{zone} with $\mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}$, \texttt{area\_of} is \texttt{absent} where the data has no row +\item[{$\mathcal{B}$}] index $b$ --- \texttt{bp} +\item[{$\mathcal{U}$}] index $u$ --- \texttt{bus} with $\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}$, \texttt{area\_of} is \texttt{absent} where the data has no row, \texttt{connection} is \texttt{absent} where the data has no row +\item[{$\mathcal{G}$}] index $g$ --- \texttt{generator} with $\mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}$, \texttt{connection} is \texttt{absent} where the data has no row \item[{$\mathcal{S}$}] index $s$ --- \texttt{season} with $\mathrm{season\_of}: \mathcal{T} \to \mathcal{S}$ -\item[{$\mathcal{E}$}] index $e$ --- \texttt{technology} with $\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}$ -\item[{$\mathcal{A}$}] index $a$ --- \texttt{bp} +\item[{$\mathcal{T}$}] index $t$ --- \texttt{snapshot} (\texttt{int} coordinates) with $\mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T},\ \mathrm{season\_of}: \mathcal{T} \to \mathcal{S}$ +\item[{$\mathcal{E}$}] index $e$ --- \texttt{technology} with $\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E}$ +\item[{$\mathcal{Z}$}] index $z$ --- \texttt{zone} with $\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}$, \texttt{area\_of} is \texttt{absent} where the data has no row \end{description} \paragraph{Parameters} \begin{description} -\item[{$\mathrm{p}^{\mathrm{max}}$}] \texttt{p\_max} over $\mathcal{G}$, $\infty$ where the data has no row -\item[{$\mathrm{p}^{\mathrm{min}}$}] \texttt{p\_min} over $\mathcal{G}$ +\item[{$\mathrm{bp\_heat}$}] \texttt{bp\_heat} over $\mathcal{B} \times \mathcal{G}$ +\item[{$\mathrm{bp\_run}$}] \texttt{bp\_run} over $\mathcal{B} \times \mathcal{G}$ +\item[{$\mathrm{bp\_x}$}] \texttt{bp\_x} over $\mathcal{B} \times \mathcal{G}$, \texttt{neutral} where the data has no row +\item[{$\mathrm{bp\_y}$}] \texttt{bp\_y} over $\mathcal{B} \times \mathcal{G}$, \texttt{neutral} where the data has no row +\item[{$\mathrm{budget}$}] \texttt{budget} (scalar) \item[{$\mathrm{cost}$}] \texttt{cost} over $\mathcal{G}$, \texttt{neutral} where the data has no row -\item[{$\mathrm{load}$}] \texttt{load} over $\mathcal{B} \times \mathcal{T}$ -\item[{$\mathrm{is\_flexible}$}] \texttt{is\_flexible} over $\mathcal{G}$, \texttt{false} where the data has no row -\item[{$\mathrm{zone\_cap}$}] \texttt{zone\_cap} over $\mathcal{Z}$ -\item[{$\mathrm{tech\_cap}$}] \texttt{tech\_cap} over $\mathcal{B} \times \mathcal{E}$, \texttt{absent} where the data has no row -\item[{$\mathrm{min\_up}$}] \texttt{min\_up} over $\mathcal{G}$ \item[{$\mathrm{eta}$}] \texttt{eta} over $\mathcal{G}$ -\item[{$\mathrm{lead}$}] \texttt{lead} over $\mathcal{G}$ -\item[{$\mathrm{budget}$}] \texttt{budget} (scalar) \item[{$\mathrm{growth}$}] \texttt{growth} (scalar) -\item[{$\mathrm{bp\_x}$}] \texttt{bp\_x} over $\mathcal{A} \times \mathcal{G}$, \texttt{neutral} where the data has no row -\item[{$\mathrm{bp\_y}$}] \texttt{bp\_y} over $\mathcal{A} \times \mathcal{G}$, \texttt{neutral} where the data has no row -\item[{$\mathrm{bp\_heat}$}] \texttt{bp\_heat} over $\mathcal{A} \times \mathcal{G}$ -\item[{$\mathrm{bp\_run}$}] \texttt{bp\_run} over $\mathcal{A} \times \mathcal{G}$ +\item[{$\mathrm{is\_flexible}$}] \texttt{is\_flexible} over $\mathcal{G}$, \texttt{false} where the data has no row +\item[{$\mathrm{lead}$}] \texttt{lead} over $\mathcal{G}$ +\item[{$\mathrm{load}$}] \texttt{load} over $\mathcal{U} \times \mathcal{T}$ +\item[{$\mathrm{min\_up}$}] \texttt{min\_up} over $\mathcal{G}$ +\item[{$\mathrm{p}^{\mathrm{max}}$}] \texttt{p\_max} over $\mathcal{G}$, $\infty$ where the data has no row +\item[{$\mathrm{p}^{\mathrm{min}}$}] \texttt{p\_min} over $\mathcal{G}$ +\item[{$\mathrm{tech\_cap}$}] \texttt{tech\_cap} over $\mathcal{U} \times \mathcal{E}$, \texttt{absent} where the data has no row +\item[{$\mathrm{zone\_cap}$}] \texttt{zone\_cap} over $\mathcal{Z}$ \end{description} \paragraph{Conditions} @@ -46,30 +46,30 @@ \paragraph{Variables} \begin{description} -\item[{$p$}] \texttt{p} over $\mathcal{G} \times \mathcal{T}$ -\item[{$\mathit{spill}$}] \texttt{spill} over $\mathcal{T}$ -\item[{$\mathit{slack}$}] \texttt{slack} over $\mathcal{T}$ -\item[{$\theta$}] \texttt{theta} over $\mathcal{B}$ -\item[{$\mathit{on}$}] \texttt{on} over $\mathcal{G} \times \mathcal{T}$ -\item[{$\mathit{units}$}] \texttt{units} over $\mathcal{G}$ -\item[{$\mathit{spare}$}] \texttt{spare} over $\mathcal{G}$ -\item[{$\mathit{reserve}$}] \texttt{reserve} (scalar) -\item[{$\mathit{headroom}$}] \texttt{headroom} (scalar), \texttt{neutral} where the mask leaves it out -\item[{$\mathit{weight}$}] \texttt{weight} over $\mathcal{G} \times \mathcal{T}$ \item[{$\mathit{fuel}$}] \texttt{fuel} over $\mathcal{G} \times \mathcal{T}$ +\item[{$\mathit{headroom}$}] \texttt{headroom} (scalar), \texttt{neutral} where the mask leaves it out \item[{$\mathit{heat}$}] \texttt{heat} over $\mathcal{G} \times \mathcal{T}$ +\item[{$\mathit{on}$}] \texttt{on} over $\mathcal{G} \times \mathcal{T}$ \item[{$\mathit{op\_cost}$}] \texttt{op\_cost} over $\mathcal{G} \times \mathcal{T}$ +\item[{$p$}] \texttt{p} over $\mathcal{G} \times \mathcal{T}$ +\item[{$\mathit{reserve}$}] \texttt{reserve} (scalar) +\item[{$\mathit{slack}$}] \texttt{slack} over $\mathcal{T}$ +\item[{$\mathit{spare}$}] \texttt{spare} over $\mathcal{G}$ +\item[{$\mathit{spill}$}] \texttt{spill} over $\mathcal{T}$ +\item[{$\theta$}] \texttt{theta} over $\mathcal{U}$ +\item[{$\mathit{units}$}] \texttt{units} over $\mathcal{G}$ \item[{$\mathit{warm}$}] \texttt{warm} over $\mathcal{G} \times \mathcal{T}$ +\item[{$\mathit{weight}$}] \texttt{weight} over $\mathcal{G} \times \mathcal{T}$ \end{description} \paragraph{Definitions} \begin{description} -\item[{$\mathrm{spend}^{\mathrm{cap}}$}] \texttt{spend\_cap} over $\mathcal{G}$ -\item[{$\mathit{spend}$}] \texttt{spend} over $\mathcal{T}$ --- what a snapshot's dispatch costs -\item[{$\mathrm{rating}$}] \texttt{rating} over $\mathcal{G} \times \mathcal{T}$ \item[{$\mathit{lcoe}$}] \texttt{lcoe} (scalar) +\item[{$\mathit{marginal\_price}$}] \texttt{marginal\_price} over $\mathcal{U} \times \mathcal{T}$ \item[{$\mathit{net}$}] \texttt{net} over $\mathcal{T}$ --- what a snapshot spills, less what it lacks -\item[{$\mathit{marginal\_price}$}] \texttt{marginal\_price} over $\mathcal{B} \times \mathcal{T}$ +\item[{$\mathrm{rating}$}] \texttt{rating} over $\mathcal{G} \times \mathcal{T}$ +\item[{$\mathit{spend}$}] \texttt{spend} over $\mathcal{T}$ --- what a snapshot's dispatch costs +\item[{$\mathrm{spend}^{\mathrm{cap}}$}] \texttt{spend\_cap} over $\mathcal{G}$ \item[{$\mathrm{startup\_cost}$}] \texttt{startup\_cost} over $\mathcal{G} \times \mathcal{T}$ --- what starting a unit in this snapshot costs, which the horizon's edge changes \end{description} @@ -91,30 +91,30 @@ \paragraph{Variable domains} \begin{align} -\text{p} && \mathrm{p}^{\mathrm{min}}_{g} \le p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} > 0 \wedge \neg \mathrm{is\_flexible}_{g} \vee \mathrm{p}^{\mathrm{min}}_{g} > 0 \\ -\text{spill} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \\ -\text{slack} && \mathit{slack}_{t} & \le 100 && \forall\, t \in \mathcal{T} \\ -\text{theta} && \theta_{b} & \in \mathbb{R} && \forall\, b \in \mathcal{B} \\ -\text{on} && \mathit{on}_{g,t} & \in \{0, 1\} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{units} && 0 \le \mathit{units}_{g} & \le 10, \mathit{units}_{g} \in \mathbb{Z} && \forall\, g \in \mathcal{G} \\ -\text{spare} && \mathit{spare}_{g} & \in \mathbb{Z} && \forall\, g \in \mathcal{G} \\ -\text{reserve} && \mathit{reserve} & \ge 0 \\ -\text{headroom} && \mathit{headroom} & \ge 0 && \text{where } \mathrm{budget} \text{ is defined} \\ -\text{weight} && 0 \le \mathit{weight}_{g,t} & \le 1 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{fuel} && \mathit{fuel}_{g,t} & \ge 0 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{headroom} && \mathit{headroom} & \ge 0 && \text{where } \mathrm{budget} \text{ is defined} \\ \text{heat} && \mathit{heat}_{g,t} & \ge 0 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{on} && \mathit{on}_{g,t} & \in \{0, 1\} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{op\_cost} && \mathit{op\_cost}_{g,t} & \ge 0 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{warm} && \mathit{warm}_{g,t} & \in \{0, 1\} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{is\_flexible}_{g} +\text{p} && \mathrm{p}^{\mathrm{min}}_{g} \le p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} > 0 \wedge \neg \mathrm{is\_flexible}_{g} \vee \mathrm{p}^{\mathrm{min}}_{g} > 0 \\ +\text{reserve} && \mathit{reserve} & \ge 0 \\ +\text{slack} && \mathit{slack}_{t} & \le 100 && \forall\, t \in \mathcal{T} \\ +\text{spare} && \mathit{spare}_{g} & \in \mathbb{Z} && \forall\, g \in \mathcal{G} \\ +\text{spill} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \\ +\text{theta} && \theta_{u} & \in \mathbb{R} && \forall\, u \in \mathcal{U} \\ +\text{units} && 0 \le \mathit{units}_{g} & \le 10, \mathit{units}_{g} \in \mathbb{Z} && \forall\, g \in \mathcal{G} \\ +\text{warm} && \mathit{warm}_{g,t} & \in \{0, 1\} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{is\_flexible}_{g} \\ +\text{weight} && 0 \le \mathit{weight}_{g,t} & \le 1 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \end{align} \paragraph{Definitions} \begin{align} -\text{spend\_cap} && \mathrm{spend}^{\mathrm{cap}}_{g} & = \mathrm{cost}_{g} \cdot 2 && \forall\, g \in \mathcal{G} \\ -\text{spend} && \mathit{spend}_{t} & = \sum_{g \in \mathcal{G}} p_{g,t} \cdot \mathrm{cost}_{g} && \forall\, t \in \mathcal{T} \\ -\text{rating} && \mathrm{rating}_{g,t} & = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{b \in \mathcal{B}} \mathrm{load}_{b,t} \right) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{lcoe} && \mathit{lcoe} & = \frac{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \cdot \mathrm{cost}_{g}}{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t}} \\ +\text{marginal\_price} && \mathit{marginal\_price}_{u,t} & = \lambda_{\mathrm{balance},u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \\ \text{net} && \mathit{net}_{t} & = -\mathit{spill}_{t} + \mathit{slack}_{t} && \forall\, t \in \mathcal{T} \\ -\text{marginal\_price} && \mathit{marginal\_price}_{b,t} & = \lambda_{\mathrm{balance},b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \\ +\text{rating} && \mathrm{rating}_{g,t} & = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{u \in \mathcal{U}} \mathrm{load}_{u,t} \right) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{spend} && \mathit{spend}_{t} & = \sum_{g \in \mathcal{G}} p_{g,t} \cdot \mathrm{cost}_{g} && \forall\, t \in \mathcal{T} \\ +\text{spend\_cap} && \mathrm{spend}^{\mathrm{cap}}_{g} & = \mathrm{cost}_{g} \cdot 2 && \forall\, g \in \mathcal{G} \\ \text{startup\_cost} && \mathrm{startup\_cost}_{g,t} & = \begin{cases} \mathrm{cost}_{g} & \text{if } \mathrm{pos}(t) = 0 \\ \mathrm{cost}_{g} \cdot 2 & \text{if } \mathrm{pos}(t) > 0 \wedge \mathrm{season\_of}(t) = \text{'}\mathrm{winter}\text{'} \\ 0 & \text{otherwise} \end{cases} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \end{align} @@ -125,88 +125,88 @@ \paragraph{Subject to} \begin{align} -\text{budgeted} && \mathit{spend}_{t} & \le \mathrm{budget} && \forall\, t \in \mathcal{T} \\ -\text{starts} && p_{g,t} & \le \mathrm{startup\_cost}_{g,t} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{under\_rating} && p_{g,t} & \le \mathrm{rating}_{g,t} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{balance} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} & = \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \\ -\text{netted} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{net}_{t} & = \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \\ -\text{ramp} && p_{g,t} - p_{g,t \ominus 1} & \le p_{g,t - 1} + \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{edges} && p_{g,t \boxminus_{0} 1} & \le p_{g,t \boxplus_{0} 1} + \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{ahead} && p_{g,t} & \le p_{g,t \oplus 1} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{always} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \\ +\text{arithmetic} && \sum_{g \in \mathcal{G}} \left( \frac{p_{g,t}}{2} - \mathrm{cost}_{g} + 10^{-5} \cdot p_{g,t} + 2.5 \times 10^{-7} \cdot \mathrm{cost}_{g} + 0.5 \cdot p_{g,t} \right) & \ge -\left( \sum_{g \in \mathcal{G}} p_{g,t} \right) \cdot \left( -3 \right) && \forall\, t \in \mathcal{T} \\ +\text{balance} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} & = \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \\ +\text{budgeted} && \mathit{spend}_{t} & \le \mathrm{budget} && \forall\, t \in \mathcal{T} \\ +\text{capped} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{spend}^{\mathrm{cap}}_{g} > 0 \vee \neg \mathrm{is\_flexible}_{g} \\ +\text{ceiling} && \theta_{u} & \le \infty && \forall\, u \in \mathcal{U} \\ \text{composed} && p_{g,t - 2} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{uncomposed} && p_{g,\left( t - 1 \right) \boxminus_{0} \mathrm{lead}} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{connected} && p_{g,t} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( u,\ g \right) \in \mathrm{connection} \\ +\text{counted} && \theta_{u} & \le \mathrm{budget} && \forall\, u \in \mathcal{U} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e} > 0 \} \rvert \ge 2 \\ +\text{counted\_here} && \theta_{u} & \le \mathrm{tech\_cap}_{u,e} && \forall\, u \in \mathcal{U},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e'} > 0 \} \rvert \ge 2 \\ +\text{covered} && \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} & \le \mathrm{budget} && \text{where } \sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} \\ \text{crossed} && p_{g + 1,t \ominus 1} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{lead\_time} && p_{g,t \boxminus_{0} \mathrm{lead}} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{in\_season} && p_{g,t} & \le p_{g,t \ominus^{\mathrm{season\_of}(t)} 1} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{edges} && p_{g,t \boxminus_{0} 1} & \le p_{g,t \boxplus_{0} 1} + \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{efficiency} && p_{g,t} & \le \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{first} && \mathit{on}_{g,t} & = 1 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = 0 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = 0 \\ +\text{grouped\_once} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = u \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} & \le \mathrm{tech\_cap}_{u,e} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T},\ e \in \mathcal{E} \\ \text{held\_in\_season} && p_{g,t} & \le p_{g,t \boxminus_{0}^{\mathrm{season\_of}(t)} 1} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{window} && \sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < 3} \mathit{on}_{g,t'} & \le \mathit{units}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{history} && \sum_{t' \in \mathcal{T} \,:\, 0 \le t \ominus t' < \mathrm{min\_up}} \mathit{on}_{g,t'} & \le \mathit{units}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{seasonal\_window} && \sum_{t' \in \mathcal{T} \,:\, 0 \le t -^{\mathrm{season\_of}(t)} t' < 3} \mathit{on}_{g,t'} & \le \mathit{units}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{lookup} && \mathit{spill}_{t} & \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \\ -\text{grouped\_once} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = b \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} & \le \mathrm{tech\_cap}_{b,e} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T},\ e \in \mathcal{E} \\ +\text{in\_season} && p_{g,t} & \le p_{g,t \ominus^{\mathrm{season\_of}(t)} 1} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{last} && \mathit{on}_{g,t} & = 0 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = \lvert \mathcal{T} \rvert - 1 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = \lvert \mathcal{T}_{\mathrm{season\_of}(t)} \rvert - 1 \\ +\text{lead\_time} && p_{g,t \boxminus_{0} \mathrm{lead}} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ \text{looked\_up\_once} && \mathit{units}_{g} & \le \mathrm{tech\_cap}_{\mathrm{gen\_bt.bus}(g),\mathrm{gen\_bt.technology}(g)} && \forall\, g \in \mathcal{G} \\ -\text{within\_bus} && \mathit{units}_{g} & \le \mathit{units}_{g \boxminus_{0}^{\mathrm{gen\_bt.bus}(g)} 1} && \forall\, g \in \mathcal{G} \,:\, \mathrm{pos}_{\left( \mathrm{gen\_bt.bus}(g),\ \mathrm{gen\_bt.technology}(g) \right)}(g) = 0 \\ -\text{relational} && \sum_{g \in \mathcal{G} \,:\, \left( b,\ g \right) \in \mathrm{connection}} p_{g,t} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \\ -\text{connected} && p_{g,t} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( b,\ g \right) \in \mathrm{connection} \\ +\text{lookup} && \mathit{spill}_{t} & \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \\ +\text{margin} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} - \mathrm{p}^{\mathrm{min}}_{g} > \frac{\mathrm{cost}_{g}}{2} \\ +\text{masked} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{priced\_dispatch}_{g} \wedge \mathrm{pos}(t) > 0 \\ +\text{netted} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{net}_{t} & = \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \\ +\text{never} && \mathit{slack}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \,:\, \bot \\ +\text{northern} && \mathit{slack}_{t} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(u) \neq \mathrm{area\_of}(u) \wedge \mathrm{zone\_of}(u) \text{ is defined} \\ +\text{ramp} && p_{g,t} - p_{g,t \ominus 1} & \le p_{g,t - 1} + \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{ramped} && \mathit{slack}_{t} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \wedge \mathrm{pos}(t) > 0 \\ +\text{redundant} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \,:\, \mathit{spill}_{t} \text{ exists} \\ +\text{relational} && \sum_{g \in \mathcal{G} \,:\, \left( u,\ g \right) \in \mathrm{connection}} p_{g,t} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \\ \text{representative} && \sum_{t' \in \mathcal{T} \,:\, \mathrm{rep\_of}(t') = t} \mathit{spill}_{t'} & \le \mathit{spill}_{\mathrm{rep\_of}(t)} && \forall\, t \in \mathcal{T} \\ +\text{run\_start} && \mathit{slack}_{t} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{u,t - 1} \text{ is defined} \right) \\ +\text{running} && \theta_{u} & \le \mathrm{load}_{u,t} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \theta_{u} \text{ exists} \wedge t \ge 3 \\ +\text{scalar} && \mathit{units}_{g} & \le \mathrm{budget} && \forall\, g \in \mathcal{G} \,:\, \mathrm{cost}_{g} \text{ is defined} \\ +\text{seasonal\_window} && \sum_{t' \in \mathcal{T} \,:\, 0 \le t -^{\mathrm{season\_of}(t)} t' < 3} \mathit{on}_{g,t'} & \le \mathit{units}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{starts} && p_{g,t} & \le \mathrm{startup\_cost}_{g,t} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{total} && \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} & \le \mathrm{budget} \\ +\text{uncomposed} && p_{g,\left( t - 1 \right) \boxminus_{0} \mathrm{lead}} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{under\_rating} && p_{g,t} & \le \mathrm{rating}_{g,t} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{window} && \sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < 3} \mathit{on}_{g,t'} & \le \mathit{units}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{within\_bus} && \mathit{units}_{g} & \le \mathit{units}_{g \boxminus_{0}^{\mathrm{gen\_bt.bus}(g)} 1} && \forall\, g \in \mathcal{G} \,:\, \mathrm{pos}_{\left( \mathrm{gen\_bt.bus}(g),\ \mathrm{gen\_bt.technology}(g) \right)}(g) = 0 \\ \text{zonal} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} & \le \mathrm{zone\_cap}_{z} && \forall\, t \in \mathcal{T},\ z \in \mathcal{Z} \\ \text{zonal\_history} && \sum_{t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} & \le \mathrm{zone\_cap}_{z} && \forall\, g \in \mathcal{G},\ z \in \mathcal{Z} \\ -\text{zonal\_membership} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) \text{ is defined}} \mathit{units}_{g} & \le \mathrm{budget} && \forall\, t \in \mathcal{T} \\ \text{zonal\_lookup} && p_{g,t} & \le \mathit{spill}_{t} \cdot \mathrm{zone\_cap}_{\mathrm{gen\_zone}(g,\ t)} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{pos}_{\mathrm{gen\_zone}(g,\ t)}(g) = 0 \\ -\text{arithmetic} && \sum_{g \in \mathcal{G}} \left( \frac{p_{g,t}}{2} - \mathrm{cost}_{g} + 10^{-5} \cdot p_{g,t} + 2.5 \times 10^{-7} \cdot \mathrm{cost}_{g} + 0.5 \cdot p_{g,t} \right) & \ge -\left( \sum_{g \in \mathcal{G}} p_{g,t} \right) \cdot \left( -3 \right) && \forall\, t \in \mathcal{T} \\ -\text{total} && \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} & \le \mathrm{budget} \\ -\text{scalar} && \mathit{units}_{g} & \le \mathrm{budget} && \forall\, g \in \mathcal{G} \,:\, \mathrm{cost}_{g} \text{ is defined} \\ -\text{running} && \theta_{b} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \theta_{b} \text{ exists} \wedge t \ge 3 \\ -\text{first} && \mathit{on}_{g,t} & = 1 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = 0 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = 0 \\ -\text{last} && \mathit{on}_{g,t} & = 0 && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = \lvert \mathcal{T} \rvert - 1 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = \lvert \mathcal{T}_{\mathrm{season\_of}(t)} \rvert - 1 \\ -\text{northern} && \mathit{slack}_{t} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(b) \neq \mathrm{area\_of}(b) \wedge \mathrm{zone\_of}(b) \text{ is defined} \\ -\text{efficiency} && p_{g,t} & \le \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{ceiling} && \theta_{b} & \le \infty && \forall\, b \in \mathcal{B} \\ -\text{always} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \\ -\text{redundant} && \mathit{spill}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \,:\, \mathit{spill}_{t} \text{ exists} \\ -\text{never} && \mathit{slack}_{t} & \ge 0 && \forall\, t \in \mathcal{T} \,:\, \bot \\ -\text{margin} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} - \mathrm{p}^{\mathrm{min}}_{g} > \frac{\mathrm{cost}_{g}}{2} \\ -\text{ramped} && \mathit{slack}_{t} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \wedge \mathrm{pos}(t) > 0 \\ -\text{covered} && \sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} & \le \mathrm{budget} && \text{where } \sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} \\ -\text{counted} && \theta_{b} & \le \mathrm{budget} && \forall\, b \in \mathcal{B} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e} > 0 \} \rvert \ge 2 \\ -\text{counted\_here} && \theta_{b} & \le \mathrm{tech\_cap}_{b,e} && \forall\, b \in \mathcal{B},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e'} > 0 \} \rvert \ge 2 \\ -\text{run\_start} && \mathit{slack}_{t} & \le \mathrm{load}_{b,t} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{b,t - 1} \text{ is defined} \right) \\ -\text{zoned} && \theta_{b} & \le \mathrm{budget} && \forall\, b \in \mathcal{B} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \text{ is defined} \\ -\text{capped} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{spend}^{\mathrm{cap}}_{g} > 0 \vee \neg \mathrm{is\_flexible}_{g} \\ -\text{masked} && p_{g,t} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{priced\_dispatch}_{g} \wedge \mathrm{pos}(t) > 0 \\ +\text{zonal\_membership} && \sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) \text{ is defined}} \mathit{units}_{g} & \le \mathrm{budget} && \forall\, t \in \mathcal{T} \\ +\text{zoned} && \theta_{u} & \le \mathrm{budget} && \forall\, u \in \mathcal{U} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \text{ is defined} \\ \text{adjacent} && \left( \mathit{weight}_{g,t} \right)_{g \in \mathcal{G}} & \in \mathrm{SOS}2 && \forall\, t \in \mathcal{T} \\ -\text{fuel\_curve} && \left( p_{g,t},\ \mathit{fuel}_{g,t},\ \mathit{heat}_{g,t} \right) & \in \mathit{on}_{g,t} \cdot \mathrm{pwl}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g},\ \mathrm{bp\_heat}_{a,g}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{cost\_curve} && \mathit{op\_cost}_{g,t} & \ge \begin{cases} \mathit{warm}_{g,t} & \text{if } \mathrm{is\_flexible}_{g} \\ 1 & \text{otherwise} \end{cases} \cdot \mathrm{pwl}_{a \in \mathcal{A} \,:\, \mathrm{bp\_run}_{a,g}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{hull\_curve} && \left( p_{g,t},\ \mathit{fuel}_{g,t} \right) & \in \mathrm{conv}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_heat}_{a,g}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{lp\_curve} && \mathit{fuel}_{g,t} & \ge \mathrm{pwl}_{a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ -\text{ramp\_curve} && \mathit{heat}_{g,t} & \le \mathrm{pwl}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_heat}_{a,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\text{cost\_curve} && \mathit{op\_cost}_{g,t} & \ge \begin{cases} \mathit{warm}_{g,t} & \text{if } \mathrm{is\_flexible}_{g} \\ 1 & \text{otherwise} \end{cases} \cdot \mathrm{pwl}_{b \in \mathcal{B} \,:\, \mathrm{bp\_run}_{b,g}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{fuel\_curve} && \left( p_{g,t},\ \mathit{fuel}_{g,t},\ \mathit{heat}_{g,t} \right) & \in \mathit{on}_{g,t} \cdot \mathrm{pwl}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g},\ \mathrm{bp\_heat}_{b,g}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{hull\_curve} && \left( p_{g,t},\ \mathit{fuel}_{g,t} \right) & \in \mathrm{conv}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_heat}_{b,g}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{lp\_curve} && \mathit{fuel}_{g,t} & \ge \mathrm{pwl}_{b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \\ +\text{ramp\_curve} && \mathit{heat}_{g,t} & \le \mathrm{pwl}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_heat}_{b,g})(p_{g,t}) && \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \end{align} \paragraph{Assumptions} \begin{align} \text{bounds\_do\_not\_cross} && \mathrm{p}^{\mathrm{min}}_{g} & \le \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G} \\ -\text{efficiency\_is\_a\_fraction} && \mathrm{eta}_{g} > 0 \wedge \mathrm{eta}_{g} \le 1 & && \forall\, g \in \mathcal{G} \\ -\text{lead\_times\_are\_short} && \mathrm{lead}_{g} & \le 3 && \forall\, g \in \mathcal{G} \\ -\text{zones\_agree} && \mathrm{zone\_of}(b) & = \mathrm{area\_of}(b) && \forall\, b \in \mathcal{B} \\ \text{budget\_covers\_the\_peak} && \sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} & \ge \mathrm{budget} \\ -\text{ramps\_are\_gentle} && \mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} & \le \mathrm{budget} && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 \\ +\text{efficiency\_is\_a\_fraction} && \mathrm{eta}_{g} > 0 \wedge \mathrm{eta}_{g} \le 1 & && \forall\, g \in \mathcal{G} \\ \text{flexible\_units\_have\_headroom} && \mathrm{p}^{\mathrm{min}}_{g} & < \mathrm{p}^{\mathrm{max}}_{g} && \forall\, g \in \mathcal{G} \,:\, \mathrm{is\_flexible}_{g} \\ -\text{northern\_demand\_is\_real} && \mathrm{load}_{b,t} & \ge 0 && \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} \\ -\text{fuel\_curve\_complete} && \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} & && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \\ -\text{cost\_curve\_complete} && \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} & && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_run}_{a,g} \\ -\text{cost\_curve\_contiguous} && \lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_run}_{a,g} \wedge \neg \mathrm{bp\_run}_{a - 1,g} \} \rvert & = 1 && \forall\, g \in \mathcal{G} \\ -\text{hull\_curve\_complete} && \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} & && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \\ -\text{hull\_curve\_increasing} && \mathrm{bp\_x}_{a \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{a,g} && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 \\ -\text{hull\_curve\_curvature} && \lvert \{ a \in \mathcal{A} \,:\, \left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) > \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 \} \rvert = 0 \vee \lvert \{ a \in \mathcal{A} \,:\, \left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) < \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 \} \rvert = 0 & && \forall\, g \in \mathcal{G} \\ -\text{lp\_curve\_complete} && \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} & && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \\ -\text{lp\_curve\_increasing} && \mathrm{bp\_x}_{a \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{a,g} && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a - 1,g} \text{ is defined} \\ -\text{lp\_curve\_curvature} && \left( \mathrm{bp\_y}_{a,g} - \mathrm{bp\_y}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) & \le \left( \mathrm{bp\_y}_{a \boxplus_{0} 1,g} - \mathrm{bp\_y}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a - 1,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a + 1,g} \text{ is defined} \\ -\text{lp\_curve\_breakpoints} && \lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \} \rvert & \ge 2 && \forall\, g \in \mathcal{G} \\ -\text{lp\_curve\_contiguous} && \lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \neg \left( \mathrm{bp\_x}_{a - 1,g} \text{ is defined} \right) \} \rvert & = 1 && \forall\, g \in \mathcal{G} \\ -\text{ramp\_curve\_complete} && \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} & && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \\ -\text{ramp\_curve\_increasing} && \mathrm{bp\_x}_{a \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{a,g} && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 \\ -\text{ramp\_curve\_curvature} && \left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) & \ge \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) && \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 \\ -\text{ramp\_curve\_breakpoints} && \lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \} \rvert & \ge 2 && \forall\, g \in \mathcal{G} +\text{lead\_times\_are\_short} && \mathrm{lead}_{g} & \le 3 && \forall\, g \in \mathcal{G} \\ +\text{northern\_demand\_is\_real} && \mathrm{load}_{u,t} & \ge 0 && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} \\ +\text{ramps\_are\_gentle} && \mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} & \le \mathrm{budget} && \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 \\ +\text{zones\_agree} && \mathrm{zone\_of}(u) & = \mathrm{area\_of}(u) && \forall\, u \in \mathcal{U} \\ +\text{cost\_curve\_complete} && \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} & && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_run}_{b,g} \\ +\text{cost\_curve\_contiguous} && \lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_run}_{b,g} \wedge \neg \mathrm{bp\_run}_{b - 1,g} \} \rvert & = 1 && \forall\, g \in \mathcal{G} \\ +\text{fuel\_curve\_complete} && \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} & && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \\ +\text{hull\_curve\_complete} && \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} & && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \\ +\text{hull\_curve\_increasing} && \mathrm{bp\_x}_{b \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{b,g} && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 \\ +\text{hull\_curve\_curvature} && \lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) > \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \vee \lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) < \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 & && \forall\, g \in \mathcal{G} \\ +\text{lp\_curve\_complete} && \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} & && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \\ +\text{lp\_curve\_increasing} && \mathrm{bp\_x}_{b \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{b,g} && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b - 1,g} \text{ is defined} \\ +\text{lp\_curve\_curvature} && \left( \mathrm{bp\_y}_{b,g} - \mathrm{bp\_y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) & \le \left( \mathrm{bp\_y}_{b \boxplus_{0} 1,g} - \mathrm{bp\_y}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b - 1,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b + 1,g} \text{ is defined} \\ +\text{lp\_curve\_breakpoints} && \lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \} \rvert & \ge 2 && \forall\, g \in \mathcal{G} \\ +\text{lp\_curve\_contiguous} && \lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \neg \left( \mathrm{bp\_x}_{b - 1,g} \text{ is defined} \right) \} \rvert & = 1 && \forall\, g \in \mathcal{G} \\ +\text{ramp\_curve\_complete} && \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} & && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \\ +\text{ramp\_curve\_increasing} && \mathrm{bp\_x}_{b \boxminus_{0} 1,g} & < \mathrm{bp\_x}_{b,g} && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 \\ +\text{ramp\_curve\_curvature} && \left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) & \ge \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) && \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \\ +\text{ramp\_curve\_breakpoints} && \lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \} \rvert & \ge 2 && \forall\, g \in \mathcal{G} \end{align} \end{document} diff --git a/tests/typesetting/golden/markdown.out b/tests/typesetting/golden/markdown.out index 67683978..560b8ea6 100644 --- a/tests/typesetting/golden/markdown.out +++ b/tests/typesetting/golden/markdown.out @@ -6,34 +6,34 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 | Symbol | Meaning | |---|---| -| $`\mathcal{T}`$ | index $`t`$ — `snapshot` (`int` coordinates) with $`\mathrm{season\_of}: \mathcal{T} \to \mathcal{S},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T}`$ | -| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$, `connection` is `absent` where the data has no row | -| $`\mathcal{B}`$ | index $`b`$ — `bus` with $`\mathrm{gen\_bus}: \mathcal{G} \to \mathcal{B},\ \mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{B} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row | -| $`\mathcal{Z}`$ | index $`z`$ — `zone` with $`\mathrm{zone\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{area\_of}: \mathcal{B} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row | +| $`\mathcal{B}`$ | index $`b`$ — `bp` | +| $`\mathcal{U}`$ | index $`u`$ — `bus` with $`\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row | +| $`\mathcal{G}`$ | index $`g`$ — `generator` with $`\mathrm{connection} \subseteq \mathcal{U} \times \mathcal{G},\ \mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E},\ \mathrm{gen\_bus}: \mathcal{G} \to \mathcal{U},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z}`$, `connection` is `absent` where the data has no row | | $`\mathcal{S}`$ | index $`s`$ — `season` with $`\mathrm{season\_of}: \mathcal{T} \to \mathcal{S}`$ | -| $`\mathcal{E}`$ | index $`e`$ — `technology` with $`\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{B} \times \mathcal{E}`$ | -| $`\mathcal{A}`$ | index $`a`$ — `bp` | +| $`\mathcal{T}`$ | index $`t`$ — `snapshot` (`int` coordinates) with $`\mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{rep\_of}: \mathcal{T} \to \mathcal{T},\ \mathrm{season\_of}: \mathcal{T} \to \mathcal{S}`$ | +| $`\mathcal{E}`$ | index $`e`$ — `technology` with $`\mathrm{gen\_bt}: \mathcal{G} \to \mathcal{U} \times \mathcal{E}`$ | +| $`\mathcal{Z}`$ | index $`z`$ — `zone` with $`\mathrm{area\_of}: \mathcal{U} \to \mathcal{Z},\ \mathrm{gen\_zone}: \mathcal{G} \times \mathcal{T} \to \mathcal{Z},\ \mathrm{zone\_of}: \mathcal{U} \to \mathcal{Z}`$, `area_of` is `absent` where the data has no row | #### Parameters | Symbol | Meaning | |---|---| -| $`\mathrm{p}^{\mathrm{max}}`$ | `p_max` over $`\mathcal{G}`$, $`\infty`$ where the data has no row | -| $`\mathrm{p}^{\mathrm{min}}`$ | `p_min` over $`\mathcal{G}`$ | +| $`\mathrm{bp\_heat}`$ | `bp_heat` over $`\mathcal{B} \times \mathcal{G}`$ | +| $`\mathrm{bp\_run}`$ | `bp_run` over $`\mathcal{B} \times \mathcal{G}`$ | +| $`\mathrm{bp\_x}`$ | `bp_x` over $`\mathcal{B} \times \mathcal{G}`$, `neutral` where the data has no row | +| $`\mathrm{bp\_y}`$ | `bp_y` over $`\mathcal{B} \times \mathcal{G}`$, `neutral` where the data has no row | +| $`\mathrm{budget}`$ | `budget` (scalar) | | $`\mathrm{cost}`$ | `cost` over $`\mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{load}`$ | `load` over $`\mathcal{B} \times \mathcal{T}`$ | -| $`\mathrm{is\_flexible}`$ | `is_flexible` over $`\mathcal{G}`$, `false` where the data has no row | -| $`\mathrm{zone\_cap}`$ | `zone_cap` over $`\mathcal{Z}`$ | -| $`\mathrm{tech\_cap}`$ | `tech_cap` over $`\mathcal{B} \times \mathcal{E}`$, `absent` where the data has no row | -| $`\mathrm{min\_up}`$ | `min_up` over $`\mathcal{G}`$ | | $`\mathrm{eta}`$ | `eta` over $`\mathcal{G}`$ | -| $`\mathrm{lead}`$ | `lead` over $`\mathcal{G}`$ | -| $`\mathrm{budget}`$ | `budget` (scalar) | | $`\mathrm{growth}`$ | `growth` (scalar) | -| $`\mathrm{bp\_x}`$ | `bp_x` over $`\mathcal{A} \times \mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{bp\_y}`$ | `bp_y` over $`\mathcal{A} \times \mathcal{G}`$, `neutral` where the data has no row | -| $`\mathrm{bp\_heat}`$ | `bp_heat` over $`\mathcal{A} \times \mathcal{G}`$ | -| $`\mathrm{bp\_run}`$ | `bp_run` over $`\mathcal{A} \times \mathcal{G}`$ | +| $`\mathrm{is\_flexible}`$ | `is_flexible` over $`\mathcal{G}`$, `false` where the data has no row | +| $`\mathrm{lead}`$ | `lead` over $`\mathcal{G}`$ | +| $`\mathrm{load}`$ | `load` over $`\mathcal{U} \times \mathcal{T}`$ | +| $`\mathrm{min\_up}`$ | `min_up` over $`\mathcal{G}`$ | +| $`\mathrm{p}^{\mathrm{max}}`$ | `p_max` over $`\mathcal{G}`$, $`\infty`$ where the data has no row | +| $`\mathrm{p}^{\mathrm{min}}`$ | `p_min` over $`\mathcal{G}`$ | +| $`\mathrm{tech\_cap}`$ | `tech_cap` over $`\mathcal{U} \times \mathcal{E}`$, `absent` where the data has no row | +| $`\mathrm{zone\_cap}`$ | `zone_cap` over $`\mathcal{Z}`$ | #### Conditions @@ -46,31 +46,31 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 | Symbol | Meaning | |---|---| -| $`p`$ | `p` over $`\mathcal{G} \times \mathcal{T}`$ | -| $`\mathit{spill}`$ | `spill` over $`\mathcal{T}`$ | -| $`\mathit{slack}`$ | `slack` over $`\mathcal{T}`$ | -| $`\theta`$ | `theta` over $`\mathcal{B}`$ | -| $`\mathit{on}`$ | `on` over $`\mathcal{G} \times \mathcal{T}`$ | -| $`\mathit{units}`$ | `units` over $`\mathcal{G}`$ | -| $`\mathit{spare}`$ | `spare` over $`\mathcal{G}`$ | -| $`\mathit{reserve}`$ | `reserve` (scalar) | -| $`\mathit{headroom}`$ | `headroom` (scalar), `neutral` where the mask leaves it out | -| $`\mathit{weight}`$ | `weight` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{fuel}`$ | `fuel` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{headroom}`$ | `headroom` (scalar), `neutral` where the mask leaves it out | | $`\mathit{heat}`$ | `heat` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{on}`$ | `on` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{op\_cost}`$ | `op_cost` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`p`$ | `p` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{reserve}`$ | `reserve` (scalar) | +| $`\mathit{slack}`$ | `slack` over $`\mathcal{T}`$ | +| $`\mathit{spare}`$ | `spare` over $`\mathcal{G}`$ | +| $`\mathit{spill}`$ | `spill` over $`\mathcal{T}`$ | +| $`\theta`$ | `theta` over $`\mathcal{U}`$ | +| $`\mathit{units}`$ | `units` over $`\mathcal{G}`$ | | $`\mathit{warm}`$ | `warm` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{weight}`$ | `weight` over $`\mathcal{G} \times \mathcal{T}`$ | #### Definitions | Symbol | Meaning | |---|---| -| $`\mathrm{spend}^{\mathrm{cap}}`$ | `spend_cap` over $`\mathcal{G}`$ | -| $`\mathit{spend}`$ | `spend` over $`\mathcal{T}`$ — what a snapshot's dispatch costs | -| $`\mathrm{rating}`$ | `rating` over $`\mathcal{G} \times \mathcal{T}`$ | | $`\mathit{lcoe}`$ | `lcoe` (scalar) | +| $`\mathit{marginal\_price}`$ | `marginal_price` over $`\mathcal{U} \times \mathcal{T}`$ | | $`\mathit{net}`$ | `net` over $`\mathcal{T}`$ — what a snapshot spills, less what it lacks | -| $`\mathit{marginal\_price}`$ | `marginal_price` over $`\mathcal{B} \times \mathcal{T}`$ | +| $`\mathrm{rating}`$ | `rating` over $`\mathcal{G} \times \mathcal{T}`$ | +| $`\mathit{spend}`$ | `spend` over $`\mathcal{T}`$ — what a snapshot's dispatch costs | +| $`\mathrm{spend}^{\mathrm{cap}}`$ | `spend_cap` over $`\mathcal{G}`$ | | $`\mathrm{startup\_cost}`$ | `startup_cost` over $`\mathcal{G} \times \mathcal{T}`$ — what starting a unit in this snapshot costs, which the horizon's edge changes | #### Notation @@ -100,28 +100,22 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 #### Variable domains -**`p`** - -```math -\mathrm{p}^{\mathrm{min}}_{g} \le p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} > 0 \wedge \neg \mathrm{is\_flexible}_{g} \vee \mathrm{p}^{\mathrm{min}}_{g} > 0 -``` - -**`spill`** +**`fuel`** ```math -\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} +\mathit{fuel}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`slack`** +**`headroom`** ```math -\mathit{slack}_{t} \le 100 \qquad \forall\, t \in \mathcal{T} +\mathit{headroom} \ge 0 \qquad \text{where } \mathrm{budget} \text{ is defined} ``` -**`theta`** +**`heat`** ```math -\theta_{b} \in \mathbb{R} \qquad \forall\, b \in \mathcal{B} +\mathit{heat}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` **`on`** @@ -130,16 +124,16 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 \mathit{on}_{g,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`units`** +**`op_cost`** ```math -0 \le \mathit{units}_{g} \le 10, \mathit{units}_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} +\mathit{op\_cost}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`spare`** +**`p`** ```math -\mathit{spare}_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} +\mathrm{p}^{\mathrm{min}}_{g} \le p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} > 0 \wedge \neg \mathrm{is\_flexible}_{g} \vee \mathrm{p}^{\mathrm{min}}_{g} > 0 ``` **`reserve`** @@ -148,34 +142,34 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 \mathit{reserve} \ge 0 ``` -**`headroom`** +**`slack`** ```math -\mathit{headroom} \ge 0 \qquad \text{where } \mathrm{budget} \text{ is defined} +\mathit{slack}_{t} \le 100 \qquad \forall\, t \in \mathcal{T} ``` -**`weight`** +**`spare`** ```math -0 \le \mathit{weight}_{g,t} \le 1 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{spare}_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} ``` -**`fuel`** +**`spill`** ```math -\mathit{fuel}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} ``` -**`heat`** +**`theta`** ```math -\mathit{heat}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\theta_{u} \in \mathbb{R} \qquad \forall\, u \in \mathcal{U} ``` -**`op_cost`** +**`units`** ```math -\mathit{op\_cost}_{g,t} \ge 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +0 \le \mathit{units}_{g} \le 10, \mathit{units}_{g} \in \mathbb{Z} \qquad \forall\, g \in \mathcal{G} ``` **`warm`** @@ -184,42 +178,48 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 \mathit{warm}_{g,t} \in \{0, 1\} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{is\_flexible}_{g} ``` +**`weight`** + +```math +0 \le \mathit{weight}_{g,t} \le 1 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +``` + #### Definitions -**`spend_cap`** +**`lcoe`** ```math -\mathrm{spend}^{\mathrm{cap}}_{g} = \mathrm{cost}_{g} \cdot 2 \qquad \forall\, g \in \mathcal{G} +\mathit{lcoe} = \frac{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \cdot \mathrm{cost}_{g}}{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t}} ``` -**`spend`** +**`marginal_price`** ```math -\mathit{spend}_{t} = \sum_{g \in \mathcal{G}} p_{g,t} \cdot \mathrm{cost}_{g} \qquad \forall\, t \in \mathcal{T} +\mathit{marginal\_price}_{u,t} = \lambda_{\mathrm{balance},u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` -**`rating`** +**`net`** ```math -\mathrm{rating}_{g,t} = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{b \in \mathcal{B}} \mathrm{load}_{b,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{net}_{t} = -\mathit{spill}_{t} + \mathit{slack}_{t} \qquad \forall\, t \in \mathcal{T} ``` -**`lcoe`** +**`rating`** ```math -\mathit{lcoe} = \frac{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \cdot \mathrm{cost}_{g}}{\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t}} +\mathrm{rating}_{g,t} = \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \cdot \left( \sum_{u \in \mathcal{U}} \mathrm{load}_{u,t} \right) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`net`** +**`spend`** ```math -\mathit{net}_{t} = -\mathit{spill}_{t} + \mathit{slack}_{t} \qquad \forall\, t \in \mathcal{T} +\mathit{spend}_{t} = \sum_{g \in \mathcal{G}} p_{g,t} \cdot \mathrm{cost}_{g} \qquad \forall\, t \in \mathcal{T} ``` -**`marginal_price`** +**`spend_cap`** ```math -\mathit{marginal\_price}_{b,t} = \lambda_{\mathrm{balance},b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\mathrm{spend}^{\mathrm{cap}}_{g} = \mathrm{cost}_{g} \cdot 2 \qquad \forall\, g \in \mathcal{G} ``` **`startup_cost`** @@ -236,298 +236,298 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 #### Subject to -**`budgeted`** +**`ahead`** ```math -\mathit{spend}_{t} \le \mathrm{budget} \qquad \forall\, t \in \mathcal{T} +p_{g,t} \le p_{g,t \oplus 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`starts`** +**`always`** ```math -p_{g,t} \le \mathrm{startup\_cost}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} ``` -**`under_rating`** +**`arithmetic`** ```math -p_{g,t} \le \mathrm{rating}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G}} \left( \frac{p_{g,t}}{2} - \mathrm{cost}_{g} + 10^{-5} \cdot p_{g,t} + 2.5 \times 10^{-7} \cdot \mathrm{cost}_{g} + 0.5 \cdot p_{g,t} \right) \ge -\left( \sum_{g \in \mathcal{G}} p_{g,t} \right) \cdot \left( -3 \right) \qquad \forall\, t \in \mathcal{T} ``` **`balance`** ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} = \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{spill}_{t} - \mathit{slack}_{t} = \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` -**`netted`** +**`budgeted`** ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = b} p_{g,t} + \mathit{net}_{t} = \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +\mathit{spend}_{t} \le \mathrm{budget} \qquad \forall\, t \in \mathcal{T} ``` -**`ramp`** +**`capped`** ```math -p_{g,t} - p_{g,t \ominus 1} \le p_{g,t - 1} + \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{spend}^{\mathrm{cap}}_{g} > 0 \vee \neg \mathrm{is\_flexible}_{g} ``` -**`edges`** +**`ceiling`** ```math -p_{g,t \boxminus_{0} 1} \le p_{g,t \boxplus_{0} 1} + \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\theta_{u} \le \infty \qquad \forall\, u \in \mathcal{U} ``` -**`ahead`** +**`composed`** ```math -p_{g,t} \le p_{g,t \oplus 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g,t - 2} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`composed`** +**`connected`** ```math -p_{g,t - 2} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g,t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( u,\ g \right) \in \mathrm{connection} ``` -**`uncomposed`** +**`counted`** ```math -p_{g,\left( t - 1 \right) \boxminus_{0} \mathrm{lead}} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\theta_{u} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e} > 0 \} \rvert \ge 2 ``` -**`crossed`** +**`counted_here`** ```math -p_{g + 1,t \ominus 1} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\theta_{u} \le \mathrm{tech\_cap}_{u,e} \qquad \forall\, u \in \mathcal{U},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{u,e'} > 0 \} \rvert \ge 2 ``` -**`lead_time`** +**`covered`** ```math -p_{g,t \boxminus_{0} \mathrm{lead}} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \le \mathrm{budget} \qquad \text{where } \sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} ``` -**`in_season`** +**`crossed`** ```math -p_{g,t} \le p_{g,t \ominus^{\mathrm{season\_of}(t)} 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g + 1,t \ominus 1} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`held_in_season`** +**`edges`** ```math -p_{g,t} \le p_{g,t \boxminus_{0}^{\mathrm{season\_of}(t)} 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g,t \boxminus_{0} 1} \le p_{g,t \boxplus_{0} 1} + \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`window`** +**`efficiency`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < 3} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +p_{g,t} \le \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`history`** +**`first`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t \ominus t' < \mathrm{min\_up}} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{on}_{g,t} = 1 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = 0 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = 0 ``` -**`seasonal_window`** +**`grouped_once`** ```math -\sum_{t' \in \mathcal{T} \,:\, 0 \le t -^{\mathrm{season\_of}(t)} t' < 3} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = u \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} \le \mathrm{tech\_cap}_{u,e} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T},\ e \in \mathcal{E} ``` -**`lookup`** +**`held_in_season`** ```math -\mathit{spill}_{t} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +p_{g,t} \le p_{g,t \boxminus_{0}^{\mathrm{season\_of}(t)} 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`grouped_once`** +**`history`** ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bt.bus}(g) = b \wedge \mathrm{gen\_bt.technology}(g) = e} p_{g,t} \le \mathrm{tech\_cap}_{b,e} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T},\ e \in \mathcal{E} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t \ominus t' < \mathrm{min\_up}} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`looked_up_once`** +**`in_season`** ```math -\mathit{units}_{g} \le \mathrm{tech\_cap}_{\mathrm{gen\_bt.bus}(g),\mathrm{gen\_bt.technology}(g)} \qquad \forall\, g \in \mathcal{G} +p_{g,t} \le p_{g,t \ominus^{\mathrm{season\_of}(t)} 1} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`within_bus`** +**`last`** ```math -\mathit{units}_{g} \le \mathit{units}_{g \boxminus_{0}^{\mathrm{gen\_bt.bus}(g)} 1} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{pos}_{\left( \mathrm{gen\_bt.bus}(g),\ \mathrm{gen\_bt.technology}(g) \right)}(g) = 0 +\mathit{on}_{g,t} = 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = \lvert \mathcal{T} \rvert - 1 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = \lvert \mathcal{T}_{\mathrm{season\_of}(t)} \rvert - 1 ``` -**`relational`** +**`lead_time`** ```math -\sum_{g \in \mathcal{G} \,:\, \left( b,\ g \right) \in \mathrm{connection}} p_{g,t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} +p_{g,t \boxminus_{0} \mathrm{lead}} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`connected`** +**`looked_up_once`** ```math -p_{g,t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \left( b,\ g \right) \in \mathrm{connection} +\mathit{units}_{g} \le \mathrm{tech\_cap}_{\mathrm{gen\_bt.bus}(g),\mathrm{gen\_bt.technology}(g)} \qquad \forall\, g \in \mathcal{G} ``` -**`representative`** +**`lookup`** ```math -\sum_{t' \in \mathcal{T} \,:\, \mathrm{rep\_of}(t') = t} \mathit{spill}_{t'} \le \mathit{spill}_{\mathrm{rep\_of}(t)} \qquad \forall\, t \in \mathcal{T} +\mathit{spill}_{t} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` -**`zonal`** +**`margin`** ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} \le \mathrm{zone\_cap}_{z} \qquad \forall\, t \in \mathcal{T},\ z \in \mathcal{Z} +p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} - \mathrm{p}^{\mathrm{min}}_{g} > \frac{\mathrm{cost}_{g}}{2} ``` -**`zonal_history`** +**`masked`** ```math -\sum_{t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} \le \mathrm{zone\_cap}_{z} \qquad \forall\, g \in \mathcal{G},\ z \in \mathcal{Z} +p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{priced\_dispatch}_{g} \wedge \mathrm{pos}(t) > 0 ``` -**`zonal_membership`** +**`netted`** ```math -\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) \text{ is defined}} \mathit{units}_{g} \le \mathrm{budget} \qquad \forall\, t \in \mathcal{T} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_bus}(g) = u} p_{g,t} + \mathit{net}_{t} = \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` -**`zonal_lookup`** +**`never`** ```math -p_{g,t} \le \mathit{spill}_{t} \cdot \mathrm{zone\_cap}_{\mathrm{gen\_zone}(g,\ t)} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{pos}_{\mathrm{gen\_zone}(g,\ t)}(g) = 0 +\mathit{slack}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} \,:\, \bot ``` -**`arithmetic`** +**`northern`** ```math -\sum_{g \in \mathcal{G}} \left( \frac{p_{g,t}}{2} - \mathrm{cost}_{g} + 10^{-5} \cdot p_{g,t} + 2.5 \times 10^{-7} \cdot \mathrm{cost}_{g} + 0.5 \cdot p_{g,t} \right) \ge -\left( \sum_{g \in \mathcal{G}} p_{g,t} \right) \cdot \left( -3 \right) \qquad \forall\, t \in \mathcal{T} +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(u) \neq \mathrm{area\_of}(u) \wedge \mathrm{zone\_of}(u) \text{ is defined} ``` -**`total`** +**`ramp`** ```math -\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \le \mathrm{budget} +p_{g,t} - p_{g,t \ominus 1} \le p_{g,t - 1} + \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`scalar`** +**`ramped`** ```math -\mathit{units}_{g} \le \mathrm{budget} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{cost}_{g} \text{ is defined} +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \wedge \mathrm{pos}(t) > 0 ``` -**`running`** +**`redundant`** ```math -\theta_{b} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \theta_{b} \text{ exists} \wedge t \ge 3 +\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} \,:\, \mathit{spill}_{t} \text{ exists} ``` -**`first`** +**`relational`** ```math -\mathit{on}_{g,t} = 1 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = 0 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = 0 +\sum_{g \in \mathcal{G} \,:\, \left( u,\ g \right) \in \mathrm{connection}} p_{g,t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} ``` -**`last`** +**`representative`** ```math -\mathit{on}_{g,t} = 0 \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) = \lvert \mathcal{T} \rvert - 1 \vee \mathrm{pos}_{\mathrm{season\_of}(t)}(t) = \lvert \mathcal{T}_{\mathrm{season\_of}(t)} \rvert - 1 +\sum_{t' \in \mathcal{T} \,:\, \mathrm{rep\_of}(t') = t} \mathit{spill}_{t'} \le \mathit{spill}_{\mathrm{rep\_of}(t)} \qquad \forall\, t \in \mathcal{T} ``` -**`northern`** +**`run_start`** ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{zone\_of}(b) \neq \mathrm{area\_of}(b) \wedge \mathrm{zone\_of}(b) \text{ is defined} +\mathit{slack}_{t} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{load}_{u,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{u,t - 1} \text{ is defined} \right) ``` -**`efficiency`** +**`running`** ```math -p_{g,t} \le \mathrm{eta}_{g} \cdot \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\theta_{u} \le \mathrm{load}_{u,t} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \theta_{u} \text{ exists} \wedge t \ge 3 ``` -**`ceiling`** +**`scalar`** ```math -\theta_{b} \le \infty \qquad \forall\, b \in \mathcal{B} +\mathit{units}_{g} \le \mathrm{budget} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{cost}_{g} \text{ is defined} ``` -**`always`** +**`seasonal_window`** ```math -\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t -^{\mathrm{season\_of}(t)} t' < 3} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`redundant`** +**`starts`** ```math -\mathit{spill}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} \,:\, \mathit{spill}_{t} \text{ exists} +p_{g,t} \le \mathrm{startup\_cost}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`never`** +**`total`** ```math -\mathit{slack}_{t} \ge 0 \qquad \forall\, t \in \mathcal{T} \,:\, \bot +\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \le \mathrm{budget} ``` -**`margin`** +**`uncomposed`** ```math -p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{p}^{\mathrm{max}}_{g} - \mathrm{p}^{\mathrm{min}}_{g} > \frac{\mathrm{cost}_{g}}{2} +p_{g,\left( t - 1 \right) \boxminus_{0} \mathrm{lead}} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`ramped`** +**`under_rating`** ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} \le \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \wedge \mathrm{pos}(t) > 0 +p_{g,t} \le \mathrm{rating}_{g,t} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`covered`** +**`window`** ```math -\sum_{g \in \mathcal{G},\ t \in \mathcal{T}} p_{g,t} \le \mathrm{budget} \qquad \text{where } \sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} +\sum_{t' \in \mathcal{T} \,:\, 0 \le t - t' < 3} \mathit{on}_{g,t'} \le \mathit{units}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`counted`** +**`within_bus`** ```math -\theta_{b} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B} \,:\, \lvert \{ e \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e} > 0 \} \rvert \ge 2 +\mathit{units}_{g} \le \mathit{units}_{g \boxminus_{0}^{\mathrm{gen\_bt.bus}(g)} 1} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{pos}_{\left( \mathrm{gen\_bt.bus}(g),\ \mathrm{gen\_bt.technology}(g) \right)}(g) = 0 ``` -**`counted_here`** +**`zonal`** ```math -\theta_{b} \le \mathrm{tech\_cap}_{b,e} \qquad \forall\, b \in \mathcal{B},\ e \in \mathcal{E} \,:\, \lvert \{ e' \in \mathcal{E} \,:\, \mathrm{tech\_cap}_{b,e'} > 0 \} \rvert \ge 2 +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} \le \mathrm{zone\_cap}_{z} \qquad \forall\, t \in \mathcal{T},\ z \in \mathcal{Z} ``` -**`run_start`** +**`zonal_history`** ```math -\mathit{slack}_{t} \le \mathrm{load}_{b,t} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{load}_{b,t} \text{ is defined} \wedge \neg \left( \mathrm{load}_{b,t - 1} \text{ is defined} \right) +\sum_{t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = z} p_{g,t} \le \mathrm{zone\_cap}_{z} \qquad \forall\, g \in \mathcal{G},\ z \in \mathcal{Z} ``` -**`zoned`** +**`zonal_lookup`** ```math -\theta_{b} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(b)} \text{ is defined} +p_{g,t} \le \mathit{spill}_{t} \cdot \mathrm{zone\_cap}_{\mathrm{gen\_zone}(g,\ t)} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{gen\_zone}(g,\ t) = \text{'}\mathrm{north}\text{'} \wedge \mathrm{pos}_{\mathrm{gen\_zone}(g,\ t)}(g) = 0 ``` -**`capped`** +**`zonal_membership`** ```math -p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{spend}^{\mathrm{cap}}_{g} > 0 \vee \neg \mathrm{is\_flexible}_{g} +\sum_{g \in \mathcal{G} \,:\, \mathrm{gen\_zone}(g,\ t) \text{ is defined}} \mathit{units}_{g} \le \mathrm{budget} \qquad \forall\, t \in \mathcal{T} ``` -**`masked`** +**`zoned`** ```math -p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} \,:\, \mathrm{priced\_dispatch}_{g} \wedge \mathrm{pos}(t) > 0 +\theta_{u} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U} \,:\, \mathrm{zone\_cap}_{\mathrm{zone\_of}(u)} \text{ is defined} ``` **`adjacent`** @@ -536,34 +536,34 @@ p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \left( \mathit{weight}_{g,t} \right)_{g \in \mathcal{G}} \in \mathrm{SOS}2 \qquad \forall\, t \in \mathcal{T} ``` -**`fuel_curve`** +**`cost_curve`** ```math -\left( p_{g,t},\ \mathit{fuel}_{g,t},\ \mathit{heat}_{g,t} \right) \in \mathit{on}_{g,t} \cdot \mathrm{pwl}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g},\ \mathrm{bp\_heat}_{a,g}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{op\_cost}_{g,t} \ge \begin{cases} \mathit{warm}_{g,t} & \text{if } \mathrm{is\_flexible}_{g} \\ 1 & \text{otherwise} \end{cases} \cdot \mathrm{pwl}_{b \in \mathcal{B} \,:\, \mathrm{bp\_run}_{b,g}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` -**`cost_curve`** +**`fuel_curve`** ```math -\mathit{op\_cost}_{g,t} \ge \begin{cases} \mathit{warm}_{g,t} & \text{if } \mathrm{is\_flexible}_{g} \\ 1 & \text{otherwise} \end{cases} \cdot \mathrm{pwl}_{a \in \mathcal{A} \,:\, \mathrm{bp\_run}_{a,g}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\left( p_{g,t},\ \mathit{fuel}_{g,t},\ \mathit{heat}_{g,t} \right) \in \mathit{on}_{g,t} \cdot \mathrm{pwl}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g},\ \mathrm{bp\_heat}_{b,g}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` **`hull_curve`** ```math -\left( p_{g,t},\ \mathit{fuel}_{g,t} \right) \in \mathrm{conv}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_heat}_{a,g}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\left( p_{g,t},\ \mathit{fuel}_{g,t} \right) \in \mathrm{conv}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_heat}_{b,g}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` **`lp_curve`** ```math -\mathit{fuel}_{g,t} \ge \mathrm{pwl}_{a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_y}_{a,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{fuel}_{g,t} \ge \mathrm{pwl}_{b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_y}_{b,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` **`ramp_curve`** ```math -\mathit{heat}_{g,t} \le \mathrm{pwl}_{a \in \mathcal{A}}(\mathrm{bp\_x}_{a,g},\ \mathrm{bp\_heat}_{a,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} +\mathit{heat}_{g,t} \le \mathrm{pwl}_{b \in \mathcal{B}}(\mathrm{bp\_x}_{b,g},\ \mathrm{bp\_heat}_{b,g})(p_{g,t}) \qquad \forall\, g \in \mathcal{G},\ t \in \mathcal{T} ``` #### Assumptions @@ -574,134 +574,134 @@ p_{g,t} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G},\ t \mathrm{p}^{\mathrm{min}}_{g} \le \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G} ``` -**`efficiency_is_a_fraction`** +**`budget_covers_the_peak`** ```math -\mathrm{eta}_{g} > 0 \wedge \mathrm{eta}_{g} \le 1 \qquad \forall\, g \in \mathcal{G} +\sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} ``` -**`lead_times_are_short`** +**`efficiency_is_a_fraction`** ```math -\mathrm{lead}_{g} \le 3 \qquad \forall\, g \in \mathcal{G} +\mathrm{eta}_{g} > 0 \wedge \mathrm{eta}_{g} \le 1 \qquad \forall\, g \in \mathcal{G} ``` -**`zones_agree`** +**`flexible_units_have_headroom`** ```math -\mathrm{zone\_of}(b) = \mathrm{area\_of}(b) \qquad \forall\, b \in \mathcal{B} +\mathrm{p}^{\mathrm{min}}_{g} < \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{is\_flexible}_{g} ``` -**`budget_covers_the_peak`** +**`lead_times_are_short`** ```math -\sum_{g \in \mathcal{G}} \mathrm{p}^{\mathrm{max}}_{g} \ge \mathrm{budget} +\mathrm{lead}_{g} \le 3 \qquad \forall\, g \in \mathcal{G} ``` -**`ramps_are_gentle`** +**`northern_demand_is_real`** ```math -\mathrm{load}_{b,t} - \mathrm{load}_{b,t \boxminus_{0} 1} \le \mathrm{budget} \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 +\mathrm{load}_{u,t} \ge 0 \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(u) = \text{'}\mathrm{north}\text{'} ``` -**`flexible_units_have_headroom`** +**`ramps_are_gentle`** ```math -\mathrm{p}^{\mathrm{min}}_{g} < \mathrm{p}^{\mathrm{max}}_{g} \qquad \forall\, g \in \mathcal{G} \,:\, \mathrm{is\_flexible}_{g} +\mathrm{load}_{u,t} - \mathrm{load}_{u,t \boxminus_{0} 1} \le \mathrm{budget} \qquad \forall\, u \in \mathcal{U},\ t \in \mathcal{T} \,:\, \mathrm{pos}(t) > 0 ``` -**`northern_demand_is_real`** +**`zones_agree`** ```math -\mathrm{load}_{b,t} \ge 0 \qquad \forall\, b \in \mathcal{B},\ t \in \mathcal{T} \,:\, \mathrm{zone\_of}(b) = \text{'}\mathrm{north}\text{'} +\mathrm{zone\_of}(u) = \mathrm{area\_of}(u) \qquad \forall\, u \in \mathcal{U} ``` -**`fuel_curve_complete`** +**`cost_curve_complete`** ```math -\mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} +\mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_run}_{b,g} ``` -**`cost_curve_complete`** +**`cost_curve_contiguous`** ```math -\mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_run}_{a,g} +\lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_run}_{b,g} \wedge \neg \mathrm{bp\_run}_{b - 1,g} \} \rvert = 1 \qquad \forall\, g \in \mathcal{G} ``` -**`cost_curve_contiguous`** +**`fuel_curve_complete`** ```math -\lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_run}_{a,g} \wedge \neg \mathrm{bp\_run}_{a - 1,g} \} \rvert = 1 \qquad \forall\, g \in \mathcal{G} +\mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} ``` **`hull_curve_complete`** ```math -\mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} +\mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} ``` **`hull_curve_increasing`** ```math -\mathrm{bp\_x}_{a \boxminus_{0} 1,g} < \mathrm{bp\_x}_{a,g} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 +\mathrm{bp\_x}_{b \boxminus_{0} 1,g} < \mathrm{bp\_x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 ``` **`hull_curve_curvature`** ```math -\lvert \{ a \in \mathcal{A} \,:\, \left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) > \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 \} \rvert = 0 \vee \lvert \{ a \in \mathcal{A} \,:\, \left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) < \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 \} \rvert = 0 \qquad \forall\, g \in \mathcal{G} +\lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) > \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \vee \lvert \{ b \in \mathcal{B} \,:\, \left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) < \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \wedge \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 \} \rvert = 0 \qquad \forall\, g \in \mathcal{G} ``` **`lp_curve_complete`** ```math -\mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_y}_{a,g} \text{ is defined} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} +\mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_y}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} ``` **`lp_curve_increasing`** ```math -\mathrm{bp\_x}_{a \boxminus_{0} 1,g} < \mathrm{bp\_x}_{a,g} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a - 1,g} \text{ is defined} +\mathrm{bp\_x}_{b \boxminus_{0} 1,g} < \mathrm{bp\_x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b - 1,g} \text{ is defined} ``` **`lp_curve_curvature`** ```math -\left( \mathrm{bp\_y}_{a,g} - \mathrm{bp\_y}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) \le \left( \mathrm{bp\_y}_{a \boxplus_{0} 1,g} - \mathrm{bp\_y}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a - 1,g} \text{ is defined} \wedge \mathrm{bp\_x}_{a + 1,g} \text{ is defined} +\left( \mathrm{bp\_y}_{b,g} - \mathrm{bp\_y}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) \le \left( \mathrm{bp\_y}_{b \boxplus_{0} 1,g} - \mathrm{bp\_y}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b - 1,g} \text{ is defined} \wedge \mathrm{bp\_x}_{b + 1,g} \text{ is defined} ``` **`lp_curve_breakpoints`** ```math -\lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} +\lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} ``` **`lp_curve_contiguous`** ```math -\lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \neg \left( \mathrm{bp\_x}_{a - 1,g} \text{ is defined} \right) \} \rvert = 1 \qquad \forall\, g \in \mathcal{G} +\lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \neg \left( \mathrm{bp\_x}_{b - 1,g} \text{ is defined} \right) \} \rvert = 1 \qquad \forall\, g \in \mathcal{G} ``` **`ramp_curve_complete`** ```math -\mathrm{bp\_x}_{a,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{a,g} \text{ is defined} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} +\mathrm{bp\_x}_{b,g} \text{ is defined} \wedge \mathrm{bp\_heat}_{b,g} \text{ is defined} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} ``` **`ramp_curve_increasing`** ```math -\mathrm{bp\_x}_{a \boxminus_{0} 1,g} < \mathrm{bp\_x}_{a,g} \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 +\mathrm{bp\_x}_{b \boxminus_{0} 1,g} < \mathrm{bp\_x}_{b,g} \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 ``` **`ramp_curve_curvature`** ```math -\left( \mathrm{bp\_heat}_{a,g} - \mathrm{bp\_heat}_{a \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{a \boxplus_{0} 1,g} - \mathrm{bp\_x}_{a,g} \right) \ge \left( \mathrm{bp\_heat}_{a \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{a,g} \right) \cdot \left( \mathrm{bp\_x}_{a,g} - \mathrm{bp\_x}_{a \boxminus_{0} 1,g} \right) \qquad \forall\, a \in \mathcal{A},\ g \in \mathcal{G} \,:\, \mathrm{pos}(a) > 0 \wedge \mathrm{pos}(a) \neq \lvert \mathcal{A} \rvert - 1 +\left( \mathrm{bp\_heat}_{b,g} - \mathrm{bp\_heat}_{b \boxminus_{0} 1,g} \right) \cdot \left( \mathrm{bp\_x}_{b \boxplus_{0} 1,g} - \mathrm{bp\_x}_{b,g} \right) \ge \left( \mathrm{bp\_heat}_{b \boxplus_{0} 1,g} - \mathrm{bp\_heat}_{b,g} \right) \cdot \left( \mathrm{bp\_x}_{b,g} - \mathrm{bp\_x}_{b \boxminus_{0} 1,g} \right) \qquad \forall\, b \in \mathcal{B},\ g \in \mathcal{G} \,:\, \mathrm{pos}(b) > 0 \wedge \mathrm{pos}(b) \neq \lvert \mathcal{B} \rvert - 1 ``` **`ramp_curve_breakpoints`** ```math -\lvert \{ a \in \mathcal{A} \,:\, \mathrm{bp\_x}_{a,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} +\lvert \{ b \in \mathcal{B} \,:\, \mathrm{bp\_x}_{b,g} \text{ is defined} \} \rvert \ge 2 \qquad \forall\, g \in \mathcal{G} ``` diff --git a/tests/typesetting/golden/typst.out b/tests/typesetting/golden/typst.out index 1dd2490a..b99aa11d 100644 --- a/tests/typesetting/golden/typst.out +++ b/tests/typesetting/golden/typst.out @@ -4,59 +4,59 @@ every character a notation escapes, set as text: link\_to, 100% & \#1 costs \$5 {net} \~ ^ \\ \*star\* \@ref \, and `a_name` in backticks set in code == Sets -/ $cal(T)$: index $t$ --- `snapshot` (`int` coordinates) with $upright("season_of"): cal(T) arrow.r cal(S), upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z), upright("rep_of"): cal(T) arrow.r cal(T)$ -/ $cal(G)$: index $g$ --- `generator` with $upright("gen_bus"): cal(G) arrow.r cal(B), upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z), upright("connection") subset.eq cal(B) times cal(G), upright("gen_bt"): cal(G) arrow.r cal(B) times cal(E)$, `connection` is `absent` where the data has no row -/ $cal(B)$: index $b$ --- `bus` with $upright("gen_bus"): cal(G) arrow.r cal(B), upright("zone_of"): cal(B) arrow.r cal(Z), upright("area_of"): cal(B) arrow.r cal(Z), upright("connection") subset.eq cal(B) times cal(G), upright("gen_bt"): cal(G) arrow.r cal(B) times cal(E)$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row -/ $cal(Z)$: index $z$ --- `zone` with $upright("zone_of"): cal(B) arrow.r cal(Z), upright("area_of"): cal(B) arrow.r cal(Z), upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z)$, `area_of` is `absent` where the data has no row +/ $cal(B)$: index $b$ --- `bp` +/ $cal(U)$: index $u$ --- `bus` with $upright("area_of"): cal(U) arrow.r cal(Z), upright("connection") subset.eq cal(U) times cal(G), upright("gen_bt"): cal(G) arrow.r cal(U) times cal(E), upright("gen_bus"): cal(G) arrow.r cal(U), upright("zone_of"): cal(U) arrow.r cal(Z)$, `area_of` is `absent` where the data has no row, `connection` is `absent` where the data has no row +/ $cal(G)$: index $g$ --- `generator` with $upright("connection") subset.eq cal(U) times cal(G), upright("gen_bt"): cal(G) arrow.r cal(U) times cal(E), upright("gen_bus"): cal(G) arrow.r cal(U), upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z)$, `connection` is `absent` where the data has no row / $cal(S)$: index $s$ --- `season` with $upright("season_of"): cal(T) arrow.r cal(S)$ -/ $cal(E)$: index $e$ --- `technology` with $upright("gen_bt"): cal(G) arrow.r cal(B) times cal(E)$ -/ $cal(A)$: index $a$ --- `bp` +/ $cal(T)$: index $t$ --- `snapshot` (`int` coordinates) with $upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z), upright("rep_of"): cal(T) arrow.r cal(T), upright("season_of"): cal(T) arrow.r cal(S)$ +/ $cal(E)$: index $e$ --- `technology` with $upright("gen_bt"): cal(G) arrow.r cal(U) times cal(E)$ +/ $cal(Z)$: index $z$ --- `zone` with $upright("area_of"): cal(U) arrow.r cal(Z), upright("gen_zone"): cal(G) times cal(T) arrow.r cal(Z), upright("zone_of"): cal(U) arrow.r cal(Z)$, `area_of` is `absent` where the data has no row == Parameters -/ $upright("p")^(upright("max"))$: `p_max` over $cal(G)$, $infinity$ where the data has no row -/ $upright("p")^(upright("min"))$: `p_min` over $cal(G)$ +/ $upright("bp_heat")$: `bp_heat` over $cal(B) times cal(G)$ +/ $upright("bp_run")$: `bp_run` over $cal(B) times cal(G)$ +/ $upright("bp_x")$: `bp_x` over $cal(B) times cal(G)$, `neutral` where the data has no row +/ $upright("bp_y")$: `bp_y` over $cal(B) times cal(G)$, `neutral` where the data has no row +/ $upright("budget")$: `budget` (scalar) / $upright("cost")$: `cost` over $cal(G)$, `neutral` where the data has no row -/ $upright("load")$: `load` over $cal(B) times cal(T)$ -/ $upright("is_flexible")$: `is_flexible` over $cal(G)$, `false` where the data has no row -/ $upright("zone_cap")$: `zone_cap` over $cal(Z)$ -/ $upright("tech_cap")$: `tech_cap` over $cal(B) times cal(E)$, `absent` where the data has no row -/ $upright("min_up")$: `min_up` over $cal(G)$ / $upright("eta")$: `eta` over $cal(G)$ -/ $upright("lead")$: `lead` over $cal(G)$ -/ $upright("budget")$: `budget` (scalar) / $upright("growth")$: `growth` (scalar) -/ $upright("bp_x")$: `bp_x` over $cal(A) times cal(G)$, `neutral` where the data has no row -/ $upright("bp_y")$: `bp_y` over $cal(A) times cal(G)$, `neutral` where the data has no row -/ $upright("bp_heat")$: `bp_heat` over $cal(A) times cal(G)$ -/ $upright("bp_run")$: `bp_run` over $cal(A) times cal(G)$ +/ $upright("is_flexible")$: `is_flexible` over $cal(G)$, `false` where the data has no row +/ $upright("lead")$: `lead` over $cal(G)$ +/ $upright("load")$: `load` over $cal(U) times cal(T)$ +/ $upright("min_up")$: `min_up` over $cal(G)$ +/ $upright("p")^(upright("max"))$: `p_max` over $cal(G)$, $infinity$ where the data has no row +/ $upright("p")^(upright("min"))$: `p_min` over $cal(G)$ +/ $upright("tech_cap")$: `tech_cap` over $cal(U) times cal(E)$, `absent` where the data has no row +/ $upright("zone_cap")$: `zone_cap` over $cal(Z)$ == Conditions / $upright("dispatchable")$: `dispatchable` over $cal(G)$ --- a unit that dispatches and cannot be turned down / $upright("priced_dispatch")$: `priced_dispatch` over $cal(G)$ == Variables -/ $p$: `p` over $cal(G) times cal(T)$ -/ $italic("spill")$: `spill` over $cal(T)$ -/ $italic("slack")$: `slack` over $cal(T)$ -/ $theta$: `theta` over $cal(B)$ -/ $italic("on")$: `on` over $cal(G) times cal(T)$ -/ $italic("units")$: `units` over $cal(G)$ -/ $italic("spare")$: `spare` over $cal(G)$ -/ $italic("reserve")$: `reserve` (scalar) -/ $italic("headroom")$: `headroom` (scalar), `neutral` where the mask leaves it out -/ $italic("weight")$: `weight` over $cal(G) times cal(T)$ / $italic("fuel")$: `fuel` over $cal(G) times cal(T)$ +/ $italic("headroom")$: `headroom` (scalar), `neutral` where the mask leaves it out / $italic("heat")$: `heat` over $cal(G) times cal(T)$ +/ $italic("on")$: `on` over $cal(G) times cal(T)$ / $italic("op_cost")$: `op_cost` over $cal(G) times cal(T)$ +/ $p$: `p` over $cal(G) times cal(T)$ +/ $italic("reserve")$: `reserve` (scalar) +/ $italic("slack")$: `slack` over $cal(T)$ +/ $italic("spare")$: `spare` over $cal(G)$ +/ $italic("spill")$: `spill` over $cal(T)$ +/ $theta$: `theta` over $cal(U)$ +/ $italic("units")$: `units` over $cal(G)$ / $italic("warm")$: `warm` over $cal(G) times cal(T)$ +/ $italic("weight")$: `weight` over $cal(G) times cal(T)$ == Definitions -/ $upright("spend")^(upright("cap"))$: `spend_cap` over $cal(G)$ -/ $italic("spend")$: `spend` over $cal(T)$ --- what a snapshot's dispatch costs -/ $upright("rating")$: `rating` over $cal(G) times cal(T)$ / $italic("lcoe")$: `lcoe` (scalar) +/ $italic("marginal_price")$: `marginal_price` over $cal(U) times cal(T)$ / $italic("net")$: `net` over $cal(T)$ --- what a snapshot spills, less what it lacks -/ $italic("marginal_price")$: `marginal_price` over $cal(B) times cal(T)$ +/ $upright("rating")$: `rating` over $cal(G) times cal(T)$ +/ $italic("spend")$: `spend` over $cal(T)$ --- what a snapshot's dispatch costs +/ $upright("spend")^(upright("cap"))$: `spend_cap` over $cal(G)$ / $upright("startup_cost")$: `startup_cost` over $cal(G) times cal(T)$ --- what starting a unit in this snapshot costs, which the horizon's edge changes == Notation @@ -74,29 +74,29 @@ $ upright("dispatchable") & upright("dispatchable")_(g) & arrow.l.r.double.long == Variable domains #set math.equation(numbering: "(1)") -$ upright("p") & upright("p")^(upright("min"))_(g) <= p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("p")^(upright("max"))_(g) > 0 and not upright("is_flexible")_(g) or upright("p")^(upright("min"))_(g) > 0 \ - upright("spill") & italic("spill")_(t) & >= 0 & forall t in cal(T) \ - upright("slack") & italic("slack")_(t) & <= 100 & forall t in cal(T) \ - upright("theta") & theta_(b) & in RR & forall b in cal(B) \ - upright("on") & italic("on")_(g,t) & in {0, 1} & forall g in cal(G), t in cal(T) \ - upright("units") & 0 <= italic("units")_(g) & <= 10, italic("units")_(g) in ZZ & forall g in cal(G) \ - upright("spare") & italic("spare")_(g) & in ZZ & forall g in cal(G) \ - upright("reserve") & italic("reserve") & >= 0 \ +$ upright("fuel") & italic("fuel")_(g,t) & >= 0 & forall g in cal(G), t in cal(T) \ upright("headroom") & italic("headroom") & >= 0 & upright("where ") upright("budget") upright(" is defined") \ - upright("weight") & 0 <= italic("weight")_(g,t) & <= 1 & forall g in cal(G), t in cal(T) \ - upright("fuel") & italic("fuel")_(g,t) & >= 0 & forall g in cal(G), t in cal(T) \ upright("heat") & italic("heat")_(g,t) & >= 0 & forall g in cal(G), t in cal(T) \ + upright("on") & italic("on")_(g,t) & in {0, 1} & forall g in cal(G), t in cal(T) \ upright("op_cost") & italic("op_cost")_(g,t) & >= 0 & forall g in cal(G), t in cal(T) \ - upright("warm") & italic("warm")_(g,t) & in {0, 1} & forall g in cal(G), t in cal(T) colon upright("is_flexible")_(g) $ + upright("p") & upright("p")^(upright("min"))_(g) <= p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("p")^(upright("max"))_(g) > 0 and not upright("is_flexible")_(g) or upright("p")^(upright("min"))_(g) > 0 \ + upright("reserve") & italic("reserve") & >= 0 \ + upright("slack") & italic("slack")_(t) & <= 100 & forall t in cal(T) \ + upright("spare") & italic("spare")_(g) & in ZZ & forall g in cal(G) \ + upright("spill") & italic("spill")_(t) & >= 0 & forall t in cal(T) \ + upright("theta") & theta_(u) & in RR & forall u in cal(U) \ + upright("units") & 0 <= italic("units")_(g) & <= 10, italic("units")_(g) in ZZ & forall g in cal(G) \ + upright("warm") & italic("warm")_(g,t) & in {0, 1} & forall g in cal(G), t in cal(T) colon upright("is_flexible")_(g) \ + upright("weight") & 0 <= italic("weight")_(g,t) & <= 1 & forall g in cal(G), t in cal(T) $ == Definitions #set math.equation(numbering: "(1)") -$ upright("spend_cap") & upright("spend")^(upright("cap"))_(g) & = upright("cost")_(g) dot 2 & forall g in cal(G) \ - upright("spend") & italic("spend")_(t) & = sum_(g in cal(G)) p_(g,t) dot upright("cost")_(g) & forall t in cal(T) \ - upright("rating") & upright("rating")_(g,t) & = upright("eta")_(g) dot upright("p")^(upright("max"))_(g) dot (sum_(b in cal(B)) upright("load")_(b,t)) & forall g in cal(G), t in cal(T) \ - upright("lcoe") & italic("lcoe") & = frac(sum_(g in cal(G), t in cal(T)) p_(g,t) dot upright("cost")_(g), sum_(g in cal(G), t in cal(T)) p_(g,t)) \ +$ upright("lcoe") & italic("lcoe") & = frac(sum_(g in cal(G), t in cal(T)) p_(g,t) dot upright("cost")_(g), sum_(g in cal(G), t in cal(T)) p_(g,t)) \ + upright("marginal_price") & italic("marginal_price")_(u,t) & = lambda_(upright("balance"),u,t) & forall u in cal(U), t in cal(T) \ upright("net") & italic("net")_(t) & = -italic("spill")_(t) + italic("slack")_(t) & forall t in cal(T) \ - upright("marginal_price") & italic("marginal_price")_(b,t) & = lambda_(upright("balance"),b,t) & forall b in cal(B), t in cal(T) \ + upright("rating") & upright("rating")_(g,t) & = upright("eta")_(g) dot upright("p")^(upright("max"))_(g) dot (sum_(u in cal(U)) upright("load")_(u,t)) & forall g in cal(G), t in cal(T) \ + upright("spend") & italic("spend")_(t) & = sum_(g in cal(G)) p_(g,t) dot upright("cost")_(g) & forall t in cal(T) \ + upright("spend_cap") & upright("spend")^(upright("cap"))_(g) & = upright("cost")_(g) dot 2 & forall g in cal(G) \ upright("startup_cost") & upright("startup_cost")_(g,t) & = cases(upright("cost")_(g) & upright("if ") upright("pos")(t) = 0, upright("cost")_(g) dot 2 & upright("if ") upright("pos")(t) > 0 and upright("season_of")(t) = upright("'winter'"), 0 & upright("otherwise")) & forall g in cal(G), t in cal(T) $ == Objective @@ -105,84 +105,84 @@ $ & max & sum_(g in cal(G), t in cal(T)) p_(g,t) dot upright("cost")_(g) + sum_ == Subject to #set math.equation(numbering: "(1)") -$ upright("budgeted") & italic("spend")_(t) & <= upright("budget") & forall t in cal(T) \ - upright("starts") & p_(g,t) & <= upright("startup_cost")_(g,t) & forall g in cal(G), t in cal(T) \ - upright("under_rating") & p_(g,t) & <= upright("rating")_(g,t) & forall g in cal(G), t in cal(T) \ - upright("balance") & sum_(g in cal(G) colon upright("gen_bus")(g) = b) p_(g,t) + italic("spill")_(t) - italic("slack")_(t) & = upright("load")_(b,t) & forall b in cal(B), t in cal(T) \ - upright("netted") & sum_(g in cal(G) colon upright("gen_bus")(g) = b) p_(g,t) + italic("net")_(t) & = upright("load")_(b,t) & forall b in cal(B), t in cal(T) \ - upright("ramp") & p_(g,t) - p_(g,t minus.o 1) & <= p_(g,t - 1) + upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("edges") & p_(g,t minus.square_(0) 1) & <= p_(g,t plus.square_(0) 1) + upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("ahead") & p_(g,t) & <= p_(g,t plus.o 1) & forall g in cal(G), t in cal(T) \ +$ upright("ahead") & p_(g,t) & <= p_(g,t plus.o 1) & forall g in cal(G), t in cal(T) \ + upright("always") & italic("spill")_(t) & >= 0 & forall t in cal(T) \ + upright("arithmetic") & sum_(g in cal(G)) (frac(p_(g,t), 2) - upright("cost")_(g) + 10^(-5) dot p_(g,t) + 2.5 times 10^(-7) dot upright("cost")_(g) + 0.5 dot p_(g,t)) & >= -(sum_(g in cal(G)) p_(g,t)) dot (-3) & forall t in cal(T) \ + upright("balance") & sum_(g in cal(G) colon upright("gen_bus")(g) = u) p_(g,t) + italic("spill")_(t) - italic("slack")_(t) & = upright("load")_(u,t) & forall u in cal(U), t in cal(T) \ + upright("budgeted") & italic("spend")_(t) & <= upright("budget") & forall t in cal(T) \ + upright("capped") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("spend")^(upright("cap"))_(g) > 0 or not upright("is_flexible")_(g) \ + upright("ceiling") & theta_(u) & <= infinity & forall u in cal(U) \ upright("composed") & p_(g,t - 2) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("uncomposed") & p_(g,(t - 1) minus.square_(0) upright("lead")) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ + upright("connected") & p_(g,t) & <= upright("load")_(u,t) & forall u in cal(U), g in cal(G), t in cal(T) colon (u, g) in upright("connection") \ + upright("counted") & theta_(u) & <= upright("budget") & forall u in cal(U) colon abs({e in cal(E) colon upright("tech_cap")_(u,e) > 0}) >= 2 \ + upright("counted_here") & theta_(u) & <= upright("tech_cap")_(u,e) & forall u in cal(U), e in cal(E) colon abs({e' in cal(E) colon upright("tech_cap")_(u,e') > 0}) >= 2 \ + upright("covered") & sum_(g in cal(G), t in cal(T)) p_(g,t) & <= upright("budget") & upright("where ") sum_(g in cal(G)) upright("p")^(upright("max"))_(g) >= upright("budget") \ upright("crossed") & p_(g + 1,t minus.o 1) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("lead_time") & p_(g,t minus.square_(0) upright("lead")) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("in_season") & p_(g,t) & <= p_(g,t minus.o^(upright("season_of")(t)) 1) & forall g in cal(G), t in cal(T) \ + upright("edges") & p_(g,t minus.square_(0) 1) & <= p_(g,t plus.square_(0) 1) + upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ + upright("efficiency") & p_(g,t) & <= upright("eta")_(g) dot upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ + upright("first") & italic("on")_(g,t) & = 1 & forall g in cal(G), t in cal(T) colon upright("pos")(t) = 0 or upright("pos")_(upright("season_of")(t))(t) = 0 \ + upright("grouped_once") & sum_(g in cal(G) colon upright("gen_bt.bus")(g) = u and upright("gen_bt.technology")(g) = e) p_(g,t) & <= upright("tech_cap")_(u,e) & forall u in cal(U), t in cal(T), e in cal(E) \ upright("held_in_season") & p_(g,t) & <= p_(g,t minus.square_(0)^(upright("season_of")(t)) 1) & forall g in cal(G), t in cal(T) \ - upright("window") & sum_(t' in cal(T) colon 0 <= t - t' < 3) italic("on")_(g,t') & <= italic("units")_(g) & forall g in cal(G), t in cal(T) \ upright("history") & sum_(t' in cal(T) colon 0 <= t minus.o t' < upright("min_up")) italic("on")_(g,t') & <= italic("units")_(g) & forall g in cal(G), t in cal(T) \ - upright("seasonal_window") & sum_(t' in cal(T) colon 0 <= t -^(upright("season_of")(t)) t' < 3) italic("on")_(g,t') & <= italic("units")_(g) & forall g in cal(G), t in cal(T) \ - upright("lookup") & italic("spill")_(t) & <= upright("zone_cap")_(upright("zone_of")(b)) & forall b in cal(B), t in cal(T) \ - upright("grouped_once") & sum_(g in cal(G) colon upright("gen_bt.bus")(g) = b and upright("gen_bt.technology")(g) = e) p_(g,t) & <= upright("tech_cap")_(b,e) & forall b in cal(B), t in cal(T), e in cal(E) \ + upright("in_season") & p_(g,t) & <= p_(g,t minus.o^(upright("season_of")(t)) 1) & forall g in cal(G), t in cal(T) \ + upright("last") & italic("on")_(g,t) & = 0 & forall g in cal(G), t in cal(T) colon upright("pos")(t) = abs(cal(T)) - 1 or upright("pos")_(upright("season_of")(t))(t) = abs(cal(T)_(upright("season_of")(t))) - 1 \ + upright("lead_time") & p_(g,t minus.square_(0) upright("lead")) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ upright("looked_up_once") & italic("units")_(g) & <= upright("tech_cap")_(upright("gen_bt.bus")(g),upright("gen_bt.technology")(g)) & forall g in cal(G) \ - upright("within_bus") & italic("units")_(g) & <= italic("units")_(g minus.square_(0)^(upright("gen_bt.bus")(g)) 1) & forall g in cal(G) colon upright("pos")_((upright("gen_bt.bus")(g), upright("gen_bt.technology")(g)))(g) = 0 \ - upright("relational") & sum_(g in cal(G) colon (b, g) in upright("connection")) p_(g,t) & <= upright("load")_(b,t) & forall b in cal(B), t in cal(T) \ - upright("connected") & p_(g,t) & <= upright("load")_(b,t) & forall b in cal(B), g in cal(G), t in cal(T) colon (b, g) in upright("connection") \ + upright("lookup") & italic("spill")_(t) & <= upright("zone_cap")_(upright("zone_of")(u)) & forall u in cal(U), t in cal(T) \ + upright("margin") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("p")^(upright("max"))_(g) - upright("p")^(upright("min"))_(g) > frac(upright("cost")_(g), 2) \ + upright("masked") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("priced_dispatch")_(g) and upright("pos")(t) > 0 \ + upright("netted") & sum_(g in cal(G) colon upright("gen_bus")(g) = u) p_(g,t) + italic("net")_(t) & = upright("load")_(u,t) & forall u in cal(U), t in cal(T) \ + upright("never") & italic("slack")_(t) & >= 0 & forall t in cal(T) colon bot \ + upright("northern") & italic("slack")_(t) & <= upright("load")_(u,t) & forall u in cal(U), t in cal(T) colon upright("zone_of")(u) = upright("'north'") and upright("zone_of")(u) != upright("area_of")(u) and upright("zone_of")(u) upright(" is defined") \ + upright("ramp") & p_(g,t) - p_(g,t minus.o 1) & <= p_(g,t - 1) + upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ + upright("ramped") & italic("slack")_(t) & <= upright("load")_(u,t) & forall u in cal(U), t in cal(T) colon upright("load")_(u,t) - upright("load")_(u,t minus.square_(0) 1) <= upright("zone_cap")_(upright("zone_of")(u)) and upright("pos")(t) > 0 \ + upright("redundant") & italic("spill")_(t) & >= 0 & forall t in cal(T) colon italic("spill")_(t) upright(" exists") \ + upright("relational") & sum_(g in cal(G) colon (u, g) in upright("connection")) p_(g,t) & <= upright("load")_(u,t) & forall u in cal(U), t in cal(T) \ upright("representative") & sum_(t' in cal(T) colon upright("rep_of")(t') = t) italic("spill")_(t') & <= italic("spill")_(upright("rep_of")(t)) & forall t in cal(T) \ + upright("run_start") & italic("slack")_(t) & <= upright("load")_(u,t) & forall u in cal(U), t in cal(T) colon upright("load")_(u,t) upright(" is defined") and not (upright("load")_(u,t - 1) upright(" is defined")) \ + upright("running") & theta_(u) & <= upright("load")_(u,t) & forall u in cal(U), t in cal(T) colon theta_(u) upright(" exists") and t >= 3 \ + upright("scalar") & italic("units")_(g) & <= upright("budget") & forall g in cal(G) colon upright("cost")_(g) upright(" is defined") \ + upright("seasonal_window") & sum_(t' in cal(T) colon 0 <= t -^(upright("season_of")(t)) t' < 3) italic("on")_(g,t') & <= italic("units")_(g) & forall g in cal(G), t in cal(T) \ + upright("starts") & p_(g,t) & <= upright("startup_cost")_(g,t) & forall g in cal(G), t in cal(T) \ + upright("total") & sum_(g in cal(G), t in cal(T)) p_(g,t) & <= upright("budget") \ + upright("uncomposed") & p_(g,(t - 1) minus.square_(0) upright("lead")) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ + upright("under_rating") & p_(g,t) & <= upright("rating")_(g,t) & forall g in cal(G), t in cal(T) \ + upright("window") & sum_(t' in cal(T) colon 0 <= t - t' < 3) italic("on")_(g,t') & <= italic("units")_(g) & forall g in cal(G), t in cal(T) \ + upright("within_bus") & italic("units")_(g) & <= italic("units")_(g minus.square_(0)^(upright("gen_bt.bus")(g)) 1) & forall g in cal(G) colon upright("pos")_((upright("gen_bt.bus")(g), upright("gen_bt.technology")(g)))(g) = 0 \ upright("zonal") & sum_(g in cal(G) colon upright("gen_zone")(g, t) = z) p_(g,t) & <= upright("zone_cap")_(z) & forall t in cal(T), z in cal(Z) \ upright("zonal_history") & sum_(t in cal(T) colon upright("gen_zone")(g, t) = z) p_(g,t) & <= upright("zone_cap")_(z) & forall g in cal(G), z in cal(Z) \ - upright("zonal_membership") & sum_(g in cal(G) colon upright("gen_zone")(g, t) upright(" is defined")) italic("units")_(g) & <= upright("budget") & forall t in cal(T) \ upright("zonal_lookup") & p_(g,t) & <= italic("spill")_(t) dot upright("zone_cap")_(upright("gen_zone")(g, t)) & forall g in cal(G), t in cal(T) colon upright("gen_zone")(g, t) = upright("'north'") and upright("pos")_(upright("gen_zone")(g, t))(g) = 0 \ - upright("arithmetic") & sum_(g in cal(G)) (frac(p_(g,t), 2) - upright("cost")_(g) + 10^(-5) dot p_(g,t) + 2.5 times 10^(-7) dot upright("cost")_(g) + 0.5 dot p_(g,t)) & >= -(sum_(g in cal(G)) p_(g,t)) dot (-3) & forall t in cal(T) \ - upright("total") & sum_(g in cal(G), t in cal(T)) p_(g,t) & <= upright("budget") \ - upright("scalar") & italic("units")_(g) & <= upright("budget") & forall g in cal(G) colon upright("cost")_(g) upright(" is defined") \ - upright("running") & theta_(b) & <= upright("load")_(b,t) & forall b in cal(B), t in cal(T) colon theta_(b) upright(" exists") and t >= 3 \ - upright("first") & italic("on")_(g,t) & = 1 & forall g in cal(G), t in cal(T) colon upright("pos")(t) = 0 or upright("pos")_(upright("season_of")(t))(t) = 0 \ - upright("last") & italic("on")_(g,t) & = 0 & forall g in cal(G), t in cal(T) colon upright("pos")(t) = abs(cal(T)) - 1 or upright("pos")_(upright("season_of")(t))(t) = abs(cal(T)_(upright("season_of")(t))) - 1 \ - upright("northern") & italic("slack")_(t) & <= upright("load")_(b,t) & forall b in cal(B), t in cal(T) colon upright("zone_of")(b) = upright("'north'") and upright("zone_of")(b) != upright("area_of")(b) and upright("zone_of")(b) upright(" is defined") \ - upright("efficiency") & p_(g,t) & <= upright("eta")_(g) dot upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) \ - upright("ceiling") & theta_(b) & <= infinity & forall b in cal(B) \ - upright("always") & italic("spill")_(t) & >= 0 & forall t in cal(T) \ - upright("redundant") & italic("spill")_(t) & >= 0 & forall t in cal(T) colon italic("spill")_(t) upright(" exists") \ - upright("never") & italic("slack")_(t) & >= 0 & forall t in cal(T) colon bot \ - upright("margin") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("p")^(upright("max"))_(g) - upright("p")^(upright("min"))_(g) > frac(upright("cost")_(g), 2) \ - upright("ramped") & italic("slack")_(t) & <= upright("load")_(b,t) & forall b in cal(B), t in cal(T) colon upright("load")_(b,t) - upright("load")_(b,t minus.square_(0) 1) <= upright("zone_cap")_(upright("zone_of")(b)) and upright("pos")(t) > 0 \ - upright("covered") & sum_(g in cal(G), t in cal(T)) p_(g,t) & <= upright("budget") & upright("where ") sum_(g in cal(G)) upright("p")^(upright("max"))_(g) >= upright("budget") \ - upright("counted") & theta_(b) & <= upright("budget") & forall b in cal(B) colon abs({e in cal(E) colon upright("tech_cap")_(b,e) > 0}) >= 2 \ - upright("counted_here") & theta_(b) & <= upright("tech_cap")_(b,e) & forall b in cal(B), e in cal(E) colon abs({e' in cal(E) colon upright("tech_cap")_(b,e') > 0}) >= 2 \ - upright("run_start") & italic("slack")_(t) & <= upright("load")_(b,t) & forall b in cal(B), t in cal(T) colon upright("load")_(b,t) upright(" is defined") and not (upright("load")_(b,t - 1) upright(" is defined")) \ - upright("zoned") & theta_(b) & <= upright("budget") & forall b in cal(B) colon upright("zone_cap")_(upright("zone_of")(b)) upright(" is defined") \ - upright("capped") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("spend")^(upright("cap"))_(g) > 0 or not upright("is_flexible")_(g) \ - upright("masked") & p_(g,t) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G), t in cal(T) colon upright("priced_dispatch")_(g) and upright("pos")(t) > 0 \ + upright("zonal_membership") & sum_(g in cal(G) colon upright("gen_zone")(g, t) upright(" is defined")) italic("units")_(g) & <= upright("budget") & forall t in cal(T) \ + upright("zoned") & theta_(u) & <= upright("budget") & forall u in cal(U) colon upright("zone_cap")_(upright("zone_of")(u)) upright(" is defined") \ upright("adjacent") & (italic("weight")_(g,t))_(g in cal(G)) & in upright("SOS")2 & forall t in cal(T) \ - upright("fuel_curve") & (p_(g,t), italic("fuel")_(g,t), italic("heat")_(g,t)) & in italic("on")_(g,t) dot upright("pwl")_(a in cal(A))(upright("bp_x")_(a,g), upright("bp_y")_(a,g), upright("bp_heat")_(a,g)) & forall g in cal(G), t in cal(T) \ - upright("cost_curve") & italic("op_cost")_(g,t) & >= cases(italic("warm")_(g,t) & upright("if ") upright("is_flexible")_(g), 1 & upright("otherwise")) dot upright("pwl")_(a in cal(A) colon upright("bp_run")_(a,g))(upright("bp_x")_(a,g), upright("bp_y")_(a,g))(p_(g,t)) & forall g in cal(G), t in cal(T) \ - upright("hull_curve") & (p_(g,t), italic("fuel")_(g,t)) & in upright("conv")_(a in cal(A))(upright("bp_x")_(a,g), upright("bp_heat")_(a,g)) & forall g in cal(G), t in cal(T) \ - upright("lp_curve") & italic("fuel")_(g,t) & >= upright("pwl")_(a in cal(A) colon upright("bp_x")_(a,g) upright(" is defined"))(upright("bp_x")_(a,g), upright("bp_y")_(a,g))(p_(g,t)) & forall g in cal(G), t in cal(T) \ - upright("ramp_curve") & italic("heat")_(g,t) & <= upright("pwl")_(a in cal(A))(upright("bp_x")_(a,g), upright("bp_heat")_(a,g))(p_(g,t)) & forall g in cal(G), t in cal(T) $ + upright("cost_curve") & italic("op_cost")_(g,t) & >= cases(italic("warm")_(g,t) & upright("if ") upright("is_flexible")_(g), 1 & upright("otherwise")) dot upright("pwl")_(b in cal(B) colon upright("bp_run")_(b,g))(upright("bp_x")_(b,g), upright("bp_y")_(b,g))(p_(g,t)) & forall g in cal(G), t in cal(T) \ + upright("fuel_curve") & (p_(g,t), italic("fuel")_(g,t), italic("heat")_(g,t)) & in italic("on")_(g,t) dot upright("pwl")_(b in cal(B))(upright("bp_x")_(b,g), upright("bp_y")_(b,g), upright("bp_heat")_(b,g)) & forall g in cal(G), t in cal(T) \ + upright("hull_curve") & (p_(g,t), italic("fuel")_(g,t)) & in upright("conv")_(b in cal(B))(upright("bp_x")_(b,g), upright("bp_heat")_(b,g)) & forall g in cal(G), t in cal(T) \ + upright("lp_curve") & italic("fuel")_(g,t) & >= upright("pwl")_(b in cal(B) colon upright("bp_x")_(b,g) upright(" is defined"))(upright("bp_x")_(b,g), upright("bp_y")_(b,g))(p_(g,t)) & forall g in cal(G), t in cal(T) \ + upright("ramp_curve") & italic("heat")_(g,t) & <= upright("pwl")_(b in cal(B))(upright("bp_x")_(b,g), upright("bp_heat")_(b,g))(p_(g,t)) & forall g in cal(G), t in cal(T) $ == Assumptions #set math.equation(numbering: "(1)") $ upright("bounds_do_not_cross") & upright("p")^(upright("min"))_(g) & <= upright("p")^(upright("max"))_(g) & forall g in cal(G) \ - upright("efficiency_is_a_fraction") & upright("eta")_(g) > 0 and upright("eta")_(g) <= 1 & & forall g in cal(G) \ - upright("lead_times_are_short") & upright("lead")_(g) & <= 3 & forall g in cal(G) \ - upright("zones_agree") & upright("zone_of")(b) & = upright("area_of")(b) & forall b in cal(B) \ upright("budget_covers_the_peak") & sum_(g in cal(G)) upright("p")^(upright("max"))_(g) & >= upright("budget") \ - upright("ramps_are_gentle") & upright("load")_(b,t) - upright("load")_(b,t minus.square_(0) 1) & <= upright("budget") & forall b in cal(B), t in cal(T) colon upright("pos")(t) > 0 \ + upright("efficiency_is_a_fraction") & upright("eta")_(g) > 0 and upright("eta")_(g) <= 1 & & forall g in cal(G) \ upright("flexible_units_have_headroom") & upright("p")^(upright("min"))_(g) & < upright("p")^(upright("max"))_(g) & forall g in cal(G) colon upright("is_flexible")_(g) \ - upright("northern_demand_is_real") & upright("load")_(b,t) & >= 0 & forall b in cal(B), t in cal(T) colon upright("zone_of")(b) = upright("'north'") \ - upright("fuel_curve_complete") & upright("bp_x")_(a,g) upright(" is defined") and upright("bp_y")_(a,g) upright(" is defined") and upright("bp_heat")_(a,g) upright(" is defined") & & forall a in cal(A), g in cal(G) \ - upright("cost_curve_complete") & upright("bp_x")_(a,g) upright(" is defined") and upright("bp_y")_(a,g) upright(" is defined") & & forall a in cal(A), g in cal(G) colon upright("bp_run")_(a,g) \ - upright("cost_curve_contiguous") & abs({a in cal(A) colon upright("bp_run")_(a,g) and not upright("bp_run")_(a - 1,g)}) & = 1 & forall g in cal(G) \ - upright("hull_curve_complete") & upright("bp_x")_(a,g) upright(" is defined") and upright("bp_heat")_(a,g) upright(" is defined") & & forall a in cal(A), g in cal(G) \ - upright("hull_curve_increasing") & upright("bp_x")_(a minus.square_(0) 1,g) & < upright("bp_x")_(a,g) & forall a in cal(A), g in cal(G) colon upright("pos")(a) > 0 \ - upright("hull_curve_curvature") & abs({a in cal(A) colon (upright("bp_heat")_(a,g) - upright("bp_heat")_(a minus.square_(0) 1,g)) dot (upright("bp_x")_(a plus.square_(0) 1,g) - upright("bp_x")_(a,g)) > (upright("bp_heat")_(a plus.square_(0) 1,g) - upright("bp_heat")_(a,g)) dot (upright("bp_x")_(a,g) - upright("bp_x")_(a minus.square_(0) 1,g)) and upright("pos")(a) > 0 and upright("pos")(a) != abs(cal(A)) - 1}) = 0 or abs({a in cal(A) colon (upright("bp_heat")_(a,g) - upright("bp_heat")_(a minus.square_(0) 1,g)) dot (upright("bp_x")_(a plus.square_(0) 1,g) - upright("bp_x")_(a,g)) < (upright("bp_heat")_(a plus.square_(0) 1,g) - upright("bp_heat")_(a,g)) dot (upright("bp_x")_(a,g) - upright("bp_x")_(a minus.square_(0) 1,g)) and upright("pos")(a) > 0 and upright("pos")(a) != abs(cal(A)) - 1}) = 0 & & forall g in cal(G) \ - upright("lp_curve_complete") & upright("bp_x")_(a,g) upright(" is defined") and upright("bp_y")_(a,g) upright(" is defined") & & forall a in cal(A), g in cal(G) colon upright("bp_x")_(a,g) upright(" is defined") \ - upright("lp_curve_increasing") & upright("bp_x")_(a minus.square_(0) 1,g) & < upright("bp_x")_(a,g) & forall a in cal(A), g in cal(G) colon upright("bp_x")_(a,g) upright(" is defined") and upright("bp_x")_(a - 1,g) upright(" is defined") \ - upright("lp_curve_curvature") & (upright("bp_y")_(a,g) - upright("bp_y")_(a minus.square_(0) 1,g)) dot (upright("bp_x")_(a plus.square_(0) 1,g) - upright("bp_x")_(a,g)) & <= (upright("bp_y")_(a plus.square_(0) 1,g) - upright("bp_y")_(a,g)) dot (upright("bp_x")_(a,g) - upright("bp_x")_(a minus.square_(0) 1,g)) & forall a in cal(A), g in cal(G) colon upright("bp_x")_(a,g) upright(" is defined") and upright("bp_x")_(a - 1,g) upright(" is defined") and upright("bp_x")_(a + 1,g) upright(" is defined") \ - upright("lp_curve_breakpoints") & abs({a in cal(A) colon upright("bp_x")_(a,g) upright(" is defined")}) & >= 2 & forall g in cal(G) \ - upright("lp_curve_contiguous") & abs({a in cal(A) colon upright("bp_x")_(a,g) upright(" is defined") and not (upright("bp_x")_(a - 1,g) upright(" is defined"))}) & = 1 & forall g in cal(G) \ - upright("ramp_curve_complete") & upright("bp_x")_(a,g) upright(" is defined") and upright("bp_heat")_(a,g) upright(" is defined") & & forall a in cal(A), g in cal(G) \ - upright("ramp_curve_increasing") & upright("bp_x")_(a minus.square_(0) 1,g) & < upright("bp_x")_(a,g) & forall a in cal(A), g in cal(G) colon upright("pos")(a) > 0 \ - upright("ramp_curve_curvature") & (upright("bp_heat")_(a,g) - upright("bp_heat")_(a minus.square_(0) 1,g)) dot (upright("bp_x")_(a plus.square_(0) 1,g) - upright("bp_x")_(a,g)) & >= (upright("bp_heat")_(a plus.square_(0) 1,g) - upright("bp_heat")_(a,g)) dot (upright("bp_x")_(a,g) - upright("bp_x")_(a minus.square_(0) 1,g)) & forall a in cal(A), g in cal(G) colon upright("pos")(a) > 0 and upright("pos")(a) != abs(cal(A)) - 1 \ - upright("ramp_curve_breakpoints") & abs({a in cal(A) colon upright("bp_x")_(a,g) upright(" is defined")}) & >= 2 & forall g in cal(G) $ + upright("lead_times_are_short") & upright("lead")_(g) & <= 3 & forall g in cal(G) \ + upright("northern_demand_is_real") & upright("load")_(u,t) & >= 0 & forall u in cal(U), t in cal(T) colon upright("zone_of")(u) = upright("'north'") \ + upright("ramps_are_gentle") & upright("load")_(u,t) - upright("load")_(u,t minus.square_(0) 1) & <= upright("budget") & forall u in cal(U), t in cal(T) colon upright("pos")(t) > 0 \ + upright("zones_agree") & upright("zone_of")(u) & = upright("area_of")(u) & forall u in cal(U) \ + upright("cost_curve_complete") & upright("bp_x")_(b,g) upright(" is defined") and upright("bp_y")_(b,g) upright(" is defined") & & forall b in cal(B), g in cal(G) colon upright("bp_run")_(b,g) \ + upright("cost_curve_contiguous") & abs({b in cal(B) colon upright("bp_run")_(b,g) and not upright("bp_run")_(b - 1,g)}) & = 1 & forall g in cal(G) \ + upright("fuel_curve_complete") & upright("bp_x")_(b,g) upright(" is defined") and upright("bp_y")_(b,g) upright(" is defined") and upright("bp_heat")_(b,g) upright(" is defined") & & forall b in cal(B), g in cal(G) \ + upright("hull_curve_complete") & upright("bp_x")_(b,g) upright(" is defined") and upright("bp_heat")_(b,g) upright(" is defined") & & forall b in cal(B), g in cal(G) \ + upright("hull_curve_increasing") & upright("bp_x")_(b minus.square_(0) 1,g) & < upright("bp_x")_(b,g) & forall b in cal(B), g in cal(G) colon upright("pos")(b) > 0 \ + upright("hull_curve_curvature") & abs({b in cal(B) colon (upright("bp_heat")_(b,g) - upright("bp_heat")_(b minus.square_(0) 1,g)) dot (upright("bp_x")_(b plus.square_(0) 1,g) - upright("bp_x")_(b,g)) > (upright("bp_heat")_(b plus.square_(0) 1,g) - upright("bp_heat")_(b,g)) dot (upright("bp_x")_(b,g) - upright("bp_x")_(b minus.square_(0) 1,g)) and upright("pos")(b) > 0 and upright("pos")(b) != abs(cal(B)) - 1}) = 0 or abs({b in cal(B) colon (upright("bp_heat")_(b,g) - upright("bp_heat")_(b minus.square_(0) 1,g)) dot (upright("bp_x")_(b plus.square_(0) 1,g) - upright("bp_x")_(b,g)) < (upright("bp_heat")_(b plus.square_(0) 1,g) - upright("bp_heat")_(b,g)) dot (upright("bp_x")_(b,g) - upright("bp_x")_(b minus.square_(0) 1,g)) and upright("pos")(b) > 0 and upright("pos")(b) != abs(cal(B)) - 1}) = 0 & & forall g in cal(G) \ + upright("lp_curve_complete") & upright("bp_x")_(b,g) upright(" is defined") and upright("bp_y")_(b,g) upright(" is defined") & & forall b in cal(B), g in cal(G) colon upright("bp_x")_(b,g) upright(" is defined") \ + upright("lp_curve_increasing") & upright("bp_x")_(b minus.square_(0) 1,g) & < upright("bp_x")_(b,g) & forall b in cal(B), g in cal(G) colon upright("bp_x")_(b,g) upright(" is defined") and upright("bp_x")_(b - 1,g) upright(" is defined") \ + upright("lp_curve_curvature") & (upright("bp_y")_(b,g) - upright("bp_y")_(b minus.square_(0) 1,g)) dot (upright("bp_x")_(b plus.square_(0) 1,g) - upright("bp_x")_(b,g)) & <= (upright("bp_y")_(b plus.square_(0) 1,g) - upright("bp_y")_(b,g)) dot (upright("bp_x")_(b,g) - upright("bp_x")_(b minus.square_(0) 1,g)) & forall b in cal(B), g in cal(G) colon upright("bp_x")_(b,g) upright(" is defined") and upright("bp_x")_(b - 1,g) upright(" is defined") and upright("bp_x")_(b + 1,g) upright(" is defined") \ + upright("lp_curve_breakpoints") & abs({b in cal(B) colon upright("bp_x")_(b,g) upright(" is defined")}) & >= 2 & forall g in cal(G) \ + upright("lp_curve_contiguous") & abs({b in cal(B) colon upright("bp_x")_(b,g) upright(" is defined") and not (upright("bp_x")_(b - 1,g) upright(" is defined"))}) & = 1 & forall g in cal(G) \ + upright("ramp_curve_complete") & upright("bp_x")_(b,g) upright(" is defined") and upright("bp_heat")_(b,g) upright(" is defined") & & forall b in cal(B), g in cal(G) \ + upright("ramp_curve_increasing") & upright("bp_x")_(b minus.square_(0) 1,g) & < upright("bp_x")_(b,g) & forall b in cal(B), g in cal(G) colon upright("pos")(b) > 0 \ + upright("ramp_curve_curvature") & (upright("bp_heat")_(b,g) - upright("bp_heat")_(b minus.square_(0) 1,g)) dot (upright("bp_x")_(b plus.square_(0) 1,g) - upright("bp_x")_(b,g)) & >= (upright("bp_heat")_(b plus.square_(0) 1,g) - upright("bp_heat")_(b,g)) dot (upright("bp_x")_(b,g) - upright("bp_x")_(b minus.square_(0) 1,g)) & forall b in cal(B), g in cal(G) colon upright("pos")(b) > 0 and upright("pos")(b) != abs(cal(B)) - 1 \ + upright("ramp_curve_breakpoints") & abs({b in cal(B) colon upright("bp_x")_(b,g) upright(" is defined")}) & >= 2 & forall g in cal(G) $ diff --git a/tests/typesetting/test_cases.py b/tests/typesetting/test_cases.py index 355eeffa..b9e14d31 100644 --- a/tests/typesetting/test_cases.py +++ b/tests/typesetting/test_cases.py @@ -148,16 +148,16 @@ def test_the_table_may_rename_a_named_expression_cased_or_plain(): assert 's_{t} & =' in tex, 'the definition prints under the spelling the table gave' -def test_the_definitions_print_in_file_order(): - """The file's order, not a set's — six of them, so a shuffle cannot pass by luck. +def test_the_definitions_print_sorted_by_name(): + """Name order, not a set's — six of them, written in reverse, so a shuffle cannot pass by luck. The names were once collected into a `frozenset`, whose iteration order follows string hashes and so is re-randomised every process: the section printed its rows in a different order on each run, and a generated page carrying two of them would churn on every regeneration. """ - declared = ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot'] + declared = ['foxtrot', 'echo', 'delta', 'charlie', 'bravo', 'alpha'] tex = to_latex(varied(CASED, **{f'expressions.{n}': BY_REGION for n in declared}), legend=False) section = tex[tex.index('Definitions') : tex.index('Objective')] labels = re.findall(r'^\\text\{(\w+)\} &&', section, flags=re.MULTILINE) - assert labels == ['headroom', *declared], "file order, the file's own" + assert labels == sorted(['headroom', *declared]), 'sorted by name, not in the order the file writes them' diff --git a/tests/typesetting/test_walk.py b/tests/typesetting/test_walk.py index 3194d52b..d42e5100 100644 --- a/tests/typesetting/test_walk.py +++ b/tests/typesetting/test_walk.py @@ -16,7 +16,7 @@ from mathspec._typesetting.symbols import _derive_name_symbol, chosen_expressions, symbols_for from mathspec._validation import to_spec from mathspec.errors import LanguageError -from tests.fixtures import DISPATCH_MODEL, EXAMPLES, OPERATOR_PROBES, SPECS, dims_reversed, varied +from tests.fixtures import DISPATCH_MODEL, EXAMPLES, OPERATOR_PROBES, SPECS, dims_reversed, entries_reversed, varied from tests.typesetting import golden from tests.typesetting.fixtures import EVERY_FORMAT, LATEX @@ -1079,6 +1079,17 @@ def test_a_set_is_labelled_by_the_entry_that_declares_it(name: FormatName, fmt: assert 'p sos' not in text +@pytest.mark.parametrize('fmt', sorted(FORMATS)) +@pytest.mark.parametrize('path', SPECS, ids=lambda path: str(path.relative_to(EXAMPLES))) +def test_the_order_a_file_lists_its_entries_in_prints_nowhere(path, fmt): + """The document printed each section's entries, and the legend its dimensions, in the order the file listed + them, so two files that state one model printed two documents.""" + spec = to_spec(path) + assert typeset(to_spec(entries_reversed(spec.to_dict())), fmt) == typeset(spec, fmt), ( + 'every section prints its entries sorted by name, whatever order the file lists them in' + ) + + @pytest.mark.parametrize('fmt', sorted(FORMATS)) @pytest.mark.parametrize('path', SPECS, ids=lambda path: str(path.relative_to(EXAMPLES))) def test_the_order_a_dims_list_is_written_in_prints_nowhere(path, fmt):