Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
235 commits
Select commit Hold shift + click to select a range
e57ab5c
feat: new pixi env setup file
JanTautorus Mar 13, 2026
f2a0410
feat: Add pre-commit config with ruff + hygiene hooks
JanTautorus Mar 13, 2026
d509aa5
fix: correct pixi.toml feature/environment configuration
JanTautorus Mar 13, 2026
fa09028
feat: add pre-commit configuration
JanTautorus Mar 13, 2026
d5f892f
chore: lint Python scripts with ruff
JanTautorus Mar 13, 2026
365993c
chore: notebook linting adjustments
JanTautorus Mar 13, 2026
4468e90
chore: add nbqa to pixi dev dependencies
JanTautorus Mar 13, 2026
9220a56
chore: add nbqa to pixi dev dependencies
JanTautorus Mar 13, 2026
5dbe7af
chore: add GitHub Actions CI for Pixi env setup
JanTautorus Mar 13, 2026
9571048
Merge branch '21-minimum-viable-run' of https://github.com/energyLS/s…
JanTautorus Mar 16, 2026
8d79c36
feat: add new streamlined readme
JanTautorus Mar 20, 2026
b8ec17a
feat: add detailed workflow plan
JanTautorus Mar 20, 2026
56855bd
chore: update plan with Step 1 policy assumptions
JanTautorus Mar 24, 2026
380ebd7
feat: add renewable potential clustering pipeline with validation and…
JanTautorus Mar 24, 2026
c79cd94
feat: distill config to barebones setup
JanTautorus Mar 24, 2026
dba3c33
fix: improve docs and change previous unit from GW to correct MW
JanTautorus Mar 25, 2026
f29ed62
feat: add comprehewnsive docs and complete clustering/validation
JanTautorus Mar 25, 2026
1985acf
feat: implement supply chain of steel based on technology data base
JanTautorus Mar 26, 2026
10fca00
chore: add missing snakemake import
JanTautorus Mar 26, 2026
6efadb4
feat: streamline retrieval and processing of pypsa-tech-database
JanTautorus Mar 27, 2026
156e4bd
feat: better code integration and documentation
JanTautorus Mar 27, 2026
63446dc
wip: dont look, still refactoring step1
JanTautorus Mar 30, 2026
69d781a
chore: update linting
JanTautorus Apr 1, 2026
69f2530
wip: lcox runs, but with uncharcterisitic infeasibility\n\nneed to ch…
JanTautorus Apr 1, 2026
1ee1a05
feat: update linter setup
JanTautorus Apr 2, 2026
9ff03e4
fix: add proper year in supply chain
JanTautorus Apr 2, 2026
c10363c
chore: format with proper linting
JanTautorus Apr 2, 2026
75aa4b3
feat: add runnable version of supply curve generation!
JanTautorus Apr 2, 2026
2c7b246
chore: clean up config and snakemake file
JanTautorus Apr 3, 2026
7d9b153
feat: expand precommit file
JanTautorus Apr 3, 2026
ea20d20
chore: improve installation, env and pre-commit
JanTautorus Apr 3, 2026
9447633
feat: add renewable potential for new workflow
JanTautorus Apr 3, 2026
edfa30b
chore:cleanup legacy code
JanTautorus Apr 3, 2026
396d4fa
chore: implement better markdown style - each sentence in a new line
JanTautorus Apr 7, 2026
31d401c
feat: add comprehensive renewable potential processing
JanTautorus Apr 8, 2026
563eb99
fix: cleanup data structre of renewable profiles and speed up processing
JanTautorus Apr 10, 2026
ed6bbcd
chore: update readme formatting
JanTautorus Apr 13, 2026
4f7359f
chore: add ipykernel to dev env
JanTautorus Apr 14, 2026
e661727
feat: add complete workflow for processing and plotting pypsa_earth data
JanTautorus Apr 15, 2026
afb739c
fix: validated full workflow for potential extraction and analysis fr…
JanTautorus Apr 16, 2026
32bfdb2
feat: refactored data loading and visualization from pypsa-earth into…
JanTautorus Apr 17, 2026
3468ea3
chore: add clear documentation about renewable potential data format
JanTautorus Apr 17, 2026
a7eef4e
fix: improve grid reconiliation to catch edgecases
JanTautorus Apr 20, 2026
a16c2ee
feat: change input format of renewable potential to minimal xarray da…
JanTautorus Apr 22, 2026
6aa9ea5
feat: implement two-stage renewable filtering + generalize product de…
JanTautorus Apr 22, 2026
ad98041
chore: integrate refactoring in snakemake rules
JanTautorus Apr 22, 2026
a1c7712
fix: change carrier naming to include technology as commented in PR
JanTautorus Apr 27, 2026
8fdb0da
chore: change renewable profile input to new structure
JanTautorus Apr 27, 2026
35381be
chore:update readme to better align with workflow
JanTautorus Apr 27, 2026
9292832
chore: change config file to real data case
JanTautorus Apr 27, 2026
a344f7b
feat: add simple tests to verify the workflow based on a easy to unde…
JanTautorus Apr 27, 2026
0f5a2c1
feat: isolate EAF grid supply
JanTautorus Apr 28, 2026
61ff233
chore: rename electricity demand wording
JanTautorus Apr 28, 2026
594e9de
test: rework supply workflow coverage
JanTautorus Apr 28, 2026
7d3e26f
ci: use pixi test env and env-driven HiGHS solver override
JanTautorus Apr 28, 2026
df750de
feat: process just trace renewables for easier workflow
JanTautorus May 6, 2026
60c4e46
feat: add blocs for trace regions
JanTautorus May 6, 2026
fab7e2c
feat: consolidate snakemake workflow
JanTautorus May 6, 2026
db22d7f
chore: improve snakemake workflow and split thematical tasks
JanTautorus May 7, 2026
627d632
fix: configure independent snakemake workflow path
JanTautorus May 7, 2026
207f8c0
chore: order pixi dependencies
JanTautorus May 11, 2026
eb985f2
feat: clean up and improve domestic reservation for renewable generators
JanTautorus May 11, 2026
9daac47
feat: enable modular, unambiguous slicing of supply chain in stages
JanTautorus May 12, 2026
b824e0c
feat: implement stage seperated, modular and dynamic calculation of lcox
JanTautorus May 18, 2026
3d8aaff
chore: remove stale env
JanTautorus May 18, 2026
dee5d40
feat: add trade chain utils
energyLS May 19, 2026
5259312
fix: adjust path for mock snakemake
energyLS May 19, 2026
83f077a
fix: add trade chain utils in alternative path to be recognized by sn…
energyLS May 19, 2026
108bec7
feat: get all new wildcards and adjust color position to config
energyLS May 19, 2026
35bbe34
feat: simplify country map based on new iso3 from config and apply co…
energyLS May 19, 2026
b0c1508
feat: add trade model smk and adjust
energyLS May 19, 2026
9ca3aff
feat: successfull trade model run on updated config and snakefile
energyLS May 19, 2026
fc5edf3
feat: build trade model from trade_chains
energyLS May 19, 2026
1aa0131
chore: consolidate logging
JanTautorus May 19, 2026
700398f
fix: adjust to new supply chain naming of files
energyLS May 19, 2026
6ce28f5
feat: adjust to new file content of supply curves
energyLS May 19, 2026
d31e2e4
feat: improve modular PyPSA supply chain creation
JanTautorus May 19, 2026
c91f3df
chore: cleanup old trade scenarios
JanTautorus May 19, 2026
5017fce
chore: add incomplete inspection notebooks
JanTautorus May 19, 2026
5dfbbe6
feat: adjust hydrogen and wacc in config
energyLS May 19, 2026
f9e6194
feat: adjust where to get the trade scenarios from in snakefile
energyLS May 19, 2026
f7f4f0e
feat: implement scenario management for trade scenarios
energyLS May 19, 2026
21db114
Merge remote-tracking branch 'origin/dev' into 21-minimum-viable-run
JanTautorus May 19, 2026
90edfef
feat: add reporting smk
energyLS May 19, 2026
207b923
fix: move snakefile and trade_chain_utils to correct path
energyLS May 19, 2026
9da97d1
fix: revert change of script path
energyLS May 19, 2026
8743326
feat: add preparation smk for notebooks
energyLS May 19, 2026
232747c
fix: adjust preparation notebooks to new region definition
energyLS May 19, 2026
40f6aaf
fix: cleanup code broken during merge
JanTautorus May 20, 2026
675e78f
feat: mga plot min instable exports instead of max stable
energyLS May 20, 2026
b36a1ba
chore: add simple pypsa analysis
JanTautorus May 20, 2026
d2b40ad
feat: improve plotting of LCOX
JanTautorus May 20, 2026
9f0f526
Merge branch 'dev' into 21-minimum-viable-run
energyLS May 21, 2026
ba16e3b
chore: delete stale test
JanTautorus May 21, 2026
b03be97
chore: delete trade_singlestage script
JanTautorus May 21, 2026
15236ff
chore: remove duplicated dir creation
JanTautorus May 21, 2026
8cbe97e
chore: move additonal tech parameters into config
JanTautorus May 21, 2026
02fc08b
chore: write proper elif
JanTautorus May 21, 2026
3288b6a
Merge pull request #34 from energyLS/21-minimum-viable-run
energyLS May 21, 2026
aa034fa
fix: adjust wacc paths and update steel demand input in supply curve
energyLS May 21, 2026
7407004
feat: add eur usd exchange rate and energy ratios necessary for noteb…
energyLS May 21, 2026
d57c447
chore: remove depreciated notebook for steel production preparation
energyLS May 21, 2026
6b3d053
chore: bring back notebook on conceptional model which was deleted in…
energyLS May 21, 2026
93d41dd
fix: have separate helper file for notebooks
energyLS May 21, 2026
0e81927
fix: hardcode first product hbi in trade model rule
energyLS May 21, 2026
7cb32a7
chore: remove legacy wacc code in trade model
energyLS May 21, 2026
5701a36
feat: proposed workflow structure of wacc integration
energyLS May 21, 2026
e36770b
feat: proposed integration of wacc in regional network (incomplete)
energyLS May 21, 2026
d44c855
fix: repair lco steel calculation
JanTautorus May 21, 2026
e3402d7
fix: add gurobi channel back in
JanTautorus May 21, 2026
8a0a4fb
fix: update snakemake path for full workflow
energyLS May 22, 2026
23e9a45
feat: integrate wacc in prepare_regional_network fully
energyLS May 22, 2026
f2aa6f4
chore: remove config wacc regional values
energyLS May 22, 2026
89ff4a7
chore: remove _wacc_for_region depreciated function
energyLS May 22, 2026
43ffab6
feat: add rule to download labour data
energyLS May 22, 2026
6831f40
feat: add rule to prepare labour cost
energyLS May 22, 2026
cced87f
fix: repair incorrect PyPSA network generator addition
JanTautorus May 22, 2026
6cacd6d
Merge branch 'dev' into wacc-in-new-supply-chain
energyLS May 22, 2026
071e8ab
Merge branch 'dev' into labour-cost-in-new-supply-chain
energyLS May 22, 2026
9e4d121
feat: add labour cost feature
energyLS May 22, 2026
74bf4e2
feat: add labour cost toggle to config
energyLS May 22, 2026
3cba678
fix: add missing pixi dependencies for notebook execution
JanTautorus May 22, 2026
29ecfda
Merge pull request #42 from energyLS/wacc-in-new-supply-chain
JanTautorus May 22, 2026
84a3d4a
chore: unify logging and remove printing. Also fix previous linting v…
JanTautorus May 26, 2026
11b8dd9
fix: change electrolysis to fom_cost and improve code readibility
JanTautorus May 26, 2026
a2060a3
Merge branch 'wacc-in-new-supply-chain' into labour-cost-in-new-suppl…
JanTautorus May 26, 2026
2f43f02
feat: add comprehensive notebook to consolidate renewable profiles ba…
JanTautorus May 27, 2026
6b11f1b
feat: add capacity factor based clustering of cells in same region
JanTautorus May 27, 2026
cf88446
feat: finish clustering and add plotting
JanTautorus May 29, 2026
07f8a64
feat: improve preservation of distinct cf buckets when clustering
JanTautorus May 29, 2026
40df0bd
Merge pull request #43 from energyLS/labour-cost-in-new-supply-chain
energyLS Jun 1, 2026
965815d
chore: update to regional wacc in config
energyLS Jun 1, 2026
42412f2
fix: drop rows with NaN supply curve values
energyLS Jun 2, 2026
e2bae2f
fix: interpretation of supply curve as independent row values
energyLS Jun 2, 2026
53e6d09
Merge pull request #45 from energyLS/fix-supply-curve-interpretation
JanTautorus Jun 2, 2026
e90cd1a
Merge remote-tracking branch 'origin/dev' into new-renewable-profiles
JanTautorus Jun 2, 2026
381ab69
chore: rename ormuz and babalmandeb
energyLS Jun 2, 2026
193d2d1
chore: adjust arrow and legend position of unstable country case
energyLS Jun 2, 2026
6c3f781
chore: switch bloc trade entries in legend
energyLS Jun 2, 2026
36e1e4f
feat: manually adjust political stability via config
energyLS Jun 2, 2026
339702b
feat: reduce middle east stability by -0.6 points
energyLS Jun 2, 2026
180dab5
chore: adjust scenario inputs for mga plots
energyLS Jun 2, 2026
3623f3d
fix: adjust matching to get Frances iso3 code correctly
energyLS Jun 2, 2026
4271f49
chore: remove outputs from notebook
energyLS Jun 2, 2026
5f2efdb
Merge pull request #46 from energyLS:figure-improvements
JanTautorus Jun 2, 2026
467d0b9
Merge remote-tracking branch 'origin/dev' into new-renewable-profiles
JanTautorus Jun 2, 2026
13de3fe
feat: improve clustering by stratyfying
JanTautorus Jun 3, 2026
c7dba41
feat: finish clustering and clustering config
JanTautorus Jun 3, 2026
7bddd18
chore: switch PyPSA input to clusters instead of TRACE
JanTautorus Jun 3, 2026
3b034f6
feat: create rule and improve comparison between scenarios
energyLS Jun 5, 2026
6078601
fix: point to correct cluster path
JanTautorus Jun 8, 2026
11bb7a3
feat: add rule plotting lcox
energyLS Jun 9, 2026
25edf78
chore: avoid nan in addition and implement colors
energyLS Jun 9, 2026
9875c96
feat: add second region to plot
energyLS Jun 9, 2026
68337c6
feat: group regions in plot
energyLS Jun 9, 2026
dcc7712
feat: improve stratyfied clustering
JanTautorus Jun 9, 2026
380a60e
feat: allocate share of renewables to supply chain based on configura…
JanTautorus Jun 9, 2026
42b2f75
feat: streamline global supply curve rule
energyLS Jun 10, 2026
3e15a2c
chore: adjust global supply curve and lcox plotting, update notebook …
energyLS Jun 10, 2026
a6e02d2
feat: add new colors for plots
energyLS Jun 10, 2026
7cf7558
feat: figure updates on lcox
energyLS Jun 10, 2026
be1b403
chore: adjust results path for plot
energyLS Jun 10, 2026
fb73663
chore: minor notebook cleaning
energyLS Jun 10, 2026
4dab7be
fix: add scenarios to plot
energyLS Jun 10, 2026
f27ba49
feat: include new assumptions in config
energyLS Jun 10, 2026
4b61f47
chore: remove depreciated dataset
energyLS Jun 10, 2026
d5ed536
feat: revise transport methodology
energyLS Jun 10, 2026
97f59a5
feat: add notebook to analyse transport cost
energyLS Jun 10, 2026
071571b
Merge pull request #48 from energyLS/revise-transport
JanTautorus Jun 10, 2026
f37f5de
feat: add notebook to analyze lcox networks
energyLS Jun 12, 2026
de539a2
fix: make iron and steel storage cyclic
JanTautorus Jun 12, 2026
0708d28
fix: prevent battery buses from being removed
JanTautorus Jun 12, 2026
1eeb6d8
chore: change NumericFocus back to default
JanTautorus Jun 12, 2026
1ed8f85
chore: add up-to-date lock file
JanTautorus Jun 12, 2026
f904593
feat: improve comparison by including new components
energyLS Jun 12, 2026
dc3e4ed
chore: use allocated share data for comparison
energyLS Jun 12, 2026
bf6fea7
feat: adjust input and output of global supply curve rule
energyLS Jun 13, 2026
e81068b
fix: supply curve plot improvements
energyLS Jun 13, 2026
3b39555
Merge pull request #44 from energyLS/new-renewable-profiles
energyLS Jun 13, 2026
ea2e390
Merge pull request #47 from energyLS/improve-comparison
energyLS Jun 13, 2026
05801d7
feat: adjust supply curve interpretation as diff and not cumulative i…
energyLS Jun 15, 2026
c30dbdc
feat: adjust supply curve interpretation as diff and not cumulative i…
energyLS Jun 15, 2026
2261be0
feat: global supply curve: get remind steel demand and optionally plo…
energyLS Jun 15, 2026
f93544c
feat: add trade options to params for trade model
energyLS Jun 15, 2026
31a755f
feat: add remind steel demand to global supply curve worklfow
energyLS Jun 15, 2026
c5dbabe
chore: scenario updates in config and new blocs definition
energyLS Jun 15, 2026
9dc7a1f
feat: add new blocs definition suitable for config drop-in
energyLS Jun 15, 2026
c2ca4d4
chore: scenario-flexible input/output of mga plotting rule
energyLS Jun 15, 2026
331fa91
fix: adjust quotation marks for mga blocs
energyLS Jun 16, 2026
41fc6ca
feat: adjust model_trade and mga plot to 3 blocs configuration
energyLS Jun 16, 2026
d672696
feat: add iron ore cost to plot lcox
energyLS Jun 16, 2026
300faef
feat: update workflow for plotting rules
energyLS Jun 16, 2026
8f024b6
chore: visual improvements in global supply curve plot
energyLS Jun 16, 2026
9427398
chore: minor visual improvements for supply curve plots and lcox
energyLS Jun 16, 2026
24d742d
feat: improve colorblind compatability of region colors
energyLS Jun 18, 2026
350d232
feat: get global wacc and set in config
energyLS Jun 18, 2026
85a73df
feat: add first draft of supply constraint
energyLS Jun 18, 2026
e189374
Merge pull request #49 from energyLS/supply-interpretation
JanTautorus Jun 18, 2026
660b456
feat: solve supply constraint pareto style flexibliy in model trade
energyLS Jun 19, 2026
7897006
feat: add input network for plot_mga
energyLS Jun 19, 2026
0043acf
feat: update inputs for plot lcox rule
energyLS Jun 20, 2026
6dec7c2
fix: read correct input for mga and pareto plot
energyLS Jun 20, 2026
af49fb4
feat: add mga plot that visualizes simple pareto front of supplier co…
energyLS Jun 20, 2026
d201f98
feat: add sensible values for supplier constraint
energyLS Jun 20, 2026
7ed14f9
feat: make lcox function region flexible
energyLS Jun 20, 2026
3e649e9
chore: remove nb outputs
energyLS Jun 20, 2026
6e43a0b
feat: minor lcox figure updates and introduction of cases
energyLS Jun 22, 2026
3ac06b2
feat: adjust plot countries to iso3, create rule and figure updates
energyLS Jun 22, 2026
fbbc77d
chore: visual improvements in plot mga
energyLS Jun 22, 2026
2693801
chore: supply curve figure updates
energyLS Jun 30, 2026
cb9d04a
feat: add new color palette tests
energyLS Jul 1, 2026
f63235b
chore: adjust alpha in global map and curves
energyLS Jul 2, 2026
153bd0c
chore: adjust slack and add new region colors
energyLS Jul 2, 2026
37679f7
feat: add okabeito color tests
energyLS Jul 2, 2026
b453d96
feat: add rule to collect figures and diversify outputs in lcox plots
energyLS Jul 2, 2026
4ee6847
fix: readd region index name for correct application in subsequent rules
energyLS Jul 2, 2026
7cfbfce
feat: introduce nice naming of regions
energyLS Jul 2, 2026
a73a411
chore: revise color palette of regions
energyLS Jul 3, 2026
675befb
chore: adjust alpha in region colors
energyLS Jul 3, 2026
fbbcc05
feat: merge battery components into one for plotting
energyLS Jul 3, 2026
3080913
chore: adjust alpha in global plot
energyLS Jul 3, 2026
30ded3c
chore: change colors of global plot
energyLS Jul 3, 2026
51d621e
feat: create rule which collects all main figures
energyLS Jul 3, 2026
14673cb
fix: mock snakemake only when called from inside
energyLS Jul 3, 2026
77112a7
chore: limit iron ore potential to 120% of today
energyLS Jul 4, 2026
1a99088
fix: use max constraint from config for plot
energyLS Jul 4, 2026
013821f
chore: clean config file
energyLS Jul 14, 2026
875c276
chore: add chokepoint global general map to streamlined figures
energyLS Jul 15, 2026
61aba54
feat: improve suez chokepoint visibility and move all colors to config
energyLS Jul 15, 2026
bae421a
Merge pull request #50 from energyLS/figure-updates
JanTautorus Jul 15, 2026
666c1e1
feat: plot market share in pareto figures
energyLS Jul 18, 2026
759d515
Merge branch 'marketshare-plot' into dev
energyLS Jul 18, 2026
739f0b6
chore: clean config
energyLS Jul 18, 2026
d9662c8
chore: adjust package acknowedgements
energyLS Jul 18, 2026
25842f5
chore: clean and delete notebooks
energyLS Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Python 🐍 CI tests

