Skip to content

PyPSA in 24 files#

You can read the PyPSA spec here one topic at a time. PyPSA in one file states it as examples/pypsa.yaml, one spec of about four thousand lines. The same spec is split into 24 fragments, one file per topic under examples/pypsa/. merge joins the 24 files back into the one file, and the two have the same canonical form.

Each fragment loads and prints on its own, and advice runs on each fragment alone. A fragment lists each name that it reads but does not declare under given. Some sums take a share from every component, such as the bus balance or the operating cost. A component names its share of such a sum as an expression of its own, a term, whose adds_to: key names the sum. For each sum, one fragment reads it and adds nothing to it, so the terms always have a reader. To add a component, you add one file, and the network file does not change.

tools/pypsa_split.py writes the 24 files from the one file, and a check compares them to it, so the two always agree. The split is a proof of concept, and which of the two is the source is not decided yet.

What each file says#

The fragments are of three kinds:

  • A component file owns the PyPSA class of that name: its dimension, its data, its variables, its rows and its share of each sum. The committable classes are Generator, Link and Process. Each of them is cut by feature into four files: the class, its commitment, its ramping and its maintenance. The three sets of four files read alike, because PyPSA builds the same rows for each class.
  • An owner file reads a sum with its description, and holds the row that reads it. The network reads Bus_injection, and power flow reads Cycle_angle_sum.
  • The settings file holds the weightings and the flags that every topic reads. It also reads the totals whose own readers a spec may leave out: the cost, the carriers and the global constraints. It sets the objective, which reads total_cost. Each component adds its capital cost to total_cost, and the cost file adds the operating cost at risk.

The sums#

Sum Over Read in The terms, by the fragment that adds each
total_cost scalar settings risk_weighted_opex, Generator_capex, Line_capex, Link_capex, Process_capex, StorageUnit_capex, Store_capex, Transformer_capex
scenario_opex scenario settings Generator_opex, Generator_commitment_opex, Link_opex, Link_commitment_opex, Process_opex, Process_commitment_opex, StorageUnit_opex, Store_opex
Bus_injection scenario, snapshot, bus network Generator_injection, Line_injection, Link_injection, Load_injection, Process_injection, StorageUnit_injection, Store_injection, Transformer_injection
tech_capacity_expansion global_constraint settings Generator_tech_capacity_expansion, Line_tech_capacity_expansion, Link_tech_capacity_expansion, Process_tech_capacity_expansion, StorageUnit_tech_capacity_expansion, Store_tech_capacity_expansion
Carrier_additions period, carrier settings Generator_additions, Line_additions, Link_additions, Process_additions, StorageUnit_additions, Store_additions
primary_energy scenario, global_constraint settings Generator_primary_energy, StorageUnit_primary_energy, Store_primary_energy
operational_limit scenario, global_constraint settings Generator_operational_limit, StorageUnit_operational_limit, Store_operational_limit
transmission_volume_expansion scenario, global_constraint settings Line_transmission_volume_expansion, Link_transmission_volume_expansion
transmission_expansion_cost scenario, global_constraint settings Line_transmission_expansion_cost, Link_transmission_expansion_cost
Cycle_angle_sum scenario, snapshot, cycle power_flow Line_angle_sum, Transformer_angle_sum

The fragments#

Fragment Parameters Variables Constraints Reads Adds to
carrier 2 0 1 1
cost 1 3 2 4 total_cost
generator 24 3 11 17 primary_energy, operational_limit, tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions, Bus_injection
generator_commitment 10 3 20 17 scenario_opex
generator_maintenance 5 4 13 9
generator_ramping 5 0 6 14
global_constraints 3 0 15 6
line 22 4 14 9 transmission_volume_expansion, transmission_expansion_cost, tech_capacity_expansion, total_cost, Carrier_additions, Bus_injection, Cycle_angle_sum
link 24 3 9 16 transmission_volume_expansion, transmission_expansion_cost, tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions, Bus_injection
link_commitment 10 3 20 17 scenario_opex
link_maintenance 5 4 13 9
link_ramping 5 0 6 14
load 3 0 0 1 Bus_injection
network 0 0 1 1
power_flow 0 0 1 1
process 22 3 9 14 tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions, Bus_injection
process_commitment 10 3 20 17 scenario_opex
process_maintenance 5 4 13 9
process_ramping 5 0 6 14
security 2 0 8 10
settings 9 0 0 8
storage_unit 36 6 21 14 primary_energy, operational_limit, tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions, Bus_injection
store 29 4 11 14 primary_energy, operational_limit, tech_capacity_expansion, scenario_opex, total_cost, Carrier_additions, Bus_injection
transformer 24 5 16 5 total_cost, Bus_injection, Cycle_angle_sum

Leaving a file out#

You may leave out a component family, the cost, the carriers, the global constraints or security. What is left is a whole spec, with nothing left under given:. You may not leave out the network or power flow while a component is in, because the terms of the component would then add to a sum that no fragment reads, and merge refuses the files.