Power system modeling

I saw a job position with the requirement: “Proficiency in open-source power system tools (e.g. PyPSA, Dispa-SET, or Calliope) and other dispatch-related software.”

Is there anything similar in Julia?

Yes. Rather than enumerate the many projects, i might just link to

5 Likes

Nice! How, do you think that https://www.callio.pe/ and PowerSimulations.jl compare?

Does PowerSimulations.jl handle different spacial resultions, e.g. on the national and the city scale?

In the moment, callio looks simpler to me, because you just have .yaml files (for the model) and .csv files (for time series) as input that you have to define. How do you define the input of PowerSimulations.jl ?

This is a question for @jdlara-berkeley

PowerSimulations.jl is an operations simulation engine not an expansion problem. It focuses more on PCM analyses or IRP development. The model resolution will depend on your data.

The inputs to PowerSimulations.jl are defined via system data in PowerSystems.jl you are welcome to check the recent tutorials on how to put the data together Welcome Page · PowerSystems.jl

1 Like

So is there a Julia package that solves the expansion problem?

We are developing IESopt.jl since 2021, which has been open-sourced this spring (note that the docs are in a different repository). It is quite similar to Calliope in some ways (we use YAML & CSV files in a very similar way, and it’s “no-code” unless you want to do your own constraints, etc.), but our components are considerably more flexible in how a user can create new “technologies” (and it’s JuMP-based so we are fast :wink:). See this example for a simple (but complete) configuration.

It’s still not exactly “outsider-friendly” since moving all of the (potentially confidential) stuff from our internal repos is quite a long task. But it integrates nicely with other packages that make use of JuMP models and supports stochastic optimization (via SDDP.jl or a custom Benders based two-stage mode), multi-objectives (via MultiObjectiveAlgorithms.jl), custom “model-to-pdf” rendering, etc. Some of these things are already in the open-source version, some of that is still being transferred.

Note that there are others as well, for example:

(sorry for any that I left out, surely an incomplete list)

Basically any full blown “energy system optimization model” will to some extent feature planning (expansion, …) and operational stage(s). Most however are limited to simplified formulations (e.g., “DC-OPF”), but since PowerModels.jl exists this can be extended (you can, e.g., couple it with an IESopt.jl model to make use of the more sophisticated formulations that PowerModels.jl offers - which should be somehow possible for all JuMP-based models).

edit: if anyone is ever interested, I’m happy to give a short bilateral intro

2 Likes

Nice! Thanks for the detailed reply.

If I compare the github stars:

GenX.jl (GPL) (suggests Julia 1.9) 280
SpineOpt.jl (GPL) (needs also Python) 60
TulipaEnergyModel.jl (Apache) Input: CSV 28
IESopt.jl (MIT) Input: YAML 15
EnergyModelsBase.jl (MIT) Input: Julia 8

But that cannot be the only criteria. I like YAML files as input, for example.

I am looking at this position: “Postdoc Energy and Water System Dispatch under Uncertainty Job Details | TU Delft

Not so clear to me yet:

Any ideas?

I can’t really speak for the other packages since I’m mostly working with our internal one, Calliope, and PyPSA. I’ll pick ours, but both Calliope and PyPSA work very similarly for the answers.


  1. You introduce two energy carriers (without any specifics)
carriers:
  water: {}
  electricity: {}
  1. Discharging water from, e.g., a reservoir could then be done by creating a basic “turbine” like this
turbine:
  type: Unit
  inputs: {water: reservoir_upper}
  outputs: {water: reservoir_lower, electricity: grid}
  conversion: 1 water -> 1 water + <w2h_ratio> electricity

This makes use of a parameter w2h_ratio that you could set from the outside to describe the 1 \text{m}^3 (or whatever unit you choose for water) to electricity ratio (depending on height, efficiency, etc.).

  1. It further assumes (besides others) that there is a “lower reservoir”, which could look like this (if we assume a fixed capacity of 10000 units of water)
