Open Energy Benchmark
This repository contains code for benchmarking optimization solvers on problems from the energy planning domain, and an interactive website for analyzing the results.
https://github.com/open-energy-transition/solver-benchmark
Category: Energy Systems
Sub Category: Energy System Modeling Frameworks
Keywords from Contributors
energy-system-modelling energy-systems energy-system-planning investment-optimization operational-optimization power-system-model power-system-planning pypsa-africa pypsa-earth scenario-analysis
Last synced: about 6 hours ago
JSON representation
Repository metadata
A benchmark of (MI)LP solvers on energy modelling problems
- Host: GitHub
- URL: https://github.com/open-energy-transition/solver-benchmark
- Owner: open-energy-transition
- License: agpl-3.0
- Created: 2024-07-15T08:05:05.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2026-08-07T20:21:41.000Z (4 days ago)
- Last Synced: 2026-08-10T14:02:15.884Z (1 day ago)
- Language: Jupyter Notebook
- Homepage: https://openenergybenchmark.org/
- Size: 44.9 MB
- Stars: 72
- Watchers: 2
- Forks: 17
- Open Issues: 45
- Releases: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
README.md
Open Energy Benchmark
This repository contains code for benchmarking optimization solvers on problems from the energy planning domain, and an interactive website for analyzing the results. The live website can be viewed at:
https://openenergybenchmark.org/
Table of Contents
Benchmark Problems
All our benchmark problems are open and available as LP/MPS files that can be downloaded in one click from our website's Benchmark Problem Set page. Some problems have been generated by us using open source energy modelling frameworks, and for these we have configuration files and instructions for reproducing the problems.
For more details on how to contribute benchmark problems, see the Benchmarks README.
Solvers
The benchmark runner can run solvers listed in the Solvers README.
We use the last released solver version in each calendar year. 2025 solvers will be updated at the end of the year.
Project Structure
Understanding the project layout to help you navigate and contribute:
solver-benchmark/
├── runner/ # Benchmark execution scripts
│ ├── benchmark_all.sh # Main entry point for running benchmarks
│ ├── run_benchmarks.py # Python script that orchestrates benchmark runs
│ ├── run_solver.py # Individual solver runner
│ ├── envs/ # Conda environment definitions for each solver year
│ └── benchmarks/ # Downloaded benchmark problem files
├── benchmarks/ # Benchmark problem definitions and metadata
│ ├── pypsa/ # PyPSA-generated energy models
│ ├── jump_highs_platform/ # JuMP/HiGHS benchmark metadata
│ └── *_metadata.yaml # Problem definitions and details
├── website/ # Next.js website for viewing results
├── infrastructure/ # GCP VM deployment scripts (for running benchmarks at scale)
├── results/ # Output directory for benchmark results
├── benchmark_results.csv # Main results file
└── metadata.yaml # Merged metadata of all problems on the website
Running Benchmarks
Local Runs
Prerequisites
System Requirements
The benchmark runner currently requires Linux as it uses systemd-run to enforce memory limits on solvers, which is not available on macOS or Windows.
Supported Linux distributions:
- Ubuntu 20.04 LTS or later
- Debian 11 or later
- Other systemd-based Linux distributions
macOS / Windows users: Use the provided Docker image to run benchmarks in a Linux container. See Running with Docker below.
Required Software
Ensure you have the following installed:
- Python 3.12+
- Conda (install Miniconda)
- systemd (usually pre-installed on modern Linux distributions)
Running Supported Solvers on Benchmarks
The benchmark runner script (runner/benchmark_all.sh) is the main entry point for running benchmarks. It takes a list of solvers and a list of years as arguments, and runs the benchmarks for each solver and year. It creates conda environments containing the solvers and other necessary prerequisites, so a virtual environment is not necessary just for running the benchmark runner. See README .
Quickstart:
- Run benchmarks
./runner/benchmark_all.sh -s "highs scip" -y "2025" infrastructure/benchmarks/sample_run/standard-00.yaml
- View logs and results
tail results/benchmark_results.csv # will overwrite currently committed results
tail runner/logs/*
- View and analyze results by running the website locally
The script will save the measured runtime and memory consumption into a CSV file in results/ that the website will then read and display. Running the website locally will allow you to view and analyze results in a user friendly way. It will use the results from results/benchmark_results.csv.
runner/benchmark_all.sh uses runner/run_benchmarks.py to run the benchmarks by year. If you wish to run benchmarks directly, you can set up the requisite conda env manually. See Documentation.
Running with Docker
You can use Docker to run benchmarks in a Linux container that has all the required dependencies.
# Build the runner image
docker build -t solver-benchmark-runner -f runner/Dockerfile .
# Run all solvers across all years, results are written to host via a volume mount
docker run --rm \
-v $(pwd)/results:/solver-benchmark/results \
solver-benchmark-runner results/metadata.yaml
The container accepts the same flags as benchmark_all.sh (e.g. -s, -y). Memory limit enforcement via systemd-run is not available inside Docker and is skipped automatically. For more details on available options, conda env caching, and Gurobi licensing, see the runner Docker documentation.
Cloud Runs
We have cloud orchestration setup for running benchmarks on Google Cloud Platform. See Documentation.
Quickstart:
For cloud infrastructure setup, install:
gcloud auth application-default login
cd infrastructure
tofu init
tofu apply -var-file benchmarks/sample_run/run.tfvars
To set up comprehensive benchmark campaigns, like the one available on the website:
- Use
notebooks/allocate-benchmarks-to-vms.ipynbto create the benchmark campaign. - Run
notebooks/run-and-observe-benchmarks.ipynbto observe the benchmark campaign progress.
Alternatively, the benchmark campaign generation can be performed from the command line using the tools described below.
Benchmark campaign creation
This repository contains tooling to create benchmark campaigns from the benchmark metadata.
Campaigns can target either:
- cloud execution using Google Cloud Platform VMs (currently allowed to maintainers only);
- local execution using the existing benchmark runner workflow.
The main entry point is:
python benchmarks/create_benchmark_campaign.py
The script prepares benchmark metadata, selects benchmark instances, and creates
either:
- a cloud campaign under
infrastructure/benchmarks/<run-id>/; or - a local campaign under
infrastructure/local/benchmarks/<run-id>/.
Execution targets
The campaign generator supports two execution targets:
| Target | Description |
|---|---|
cloud |
Generates OpenTofu VM configuration files under infrastructure/benchmarks/<run-id>/. |
local |
Generates local benchmark files under infrastructure/local/benchmarks/<run-id>/. |
The default target is:
cloud
Override it with:
python benchmarks/create_benchmark_campaign.py \
--target local
to launch a benchmark campaign on your local machine.
Basic usage
Create a campaign for all benchmark instances (please do this very carefully, especially if running on the cloud):
python benchmarks/create_benchmark_campaign.py \
--campaign my-test \
--all
This creates a run ID of the form:
YYYYMMDD-my-test
Configuration files
Campaigns can also be defined through a YAML configuration file.
A complete template is provided in:
benchmarks/config.campaign.default.yaml
Run a campaign directly from a configuration file:
python benchmarks/create_benchmark_campaign.py \
--configfile benchmarks/config.campaign.default.yaml
Command-line arguments always override values defined in the configuration file.
For example:
python benchmarks/create_benchmark_campaign.py \
--configfile benchmarks/config.campaign.default.yaml \
--campaign my-test \
--timeout-hours 6
Select benchmarks
Select all instances of one benchmark:
python benchmarks/create_benchmark_campaign.py \
--campaign pypsa-eur-test \
--benchmark pypsa-eur
Select benchmark instances by size class:
python benchmarks/create_benchmark_campaign.py \
--campaign pypsa-eur-small-medium \
--benchmark pypsa-eur-elec \
--size S M
Select benchmark instances by metadata name, for example specific spatial or temporal resolutions (field Name in the metadata):
python benchmarks/create_benchmark_campaign.py \
--campaign pypsa-eur-resolution-test \
--benchmark pypsa-eur-elec \
--name 2-1h 3-2h
Combine size and name filters:
python benchmarks/create_benchmark_campaign.py \
--campaign pypsa-eur-filtered \
--benchmark pypsa-eur-elec \
--size S M \
--name 2-1h 3-2h
Select mixed benchmark instances explicitly:
python benchmarks/create_benchmark_campaign.py \
--campaign mixed-test \
--instance pypsa-eur:2-1h \
--instance pypsa-earth:3-2h
The instance selector uses the format:
<benchmark-name>:<instance-name>
For example:
PyPSA-DE:10-1h
Include metadata entries marked as skipped (due to known timeout or memory issues):
python benchmarks/create_benchmark_campaign.py \
--campaign clean-test \
--all \
--do-not-skip
Cloud VM allocation
This section only applies to cloud campaigns.
By default, the script creates one VM per selected benchmark instance.
Use a custom number of VMs with:
python benchmarks/create_benchmark_campaign.py \
--campaign packed-test \
--all \
--num-vms 5
Cloud machine settings
By default, benchmark instances are assigned to VM profiles automatically based on their metadata size class:
| Size class | Machine profile | GCP machine type | Timeout |
|---|---|---|---|
| S, M | short | c4-standard-2 | 1 hour |
| L | long | c4-highmem-16 | 24 hours |
Default zone:
us-central1-a
When --machine-type is specified, all selected benchmark instances use the chosen profile regardless of their size classification.
Timeout policy
If no timeout is provided, the script applies the default timeout policy:
S/M instances: 1 hour
L instances: 24 hours
Override the timeout:
python benchmarks/create_benchmark_campaign.py \
--campaign timeout-test \
--all \
--timeout-hours 6
Solver and year selection
By default, the generated VM YAML files benchmark all the following solvers:
gurobi highs scip cbc glpk
The default solver year is:
2025
The year corresponds to the benchmark conda environment:
benchmark-<year>
For example:
2025 -> benchmark-2025
Run specific solvers for one or more years:
python benchmarks/create_benchmark_campaign.py \
--campaign year-test \
--all \
--solver cbc highs \
--years 2024 2025
Campaign summary
Every generated campaign includes a:
campaign_summary.csv
containing the benchmark selection, campaign configuration, solver selection,
timeout settings, allocation decisions, and metadata used to create the campaign.
Existing campaign directories
The script fails if the target campaign directory already exists.
Use a different campaign name, remove the existing directory, or overwrite it:
python benchmarks/create_benchmark_campaign.py \
--campaign my-test \
--all \
--force
Launching a cloud campaign
After reviewing the generated files, launch the campaign from the infrastructure directory:
cd infrastructure
tofu apply \
-var-file benchmarks/<run-id>/run.tfvars \
-state=states/<run-id>.tfstate
Launching a local campaign
Generate a local campaign:
python benchmarks/create_benchmark_campaign.py \
--target local \
--campaign my-local-run \
--benchmark pypsa-de-elec
This creates:
infrastructure/local/benchmarks/<run-id>/
├── campaign_summary.csv
├── local_benchmarks.yaml
└── run_local.sh
By default, local campaigns ask for confirmation before execution.
The generated run script can also be executed manually:
bash infrastructure/local/benchmarks/<run-id>/run_local.sh
Local campaigns use the existing runner/benchmark_all.sh workflow and execute benchmark instances sequentially.
Example workflows
Cloud campaign
python benchmarks/create_benchmark_campaign.py \
--configfile benchmarks/config.campaign.default.yaml \
--campaign pypsa-de-scaling
cd infrastructure
tofu apply \
-var-file benchmarks/<run-id>/run.tfvars \
-state=states/<run-id>.tfstate
Local campaign
python benchmarks/create_benchmark_campaign.py \
--configfile benchmarks/config.campaign.default.yaml \
--target local \
--campaign pypsa-de-local
The campaign generator creates the local benchmark files and asks whether the benchmark run should be started immediately.
Running your own benchmarks
To run your own benchmark problems, either locally or on the cloud, follow the steps in the appropriate section above but using a benchmarks.yaml file of your own that gives the details (metadata) and URL/path of your benchmark problems.
Here is a small example:
benchmarks:
genx-3_three_zones_w_co2_capture-no_uc:
Sizes:
- Name: 3-1h
# Size classification
Size: M
# URL of the problem (needed for cloud runs)
URL: https://storage.googleapis.com/solver-benchmarks/genx-3_three_zones_w_co2_capture-no_uc.lp
# ALTERNATIVELY, for local runs, you can also give a local path
Path: tests/sample_benchmarks/sample_lp.lp
You can quickly try running your own problem locally on our supported set of solvers by following these instructions.
Running other solvers
To run either our benchmarks, or your own (see the previous section), on a solver that we do not yet support, you need to install it into the active conda evironment and modify the run_solver.py appropriately. Please reach out to us (or open an issue) if you would like more details, or any help with this.
Running the Website
The website code is under website/. To run the website locally, you need a recent version of node and npm installed. Then, run the following commands:
cd website/
npm install
npm run build && npm run dev
Open http://localhost:3000 with your browser to see the website.
To see the results from your runs, navigate to the results page.
Development
We use the ruff code linter and formatter, and GitHub Actions runs various pre-commit checks to ensure code and files are clean.
You can install a git pre-commit that will ensure that your changes are formatted
and no lint issues are detected before creating new commits:
pip install pre-commit
pre-commit install
If you want to skip these pre-commit steps for a particular commit, you can run:
git commit --no-verify
Owner metadata
- Name: open-energy-transition
- Login: open-energy-transition
- Email:
- Kind: organization
- Description:
- Website:
- Location:
- Twitter:
- Company:
- Icon url: https://avatars.githubusercontent.com/u/131007753?v=4
- Repositories: 1
- Last ynced at: 2023-05-03T12:28:56.288Z
- Profile URL: https://github.com/open-energy-transition
GitHub Events
Total
- Create event: 139
- Issues event: 119
- Watch event: 28
- Delete event: 119
- Member event: 1
- Issue comment event: 307
- Push event: 657
- Pull request event: 272
- Pull request review event: 321
- Pull request review comment event: 127
- Fork event: 4
Last Year
- Create event: 135
- Issues event: 115
- Watch event: 27
- Delete event: 117
- Member event: 1
- Issue comment event: 295
- Push event: 640
- Pull request event: 266
- Pull request review event: 310
- Pull request review comment event: 119
- Fork event: 4
Committers metadata
Last synced: 10 days ago
Total Commits: 320
Total Committers: 16
Avg Commits per committer: 20.0
Development Distribution Score (DDS): 0.559
Commits in past year: 140
Committers in past year: 16
Avg Commits per committer in past year: 8.75
Development Distribution Score (DDS) in past year: 0.55
| Name | Commits | |
|---|---|---|
| jacek-oet | j****g@o****g | 141 |
| Siddharth Krishna | s****a | 51 |
| Daniele Lerede | d****e@o****g | 47 |
| Kristijan Faust | k****t@o****g | 36 |
| pre-commit-ci[bot] | 6****] | 13 |
| Goli Vamsi Priya | g****2@g****m | 9 |
| dependabot[bot] | 4****] | 6 |
| Enrico Antonini | 5****i | 5 |
| Madhukar Mishra | m****3@g****m | 3 |
| Fabrizio Finozzi | 1****a | 3 |
| nodet | x****t@g****m | 1 |
| Philipp Dunkel | 8****j | 1 |
| Nour Boulos | n****s@e****h | 1 |
| JohannesBehrens | 1****s | 1 |
| Diego Alejandro Tejada Arango | 1****a | 1 |
| Amir | 6****i | 1 |
Committer domains:
- openenergytransition.org: 3
- ethz.ch: 1
- gurobi.com: 1
Issue and Pull Request metadata
Last synced: 1 day ago
Total issues: 105
Total pull requests: 354
Average time to close issues: about 1 month
Average time to close pull requests: 11 days
Total issue authors: 9
Total pull request authors: 18
Average comments per issue: 0.7
Average comments per pull request: 1.38
Merged pull request: 250
Bot issues: 0
Bot pull requests: 23
Past year issues: 22
Past year pull requests: 59
Past year average time to close issues: 3 months
Past year average time to close pull requests: about 1 month
Past year issue authors: 6
Past year pull request authors: 14
Past year average comments per issue: 0.5
Past year average comments per pull request: 1.88
Past year merged pull request: 28
Past year bot issues: 0
Past year bot pull requests: 7
Top Issue Authors
- siddharth-krishna (84)
- jacek-oet (9)
- danielelerede-oet (5)
- nodet (2)
- FBumann (1)
- erling-d-andersen (1)
- LarsHadidi (1)
- mattmilten (1)
- jajhall (1)
Top Pull Request Authors
- jacek-oet (143)
- siddharth-krishna (67)
- danielelerede-oet (64)
- KristijanFaust-OET (34)
- pre-commit-ci[bot] (17)
- eantonini (8)
- dependabot[bot] (6)
- Vamsipriya22 (4)
- drifter089 (2)
- nodet (1)
- mafish88 (1)
- lprieto1409 (1)
- nour-boulos (1)
- finozzifa (1)
- HeathNaylor (1)
Top Issue Labels
- website (4)
- enhancement (3)
- bug (3)
- monitoring (1)
- dependencies (1)
- benchmark (1)
Top Pull Request Labels
- enhancement (12)
- benchmark (11)
- website (9)
- dependencies (7)
- javascript (4)
- do not merge (2)
- documentation (2)
- monitoring (2)
Dependencies
- aiohappyeyeballs 2.6.1
- aiohttp 3.13.3
- aiosignal 1.4.0
- appnope 0.1.4
- argcomplete 3.6.3
- asttokens 3.0.1
- attrs 25.4.0
- boto 2.49.0
- cachetools 5.5.2
- certifi 2026.1.4
- cffi 2.0.0
- charset-normalizer 3.4.4
- colorama 0.4.6
- comm 0.2.3
- contourpy 1.3.3
- crcmod 1.7
- cryptography 43.0.3
- cycler 0.12.1
- debugpy 1.8.20
- decorator 5.2.1
- executing 2.2.1
- fasteners 0.20
- fonttools 4.61.1
- frozenlist 1.8.0
- gcs-oauth2-boto-plugin 3.3
- google-apitools 0.5.35
- google-auth 2.39.0
- google-auth-httplib2 0.3.0
- google-reauth 0.1.1
- gsutil 5.35
- httplib2 0.20.4
- humanize 4.15.0
- idna 3.11
- ipykernel 7.1.0
- ipython 9.10.0
- ipython-pygments-lexers 1.1.1
- jedi 0.19.2
- jinja2 3.1.6
- jupyter-client 8.8.0
- jupyter-core 5.9.1
- kiwisolver 1.4.9
- markupsafe 3.0.3
- matplotlib 3.10.8
- matplotlib-inline 0.2.1
- monotonic 1.6
- multidict 6.7.1
- nest-asyncio 1.6.0
- notebooks 0.1.0
- numpy 2.4.2
- oauth2client 4.1.3
- packaging 26.0
- pandas 3.0.0
- parso 0.8.5
- pexpect 4.9.0
- pillow 12.1.0
- platformdirs 4.5.1
- prompt-toolkit 3.0.52
- propcache 0.4.1
- psutil 7.2.2
- ptyprocess 0.7.0
- pure-eval 0.2.3
- pyasn1 0.6.2
- pyasn1-modules 0.4.2
- pycparser 3.0
- pygments 2.19.2
- pyopenssl 24.2.1
- pyparsing 3.3.2
- python-dateutil 2.9.0.post0
- pyu2f 0.1.5
- pyyaml 6.0.3
- pyzmq 27.1.0
- requests 2.32.5
- retry-decorator 1.1.1
- rsa 4.7.2
- scipy 1.17.1
- six 1.17.0
- stack-data 0.6.3
- tornado 6.5.4
- traitlets 5.14.3
- tzdata 2025.3
- urllib3 2.6.3
- wcwidth 0.5.3
- yarl 1.22.0
- continuumio/miniconda3 latest build
- humanize ==4.11.0
- pandas ==2.2.2
- pyyaml >=6.0
- streamlit ==1.54.0
- streamlit-aggrid ==1.0.5
- streamlit_shadcn_ui ==0.1.18
- pip
- python 3.9
- pyyaml
- requests
- ruamel.yaml
- python 3.12-slim build
- @axe-core/cli ^4.11.1 development
- @axe-core/react ^4.11.1 development
- @eslint/eslintrc ^3 development
- @types/d3 ^7.4.3 development
- @types/js-yaml ^4.0.9 development
- @types/lodash.camelcase ^4.3.9 development
- @types/node ^20 development
- @types/papaparse ^5.3.15 development
- @types/react ^19 development
- @types/react-dom ^19 development
- @types/semver ^7.5.8 development
- eslint ^9 development
- eslint-config-next 16.2.6 development
- eslint-plugin-jsx-a11y ^6.10.2 development
- postcss >=8.5.10 development
- tailwindcss ^3.4.18 development
- typescript ^5 development
- @emailjs/browser ^4.4.1
- @redux-devtools/extension ^3.3.0
- @svgr/webpack ^8.1.0
- @tailwindcss/typography ^0.5.19
- @tanstack/react-table ^8.20.6
- @tanstack/react-virtual ^3.13.12
- better-react-mathjax ^2.3.0
- compare-versions ^6.1.1
- d3 ^7.9.0
- gray-matter ^4.0.3
- gsap ^3.15.0
- i ^0.3.7
- ip-address >=10.1.1
- js-yaml ^4.1.1
- jszip ^3.10.1
- lodash ^4.18.0
- lodash.camelcase ^4.3.0
- next ^16.2.6
- next-redux-wrapper ^8.1.0
- node-fetch ^3.3.2
- papaparse ^5.5.1
- react ^18.3.1
- react-dom ^18.3.1
- react-google-recaptcha-v3 ^1.10.1
- react-icons ^5.5.0
- react-intersection-observer ^9.16.0
- react-redux ^9.2.0
- react-select ^5.9.0
- reactjs-popup ^2.0.6
- redux ^5.0.1
- redux-thunk ^3.1.0
- remark ^15.0.1
- remark-gfm ^4.0.1
- remark-html ^16.0.1
- yaml >=2.8.3
- actions/checkout v4 composite
- github/codeql-action/analyze v3 composite
- github/codeql-action/autobuild v3 composite
- github/codeql-action/init v3 composite
- continuumio/miniconda3 latest build
- plain_pypsa_benchmark_gen_base latest build
- actions/checkout v4 composite
- actions/setup-node v4 composite
- actions/setup-python v5 composite
- actions/upload-artifact v4 composite
- conda-incubator/setup-miniconda v3 composite
- pixi_env latest build
- pypsa_benchmark_gen_base latest build
- pypsa_eur_setup latest build
- repo_clone latest build
- ubuntu latest build
- 878 dependencies
- gsutil >=5.35
- humanize >=4.15.0
- ipykernel >=7.1.0
- ipython >=9.10.0
- jinja2 >=3.1.6
- matplotlib >=3.10.8
- numpy >=2.4.2
- pandas >=3.0.0
- pyyaml >=6.0.3
- scipy >=1.17.1
Score: 7.534762657037538