on:
pull_request:
types: [closed]
branches: [main]
paths-ignore:
- "**.md"
- "**.bib"
- "**.ya?ml"
- "LICENSE"
- ".gitignore"
workflow_dispatch:

jobs:
test:
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
env:
SHIFT_SOLVER: highs
SHIFT_SOLVER_OPTIONS: highs-default
SHIFT_COMPUTE_IIS: "false"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]

steps:
- uses: actions/checkout@v4

- name: Install Pixi
run: python -m pip install --upgrade pip pixi

- name: Install dependencies via Pixi (test env)
run: pixi install --environment test

- name: Validate environment
run: pixi info --environment test

- name: Run tests
run: pixi run -e test unit-tests
43 changes: 43 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
exclude: "^LICENSES|^config/config\\.yaml$"

ci:
autoupdate_schedule: quarterly

repos:
# Run ruff to lint and format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.0
hooks:
# Run the linter
- id: ruff
args: [--fix]
# Run the formatter
- id: ruff-format

# Find common spelling mistakes
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
args: ['--ignore-regex="(\b[A-Z]+\b)"']
types_or: [python, rst, markdown]
files: ^(scripts|rules)/

# Format Snakemake rule files
- repo: https://github.com/snakemake/snakefmt
rev: v1.0.0
hooks:
- id: snakefmt

