Links#
This file states PyPSA's Link. It is one of the 25 whole specs of one topic each (fragments) that merge composes into the spec of examples/pypsa.yaml. It adds a term to each of these sums: transmission_volume_expansion, transmission_expansion_cost, tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions and Bus_injection. Link_output_arrival is what a link delivers at an output port: its flow, delayed by the port's delay within its investment period.
given:
parameters:
snapshot_weightings_objective: { dims: [snapshot] }
Link_committable: { dims: [link], dtype: bool }
Link_maintenance_pu: { dims: [scenario, link] }
scenario_weight: { dims: [scenario] }
CVaR_omega: { dims: [] }
period_weight_objective: { dims: [period] }
snapshot_weightings_generators: { dims: [snapshot] }
variables:
Link_maintenance: { dims: [scenario, snapshot, link] }
Link_maintenance_capacity: { dims: [scenario, snapshot, link] }
expressions:
energy_limit_weight: { dims: [snapshot] }
transmission_volume_expansion: { dims: [global_constraint, scenario] }
transmission_expansion_cost: { dims: [global_constraint, scenario] }
tech_capacity_expansion: { dims: [global_constraint] }
scenario_opex: { dims: [scenario] }
total_cost: { dims: [] }
Carrier_additions: { dims: [carrier, period] }
Bus_injection: { dims: [bus, scenario, snapshot] }
dimensions:
scenario:
description: the futures dispatch is chosen in, each with a weight
snapshot:
description: dispatch periods
dtype: datetime
ordered: true
bus:
description: network nodes
link:
description: controllable connections, each from one bus to the buses it delivers to
link_output:
description: >-
a link's output ports, one label per port a link declares. The labels
are PyPSA's `bus1`, `bus2`, … columns read long, data prep. A link of
any number of output ports is then one term in the balance
global_constraint:
description: PyPSA's `GlobalConstraint` rows, one label per declared limit
period:
description: investment periods. It is PyPSA's `investment_periods`
dtype: int
ordered: true
carrier:
description: energy carriers, what a growth limit is set per
maps:
snapshot:
period:
description: the investment period a snapshot falls in
refers_to: period
link:
carrier:
description: the carrier a link converts from
refers_to: carrier
bus0:
description: the bus a link leaves
refers_to: bus
link_output:
link:
description: the link an output port belongs to
refers_to: link
bus:
description: >-
the bus an output port delivers to. It is PyPSA's `bus1`, `bus2`, …
columns. A link of three output ports is three labels here rather than a
third relation, so the file states any number of them
refers_to: bus
parameters:
Link_p_nom:
description: nominal power
dims: [scenario, link]
Link_p_nom_extendable:
description: whether the nominal power is a decision
dims: [link]
dtype: bool
Link_p_min_pu:
description: "least flow, per unit of nominal power: negative for a link that carries both ways"
dims: [scenario, snapshot, link]
Link_p_max_pu:
description: most flow, per unit of nominal power
dims: [scenario, snapshot, link]
Link_efficiency:
description: >-
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:1575`)
dims: [scenario, snapshot, link_output]
Link_output_delay:
description: >-
snapshots a port's delivery lags its link's flow (PyPSA's `delay`,
`delay2`, … read long). In data prep you divide it by the
`snapshot_weightings.generators` value and round it up. It is 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:55`)
dims: [link_output]
dtype: int
Link_output_cyclic_delay:
description: >-
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
dims: [link_output]
dtype: bool
Link_marginal_cost:
description: cost of one unit of flow
dims: [scenario, snapshot, link]
Link_marginal_cost_quadratic:
description: cost of the square of one unit of flow
dims: [scenario, snapshot, link]
Link_p_nom_mod:
description: the module size a build comes in whole numbers of. No value means the build is continuous
dims: [link]
missing: absent
Link_modules_installed:
description: >-
how many whole modules a committable build has in place, data prep. It
is `Link_p_nom / Link_p_nom_mod` where a fixed build is modular, and one
where it is not. PyPSA refuses a fixed modular build whose nominal power
is not a whole number of modules
dims: [scenario, link]
Link_p_min_pu_nonneg:
description: >-
true where none of the link's own minimums-per-unit is negative. It is
PyPSA's per-unit `(p_min_pu >= 0).all()` over every snapshot and
scenario, data prep
dims: [link]
dtype: bool
Link_active:
description: whether a link is active in a snapshot's period. It is PyPSA's `active`, data prep
dims: [snapshot, link]
dtype: bool
Link_active_asset:
description: >-
whether a link is one of PyPSA's `active_assets`, by its `active` flag
alone, without build year and lifetime. A unit that is active in no
snapshot of the horizon still counts. PyPSA refuses one that differs by
scenario (`constants.py:54`)
dims: [link]
dtype: bool
Link_capital_weight:
description: the sum of period weights a link is active in. It is PyPSA's `active * period_weighting`, summed, data prep
dims: [link]
Link_first_active:
description: >-
one in the first period a link is active in, zero elsewhere, data prep.
PyPSA takes `active & (active.cumsum() == 1)` (`global_constraints.py:278`)
dims: [period, link]
Link_p_set:
description: a given flow schedule. A link without one has no row here
dims: [scenario, snapshot, link]
missing: absent
Link_e_sum_min:
description: least energy of its flow at `bus0`, the withdrawal there, over the horizon. It is minus infinity where no floor is meant
dims: [scenario, link]
Link_e_sum_max:
description: most energy of its flow at `bus0`, the withdrawal there, over the horizon. It is infinity where no cap is meant
dims: [scenario, link]
Link_p_nom_min:
description: least nominal power an extendable link may be built at
dims: [scenario, link]
Link_p_nom_max:
description: most nominal power an extendable link may be built at
dims: [scenario, link]
Link_capital_cost:
description: >-
cost of one unit of nominal power for the modelled horizon (PyPSA's
`periodized_cost`), data prep. It is `overnight_cost` as an annuity over
`lifetime` at `discount_rate`, times `nyears`, where `overnight_cost` is
given, and `capital_cost` where it is not. Both add `fom_cost`
(`components.py:1157-1178`, `costs.py:102-203`)
dims: [scenario, link]
Link_p_nom_set:
description: a given nominal power for an extendable link. One without a value has no row here
dims: [link]
missing: absent
Link_volume_weight:
description: >-
the link's length in each scenario where its carrier is in the row's set
(`global_constraints.py:882-883`), data prep. A link outside it, or one
that is not active in the row's `investment_period`, has no row
dims: [scenario, global_constraint, link]
missing: absent
Link_expansion_cost_weight:
description: >-
the link's capital cost where its carrier is in the row's set, data
prep. Where the row states no `investment_period` under
`multi_investment_periods`, it is times the objective weights of the
periods the link is active in. A link outside the set, or one that is not
active 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:1182-1200`, `global_constraints.py:905-914`)
dims: [scenario, global_constraint, link]
missing: absent
Link_tech_capacity_weight:
description: >-
one where the link is in the row's carrier-and-bus set, data prep. One
outside it, or one that is not active in the row's `investment_period`,
has no row
dims: [global_constraint, link]
missing: absent
variables:
Link_p:
description: >-
`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
dims: [scenario, snapshot, link]
where: Link_active
Link_n_mod:
description: "`Link-n_mod` — how many modules of an extendable modular build. A unit that is not active has none"
dims: [link]
where: Link_p_nom_extendable AND Link_p_nom_mod > 0 AND Link_active_asset
domain: integer
bounds:
lower: 0
Link_p_nom_ext:
description: >-
`Link-p_nom` — nominal power where it is a decision, for a link that is
active. A fixed build is the parameter of the same PyPSA name
dims: [link]
where: Link_p_nom_extendable AND Link_active_asset
expressions:
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
Link_modules:
description: >-
how many modules a committed link's status counts: the chosen number
where the build is extendable and modular, and the modules installed
otherwise (`constraints.py:656-661`)
dims: [scenario, link]
cases:
chosen: { when: Link_p_nom_extendable AND Link_p_nom_mod > 0, expression: Link_n_mod }
otherwise: Link_modules_installed
Link_p_nom_committed:
description: >-
the build a committed link's ramp rows are taken against: one module
where the build is modular, since its status counts modules, and the
given build otherwise (`constraints.py:1131-1134`)
dims: [scenario, link]
cases:
modular_build: { when: "Link_p_nom_mod > 0", expression: Link_p_nom_mod }
otherwise: Link_p_nom
Link_output_arrival:
description: >-
what a link delivers to an output port at a snapshot. It is its flow
delayed by the port's `delay` within its investment period. It is
multiplied by 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. 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]), along=snapshot, offset=Link_output_delay, edge='wrap', within=snapshot[period]) * Link_efficiency
otherwise: shift(at(Link_p, by=link_output[link]), along=snapshot, offset=Link_output_delay, edge=0, within=snapshot[period]) * Link_efficiency
Link_transmission_volume_expansion:
expression: sum(Link_p_nom_ext * Link_volume_weight, over=link)
adds_to: transmission_volume_expansion
Link_transmission_expansion_cost:
expression: sum(Link_p_nom_ext * Link_expansion_cost_weight, over=link)
adds_to: transmission_expansion_cost
Link_tech_capacity_expansion:
expression: sum(Link_p_nom_ext * Link_tech_capacity_weight, over=link)
adds_to: tech_capacity_expansion
Link_opex:
expression: >-
sum(sum(((Link_p * Link_marginal_cost) * snapshot_weightings_objective) * at(period_weight_objective, by=snapshot[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]), over=link), over=snapshot)
adds_to: scenario_opex
Link_capex:
expression: sum(scenario_weight * Link_p_nom_ext * Link_capital_cost * Link_capital_weight)
adds_to: total_cost
Link_additions:
expression: >-
sum(Link_p_nom_ext * Link_first_active, over=link, by=link[carrier])
adds_to: Carrier_additions
Link_injection:
expression: >-
-sum(Link_p, over=link, by=link[bus0])
+ sum(Link_output_arrival, over=link_output, by=link_output[bus])
adds_to: Bus_injection
conditions:
Link_committed:
description: >-
a committable link that is active in the snapshot's period: every
unit-commitment row's set
condition: Link_committable AND Link_active
constraints:
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)
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)
Link_e_sum_min:
description: "`Link-e_sum_min` — energy withdrawn at `bus0` over the horizon, each period weighted by its years, is at least its floor. A floor of minus infinity is no row, and so is a link active in no snapshot"
dims: [scenario, link]
where: Link_e_sum_min AND count(Link_active, over=snapshot) > 0
expression: sum(Link_p * energy_limit_weight, over=snapshot) >= Link_e_sum_min
Link_e_sum_max:
description: "`Link-e_sum_max` — energy withdrawn at `bus0` over the horizon, each period weighted by its years, is at most its budget. A budget of infinity is no row, and so is a link active in no snapshot"
dims: [scenario, link]
where: Link_e_sum_max AND count(Link_active, over=snapshot) > 0
expression: sum(Link_p * energy_limit_weight, over=snapshot) <= Link_e_sum_max
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)
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)
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
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
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
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
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
assumptions:
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: >-
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`). The two
agree only where that weighting is one value over the horizon. PyPSA
does not refuse an uneven weighting, so a tool refuses it through this
assumption when data is attached (#299)
Link_marginal_cost_quadratic_without_risk_preference:
holds: "Link_marginal_cost_quadratic == 0"
where: "CVaR_omega"
description: >-
a quadratic cost puts a square into every `CVaR-excess` row. PyPSA
refuses quadratic costs under any risk preference, `omega = 0` included
(`optimize.py:506-513`). In data prep you write a `CVaR_omega` row only
where a risk preference is set
Given#
| Symbol | Meaning |
|---|---|
| \(\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 |
| \(\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{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{w}^{E}\) | energy_limit_weight over \(\mathcal{T}\), an expression another file defines |
| \(\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{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 |
|---|---|
| \(\mathcal{N}\) | index \(n\) — bus with \(\mathrm{bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{bus}: \mathcal{O} \to \mathcal{N}\) — network nodes |
| \(\mathcal{I}\) | index \(i\) — carrier with \(\mathrm{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{bus0}: \mathcal{L} \to \mathcal{N},\ \mathrm{carrier}: \mathcal{L} \to \mathcal{I},\ \mathrm{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{bus}: \mathcal{O} \to \mathcal{N},\ \mathrm{link}: \mathcal{O} \to \mathcal{L}\) — a link's output ports, one label per port a link declares. The labels are PyPSA's bus1, bus2, … columns read long, data prep. A link of any number of output ports is then one term in the balance |
| \(\mathcal{Y}\) | index \(y\) — period with \(\mathrm{period}: \mathcal{T} \to \mathcal{Y}\) — investment periods. It is 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{period}: \mathcal{T} \to \mathcal{Y}\) — dispatch periods |
Parameters#
| Symbol | Meaning |
|---|---|
| \(\mathrm{on}^{f}\) | Link_active over \(\mathcal{L} \times \mathcal{T}\) — whether a link is active in a snapshot's period. It is PyPSA's active, data prep |
| \(\mathrm{act}^{f}\) | Link_active_asset over \(\mathcal{L}\) — whether a link is one of PyPSA's active_assets, by its active flag alone, without build year and lifetime. A unit that is active in no snapshot of the horizon still counts. PyPSA refuses one that differs by scenario (constants.py:54) |
| \(\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), data prep. It is overnight_cost as an annuity over lifetime at discount_rate, times nyears, where overnight_cost is given, and capital_cost where it is not. Both add fom_cost (components.py:1157-1178, costs.py:102-203) |
| \(\mathrm{W}^{f}\) | Link_capital_weight over \(\mathcal{L}\) — the sum of period weights a link is active in. It is PyPSA's active * period_weighting, summed, data prep |
| \(\overline{\mathrm{E}}^{f}\) | Link_e_sum_max over \(\mathcal{L} \times \Xi\) — most energy of its flow at bus0, the withdrawal there, over the horizon. It is infinity where no cap is meant |
| \(\underline{\mathrm{E}}^{f}\) | Link_e_sum_min over \(\mathcal{L} \times \Xi\) — least energy of its flow at bus0, the withdrawal there, over the horizon. It is minus infinity where no floor is meant |
| \(\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:1575) |
| \(\mathrm{cc}^{f}\) | Link_expansion_cost_weight over \(\mathcal{G} \times \mathcal{L} \times \Xi\), absent where the data has no row — the link's capital cost where its carrier is in the row's set, data prep. Where the row states no investment_period under multi_investment_periods, it is times the objective weights of the periods the link is active in. A link outside the set, or one that is not active 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:1182-1200, global_constraints.py:905-914) |
| \(\mathrm{new}^{f}\) | Link_first_active over \(\mathcal{L} \times \mathcal{Y}\) — one in the first period a link is active in, zero elsewhere, data prep. PyPSA takes active & (active.cumsum() == 1) (global_constraints.py:278) |
| \(\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{N}^{f,\mathrm{fix}}\) | Link_modules_installed over \(\mathcal{L} \times \Xi\) — how many whole modules a committable build has in place, data prep. It is Link_p_nom / Link_p_nom_mod where a fixed build is modular, and one where it is not. 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). In data prep you divide it by the snapshot_weightings.generators value and round it up. It is 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:55) |
| \(\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. It is 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}\), absent where the data has no row — the module size a build comes in whole numbers of. No value means the build is continuous |
| \(\mathrm{f}^{\mathrm{nom,set}}\) | Link_p_nom_set over \(\mathcal{L}\), absent where the data has no row — a given nominal power for an extendable link. One without a value has no row here |
| \(\mathrm{f}^{\mathrm{set}}\) | Link_p_set over \(\mathcal{L} \times \Xi \times \mathcal{T}\), absent 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}\), absent where the data has no row — one where the link is in the row's carrier-and-bus set, data prep. One outside it, or one that is not active in the row's investment_period, has no row |
| \(\mathrm{len}^{f}\) | Link_volume_weight over \(\mathcal{G} \times \mathcal{L} \times \Xi\), absent where the data has no row — the link's length in each scenario where its carrier is in the row's set (global_constraints.py:882-883), data prep. A link outside it, or one that is not active in the row's investment_period, has no row |
Conditions#
| Symbol | Meaning |
|---|---|
| \(\mathrm{on}^{f,\mathrm{com}}\) | Link_committed over \(\mathcal{L} \times \mathcal{T}\) — a committable link that is active in the snapshot's period: every unit-commitment row's set |
Variables#
| Symbol | Meaning |
|---|---|
| \(N^{f}\) | Link_n_mod over \(\mathcal{L}\) — Link-n_mod — how many modules of an extendable modular build. A unit that is not active has none |
| \(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. A fixed build is the parameter of the same PyPSA name |
Definitions#
| Symbol | Meaning |
|---|---|
| \(\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}\) |
| \(\mathrm{M}^{f}\) | Link_modules over \(\mathcal{L} \times \Xi\) — how many modules a committed link's status counts: the chosen number where the build is extendable and modular, and the modules installed otherwise (constraints.py:656-661) |
| \(\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. It is its flow delayed by the port's delay within its investment period. It is multiplied by 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. 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 modular, since its status counts modules, and the given build otherwise (constraints.py:1131-1134) |
| \(\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#
| Symbol | Meaning |
|---|---|
| \(t \ominus k\) | edge='wrap' — \(t-k\), cyclic |
| \(t \boxminus_{v} k\) | edge=v — \(t-k\), and \(v\) past the edge |
| \(t \ominus^{\mathrm{map}(t)} k\) | within=subject[map] — \(t-k\) inside the group of \(t\) |
Conditions#
Link_committed
Variable domains#
Link_n_mod
Link_p
Link_p_nom_ext
Definitions#
Link_additions
Link_capex
Link_injection
Link_modules
Link_opex
Link_output_arrival
Link_p_nom_committed
Link_p_nom_effective
Link_tech_capacity_expansion
Link_transmission_expansion_cost
Link_transmission_volume_expansion
Subject to#
Link_e_sum_max
Link_e_sum_min
Link_ext_p_lower
Link_ext_p_nom_lower
Link_ext_p_nom_upper
Link_ext_p_upper
Link_fix_p_lower
Link_fix_p_upper
Link_p_nom_modularity
Link_p_nom_set
Link_p_set
Assumptions#
Link_marginal_cost_quadratic_without_risk_preference
Link_output_delay_under_uniform_weighting
See also
- PyPSA in 25 files, for how the fragments compose
- PyPSA in one file, for the same spec as one file, rung by rung