Skip to content

Settings#

This file states the weightings, the risk preference and the flags that the other fragments use. It is one of the 25 whole specs of one topic each (fragments) that merge composes into the spec of examples/pypsa.yaml. It lists eight totals under given: total_cost, scenario_opex, Carrier_additions and the five global-constraint sums. A spec may leave out the other fragments that list these totals, so every term adds to a sum that some fragment lists. GlobalConstraint_energy_weight is what one unit of power at a snapshot counts for in a global-constraint row. Its objective minimises total_cost.

given:
  expressions:
    primary_energy:
      dims: [global_constraint, scenario]
      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
    operational_limit:
      dims: [global_constraint, scenario]
      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
    transmission_volume_expansion:
      dims: [global_constraint, scenario]
      description: >-
        what a `transmission_volume_expansion_limit` row totals: length times
        the chosen build of the row's branches
    transmission_expansion_cost:
      dims: [global_constraint, scenario]
      description: >-
        what a `transmission_expansion_cost_limit` row totals: capital cost
        times the chosen build of the row's branches
    tech_capacity_expansion:
      dims: [global_constraint]
      description: >-
        what a `tech_capacity_expansion_limit` row totals: the chosen build of
        the row's carrier-and-bus set
    scenario_opex:
      dims: [scenario]
      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:448-468`)
    total_cost:
      dims: []
      description: >-
        what the system costs. Capacity counts once per active period at its
        expected cost over the scenarios. Operation counts in expectation over
        the scenarios, and a share of it at the tail
    Carrier_additions:
      dims: [carrier, period]
      description: >-
        what a carrier adds in a period: every extendable component of that
        carrier, counting each build in the first period it is active in. Like
        PyPSA, it sums only the components that carry a carrier attribute, so a
        transformer, which has none, counts in no carrier

dimensions:
  scenario:
    description: the futures dispatch is chosen in, each with a weight
  snapshot:
    description: dispatch periods
    dtype: datetime
    ordered: true
  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

relations:
  snapshot_period:
    description: the investment period a snapshot falls in
    key: snapshot
    values: period

parameters:
  snapshot_weightings_objective:
    description: PyPSA's `snapshot_weightings.objective` — hours a snapshot weighs in the cost
    dims: [snapshot]
  scenario_weight:
    description: PyPSA's `scenario_weightings.weight` — the probability of a future
    dims: [scenario]
  CVaR_omega:
    description: PyPSA's `risk_preference['omega']` — the share of operating cost priced at the tail rather than in expectation. `CVaR_omega` has a value 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
    dims: []
    missing: 0
  period_weight_objective:
    description: >-
      PyPSA's `investment_period_weightings.objective` — what a period's cost
      weighs. PyPSA reads it only under `multi_investment_periods`. Otherwise
      you feed one in data prep, whatever the column contains
      (`optimize.py:231-233`, `:293-297`)
    dims: [period]
  period_weight_years:
    description: >-
      PyPSA's `investment_period_weightings.years` — what a period's energy
      weighs in a `primary_energy`, `operational_limit` or `e_sum` row. PyPSA reads it
      only under `multi_investment_periods`. Otherwise you feed one in data
      prep
    dims: [period]
  snapshot_weightings_stores:
    description: PyPSA's `snapshot_weightings.stores` — hours a snapshot weighs in a storage balance
    dims: [snapshot]
  snapshot_weightings_generators:
    description: PyPSA's `snapshot_weightings.generators` — hours a snapshot weighs in an energy total
    dims: [snapshot]
  transmission_losses:
    description: >-
      whether the network dissipates transmission losses (PyPSA's
      `transmission_losses` read as a flag). Its mode, tangents or secants,
      only decides how you fill the `segment` axis in data prep. 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 hands the keyword not to `create_model`
      (`abstract.py:645-650`) but to the solver (`:549`), so you feed false
      there in data prep
    dims: []
    dtype: bool
  GlobalConstraint_counts_snapshot:
    description: >-
      whether a row counts a snapshot in a scenario (PyPSA's
      `investment_period`), data prep. It is every snapshot where the row
      states no period, and only that period's where it states one. A row that
      states a period the run does not model has no label here, as PyPSA skips
      it (`global_constraints.py:388`). PyPSA reads the column only under
      `multi_investment_periods`. It fails on a row that states a period
      without it (`global_constraints.py:380-385`)
    dims: [scenario, global_constraint, snapshot]
    dtype: bool
    missing: false

expressions:
  energy_limit_weight:
    description: >-
      what one unit of power at a snapshot counts for in an `e_sum` row: the
      generator weighting times the years of the snapshot's period, as in an
      `operational_limit` row (`constraints.py:2935-2937`)
    dims: [snapshot]
    expression: snapshot_weightings_generators * at(period_weight_years, by=snapshot_period[period])
  GlobalConstraint_energy_weight:
    description: >-
      what one unit of power at a snapshot counts for in a row. Where the row
      counts the snapshot, it is the generator weighting times the years of
      the snapshot's period. Where it does not, it is nothing
    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

objective:
  sense: minimize
  expression: total_cost

Given#

Symbol Meaning
\(\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 is active 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{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:448-468)
\(\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 counts once per active period at its expected cost over the scenarios. Operation counts in expectation over the scenarios, and a share of it at the tail
\(\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
\(\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. 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{snapshot\_period}: \mathcal{T} \to \mathcal{Y}\) — dispatch periods

Parameters#

Symbol Meaning
\(\omega\) CVaR_omega (scalar), \(0\) where the data has no row — PyPSA's risk_preference['omega'] — the share of operating cost priced at the tail rather than in expectation. CVaR_omega has a value 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}\), false where the data has no row — whether a row counts a snapshot in a scenario (PyPSA's investment_period), data prep. It is every snapshot where the row states no period, and only that period's where it states one. A row that states a period the run does not model has no label here, as PyPSA skips it (global_constraints.py:388). PyPSA reads the column only under multi_investment_periods. It fails on a row that states a period without it (global_constraints.py:380-385)
\(\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. Otherwise you feed one in data prep, whatever the column contains (optimize.py:231-233, :293-297)
\(\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, operational_limit or e_sum row. PyPSA reads it only under multi_investment_periods. Otherwise you feed one in data prep
\(\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 weighs in an energy total
\(\mathrm{w}\) snapshot_weightings_objective over \(\mathcal{T}\) — PyPSA's snapshot_weightings.objective — hours a snapshot weighs in the cost
\(\mathrm{w}^{\mathrm{sto}}\) snapshot_weightings_stores over \(\mathcal{T}\) — PyPSA's snapshot_weightings.stores — hours a snapshot weighs 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 you fill the segment axis in data prep. 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 hands the keyword not to create_model (abstract.py:645-650) but to the solver (:549), so you feed false there in data prep

Definitions#

Symbol Meaning
\(\mathit{w}^{\mathrm{gc}}\) GlobalConstraint_energy_weight over \(\mathcal{G} \times \Xi \times \mathcal{T}\) — what one unit of power at a snapshot counts for in a row. Where the row counts the snapshot, it is the generator weighting times the years of the snapshot's period. Where it does not, it is nothing
\(\mathit{w}^{E}\) energy_limit_weight over \(\mathcal{T}\) — what one unit of power at a snapshot counts for in an e_sum row: the generator weighting times the years of the snapshot's period, as in an operational_limit row (constraints.py:2935-2937)

Definitions#

GlobalConstraint_energy_weight

\[ \mathit{w}^{\mathrm{gc}}_{g,\xi,t} = \begin{cases} \mathrm{w}^{\mathrm{gen}}_{t} \cdot \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} & \text{if } \mathrm{in}_{g,\xi,t} \\ 0 & \text{otherwise} \end{cases} \qquad \forall\, g \in \mathcal{G},\ \xi \in \Xi,\ t \in \mathcal{T} \]

energy_limit_weight

\[ \mathit{w}^{E}_{t} = \mathrm{w}^{\mathrm{gen}}_{t} \cdot \mathrm{w}^{\mathrm{yr}}_{\mathrm{snapshot\_period}(t)} \qquad \forall\, t \in \mathcal{T} \]

Objective#

\[ \min \mathit{total\_cost} \]

See also