reservoir_lower:
  type: Node
  carrier: water
  has_state: true
  state_lb: 0
  state_ub: 1e4
  1. If you want to extend that to a cascade you could include that the water flows along a “river”:
river:
  type: Connection
  node_from: reservoir_lower
  node_to: some_other_reservoir
  lb: 0
  ub: 500    # an upper bound on the flow
  delay: 15  # 15 hours delay between "in" and "out"

Depending on what exactly you mean by “spatially explicit”, yes. That’s what ESMs are used for: Modeling energy systems with a wide range across time and location. You could for example assume that (electricity market) bidding zones for Sweden (just as an example for hydro stuff) exist, which are called SE1 to SE4.

  1. You can then create unique grid nodes for these, e.g., by doing:
grid_se1:
  type: Node
  carrier: electricity

grid_se2:
  type: Node
  carrier: electricity

transmission_line17:
  type: Connection
  node_from: grid_se1
  node_to: grid_se2
  capacity: 1200

That would be a simple “transport model” electricity exchange between the two zones, commonly linked to “NTCs” (net transfer capacities).

  1. Now let’s say you are interested in a transmission expansion model. Then you could do modify the line to
transmission_line17:
  type: Connection
  node_from: grid_se1
  node_to: grid_se2
  capacity: 0.9 * (1200 + upgrade_tl17:value)

upgrade_tl17:
  type: Decision
  lb: 0
  ub: 500
  cost: 17248

This would modify the line to “start” with a capacity of 1200 (assuming that unit is most likely MW_electricity, allowing the model to extend it by up to 500, but (additionally) accounting for a simple “safety margin” of 10% of the overall capacity — only allowing 90% to be used. Each MW of additional capacity costs 17248 Euros (or whatever monetary unit you use).


Note that all of this is the most basic way to do stuff like this. You would normally group these basic building blocks like “Nodes” and “Connections” (we call these CoreComponents) into more complex assets (e.g., a pumped hydro storage with natural inflow) — we call this templates. You can then immediately initialize new components from these templates, and the model constructs all underlying components automatically, and connects them as defined.

That allows then loading components from a simple CSV file. Imagine that looking like so:

name type w2h_ratio grid_connection
plant_foo HydroReservoirPlant 0.0124 se1.grid
plant_bar HydroReservoirPlant 0.0324 se2.grid

This uses:

  • A user defined template HydroReservoirPlant that models such a plant
  • Sets unique values for their w2h_ratio parameter
  • Assumes the template has a further parameter called grid_connection to specify where the electricity is injected
  • Using se1.grid is a notation that can be used to access (sub)components within other templates, here assuming that there is something called se1 (e.g., of type BiddingZone), that contains a Node called grid.
2 Likes

I currently do not have a large-scale publicly available model “lying around”, but you can either check out the national scale example from Calliope, any of the pre-configured PyPSA-Eur (or Earth, etc.) models, or one of our examples, e.g.:

  • Creating models with multiple locations fully from CSV files [config]
  • Creating models which dynamically load (or don’t) components based on a set of regions/countries defined [config]

As most other large-scale models our formulations are MILP (mostly LP), supporting SOS1/2, or manual piecewise linear formulations. However, since JuMP makes that rather easy to do, you can — without any change — add custom formulations to the model that are different (e.g., SDPs), as long as you use an appropriate solver (e.g., if you want to model losses inside the waterways between reservoir and turbine, based on flow speed, etc.).

Note: I’ve got a European-scale model from a climate uncertainty study that I can “show” (as in: I can show the config, etc. in a call, but can’t openly share the full thing right now).

2 Likes

Just one final remark, that description explicitly lists an energy system model / framework: OSeMOSYS.

I know, and I know OSeMOSYS, but I think the task is to use the output of an OSeMOSYS model as a starting point and “Test the resilience of planned WEF development pathways under different climate and market uncertainties and so inform constraints for multi-sectoral infrastructure investment planning” etc etc

And I know that OSeMOSYS is quite limited, and we would most likely need more powerful models to achieve the desired results. And the description also explicitly mentions Julia skills as a desired capability.