# Run some default pre-commit hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
args: ["--maxkb=2000"]
- id: check-merge-conflict
- id: check-yaml
exclude: "pixi.lock"
- id: end-of-file-fixer
- id: trailing-whitespace

102 changes: 67 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,111 @@
# SHIFT – Steel & Hydrogen Integrated Freight Trade

This repository contains the **SHIFT model**, a spatially resolved techno-economic optimization of global iron and steel supply chains under decarbonization. It explores how hydrogen-based direct reduced iron (DRI) production and hot-briquetted iron (HBI) trade can shift value creation to regions with renewable energy, infrastructure, and capital availability.
This repository contains the **SHIFT model**, a spatially resolved techno-economic optimization of global iron and steel supply chains under decarbonization.
It explores how hydrogen-based direct reduced iron (DRI) production and hot-briquetted iron (HBI) trade can shift value creation to regions with renewable energy and capital availability.

The model identifies cost-optimal configurations for mining, hydrogen production, DRI processing, and steel trade, using the PyPSA framework.
The model identifies cost-optimal configurations for mining, hydrogen production, DRI processing, and HBI trade, using a two-stage optimization pipeline and open energy system libraries.

---
## Introduction SHIFT

SHIFT evaluates global supply and trade of low-carbon iron and steel at high spatial resolution.
The model quantifies where to produce, where to ship, and how to meet demand cost-effectively under decarbonization constraints.

## Prerequesite: TRACE model
Key features:
- 🚀 two-stage process: greenfield supply curves + cross-region LP trade
- 🌍 spatial renewable potentials: PyPSA-Earth wind/solar CF distributions
- 💰 integrated LCOX: region-level cost curves for H2, DRI, HBI
- 🛳️ global trade dispatch: route costs, flows, nodal prices, utilization
- ⚙️ configurable automation: regions, technologies, scenarios via YAML + Snakemake rules

The SHIFT model integrates the energy supply chain `shipping-steel` from a [fork](https://github.com/fneum/trace/tree/pypsa-eur-sec-imports-atlite) of the [TRACE model](https://github.com/euronion/trace).
## Quick installation (PIXI)

Therefore, clone the TRACE fork with `git`:
Clone the repository:

```sh
git clone https://github.com/fneum/trace.git
git clone https://github.com/energyLS/shift.git
cd shift
```

and switch to the branch `pypsa-eur-sec-imports-atlite` (commit [8bf0571](https://github.com/fneum/trace/commit/8bf057142d4e035926ffb084493462eff64fe188)) and follow these steps:
- delete `escs/shipping-steel/loads.csv`,
- delete `escs/shipping-steel/ships.csv`,
- in `data/efficiencies.csv` and `escs/shipping-steel/links.csv`, and `escs/shipping-hbi/links.csv`, add replace `direct iron reduction furnace` with `hydrogen direct iron reduction furnace` to match the latest technology-data version
- set `technology_data: "v0.12.0"` in the `config/config.default.yaml` (same as in SHIFT: `config/config.yaml`),
- run `snakemake -c1 resources/networks/default/2030/shipping-steel/DE-DE/network.nc`,
- run `snakemake -c1 resources/networks/default/2050/shipping-steel/DE-DE/network.nc`.

This creates a steel supply chain for 2030 and 2050 without loads and shipping, those parameters will be added later in the SHIFT workflow. The resulting steel model will be stored in `resources/networks/default/2050/shipping-steel/DE-DE/network.nc` and automatically fetched by the SHIFT model.

Install dependencies with pixi:

## Download, Install, and Run the SHIFT model
```sh
pixi install
```

Clone the repository with `git`:
Activate the environment:

```sh
git clone https://github.com/energyLS/shift.git
pixi shell
```

Create the environment with `conda`:
(Optional) Install pre-commit hooks:

```sh
conda env create -f environment.yaml
pre-commit install
```

Navigate to the `workflow/notebooks` and run the notebooks `global-iron-ore.ipynb`, `global-steel-production.iypnb`, `prepare-iron-ore.ipynb`, and `prepare-steel.ipynb` for preparation. Those steps will be included in the main workflow in a future version.

Run the trade model by navigating to the `workflow/` folder via `cd workflow` and then run
For details, see https://pixi.prefix.dev/latest/ (or your local PIXI docs).

## Run (core workflow)

In the workspace root:

```sh
snakemake -call model_trade_all
pixi run snakemake model_trade_all
```

To plot the supply curves subtracted with demand, run
To collect all figures (under development):

```sh
snakemake -c1 create_all_supply_curves_with_demand
pixi run snakemake collect_figures
```


*Under development:*
## Workflow overview

Run the whole workflow using `snakemake`:
### Configuration & Scenario Setup (implicit)

```sh
snakemake -call collect_figures
```
Before execution, Snakemake reads:
- **Global settings**: `config/config.yaml` (regions, cost years, solver options, enable flags)
- **Scenario matrix**: `config/trade_scenarios.csv` (rows = distinct trade scenarios)

These expand into a deterministic wildcard space (cost_year, region, product, scenario) that drives all downstream rule creation. This bootstrap is handled automatically by Snakemake; no user action required.

## Licence
### Step 0: Renewable potentials (pre-computed inputs)

This repository is licensed under the MIT License. See `LICENCE` for details.
In this stage we generate the supply-side resource backbone.
Renewable capacity-factor series and maximum deployable potentials are pre-computed externally using PyPSA-Earth's `build_renewable_profiles` rule and stored in `data/renewable_profiles/`.
This stage is not part of the current Snakefile. SHIFT consumes pre-computed .nc datasets to avoid the long runtime of full GIS processing.

> **For new users:** No action needed. Renewable data files are provided in the repository.

### Step 1: Greenfield supply curve generation (PyPSA)

With renewable profiles and [techno-economic assumptions](https://github.com/PyPSA/technology-data) in place, SHIFT builds regional PyPSA optimization models to size generation, storage, and process assets.
It evaluates each candidate plant (H2 electrolyser, DRI furnace, HBI plant, steel mills) across resource quality and cost parameters to produce levelized cost curves (LCOX) as a function of capacity.
The result is a fleet of supply curve elements (capacity buckets with marginal costs and metadata) for H2, DRI, HBI, and steel by region.

Step 1 is a multi-part stage: load techno-economic data and build regional cost baselines, prepare renewable candidate sets per region, solve optimization problems at discrete demand levels, and consolidate results into piecewise supply curves. Each stage depends on the prior; files are persisted between steps to support reproducibility and debugging.
The output is a harmonized set of supply curves used as input for the trade stage.

### Step 2: Global trade optimization (LP)

This stage takes regional supply curves and demand obligations, then runs a linear program over the regional network.
It includes transport cost matrices, ore production constraints, and market compatibility.
The solver decides how much each region should produce versus import/export, by product and route.

The trade solution yields detailed outputs: regional production volume and shipped quantities.
It can also be reconciled with scenarios for demand, policy constraints, and infrastructure availability.


## Acknowledgements

Thanks to:
- Oda Agdal and her Master's Thesis on the [Investigation of Future Global Trade of Hydrogen from Renewable Energy Sources](https://ntnuopen.ntnu.no/ntnu-xmlui/handle/11250/3031513)
- Johannes Hampp and [TRACE](https://github.com/euronion/trace)

* Oda Agdal and her Master's Thesis on the [Investigation of Future Global Trade of Hydrogen from Renewable Energy Sources](https://ntnuopen.ntnu.no/ntnu-xmlui/handle/11250/3031513).

## Licence

This repository is licensed under the MIT License. See `LICENCE` for details.
94 changes: 94 additions & 0 deletions Snakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Root Snakemake entrypoint for the Shift workflow.

Loads shared configuration and includes the modular rule files for supply curves,
trade optimization, and reporting.
"""

from pathlib import Path
from shutil import copyfile
import sys

import pandas as pd
from snakemake.utils import Paramspace


WORKFLOW_DIR = Path(workflow.basedir) / "workflow"
SCRIPT_DIR = WORKFLOW_DIR / "scripts"
NOTEBOOKS_DIR = WORKFLOW_DIR / "notebooks"
# DATA_

if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
if str(NOTEBOOKS_DIR) not in sys.path:
sys.path.insert(0, str(NOTEBOOKS_DIR))

from trade_chain_utils import ( # noqa: E402
derive_supply_curve_products,
get_ordered_stages,
get_stage_groups,
get_trade_chain,
)


configfile: "config/config.yaml"


def _load_trade_scenarios():
trade_chains = config.get("trade_chains")
if trade_chains:
rows = []
chain = get_trade_chain(config)
stages_sorted = get_ordered_stages(chain)
if len(stages_sorted) < 2:
raise ValueError(
f"Trade chain '{chain.get('id', '<unnamed>')}' needs at least 2 stages"
)
stage_groups = get_stage_groups(chain)
if not stage_groups:
raise ValueError(
f"Trade chain '{chain.get('id', '<unnamed>')}' produced no stage groups"
)
scenarios = chain.get("trade_scenarios", "default")
if isinstance(scenarios, str):
scenarios = [scenarios]
for scenario in scenarios:
rows.append(
{
"chain_id": str(chain.get("id", "default")),
"cost_year": str(chain.get("cost_year", 2050)),
"interone": str(stage_groups[0]["label"]),
"intertwo": str(
stages_sorted[-1].get(
"process_label", stages_sorted[-1]["output_commodity"]
)
),
"wacc": str(chain.get("wacc", "regional")),
"final": str(chain.get("final_product", "steel")),
"scenario": str(scenario),
}
)
return Paramspace(pd.DataFrame(rows, dtype=str))

return Paramspace(pd.read_csv("config/trade_scenarios.csv", dtype=str))


trade_scenarios = _load_trade_scenarios()


def _derive_supply_curve_products():
return derive_supply_curve_products(config)


SUPPLY_CURVE_PRODUCTS = _derive_supply_curve_products()


wildcard_constraints:
country="[a-zA-Z]+",
sweep="[a-zA-Z]+",
rule="(0|[1-9][0-9]?|100)",


include: "rules/supply_curves.smk"
include: "rules/preparation.smk"
include: "rules/trade_model.smk"
include: "rules/reporting.smk"
Loading
Loading