From 8e9eef7ff148aa833e080e62d0df613bdcd89a4c Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 16:35:58 +0200 Subject: [PATCH 1/7] docs: add MIT license and Zenodo DOI badges to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b2f5c31..ce3f1cf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # SHIFT – Steel & Hydrogen Integrated Freight Trade +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENCE) +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21875103.svg)](https://doi.org/10.5281/zenodo.21875103) + **SHIFT** is 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 From ea1333e94e18aaac0ec7e35638dbe59cbc02873f Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 16:39:07 +0200 Subject: [PATCH 2/7] docs: note Python/pixi requirement in quick start --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ce3f1cf..caf9b5c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ orchestrated with [Snakemake](https://snakemake.readthedocs.io/). ## Quick start – installation & execution +SHIFT is written in Python and uses [pixi](https://pixi.sh/latest/installation/) to manage the environment. Install pixi before you continue. + ```sh git clone https://github.com/energyLS/shift.git cd shift From 18058f834ee6a934ce6a618a3c435767e075e390 Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 16:40:53 +0200 Subject: [PATCH 3/7] docs: state Python 3.10+ requirement in quick start --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index caf9b5c..390929a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ orchestrated with [Snakemake](https://snakemake.readthedocs.io/). ## Quick start – installation & execution -SHIFT is written in Python and uses [pixi](https://pixi.sh/latest/installation/) to manage the environment. Install pixi before you continue. +SHIFT requires Python 3.10+ and uses [pixi](https://pixi.sh/latest/installation/) to manage the environment. Install pixi before you continue. ```sh git clone https://github.com/energyLS/shift.git From 253fbcbedc51acdbf56dc0133e979e26199ef018 Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 16:55:53 +0200 Subject: [PATCH 4/7] fix: default to license-free HiGHS solver, fix missing trade_opt.csv retrieval output --- README.md | 4 ++++ config/config.yaml | 4 ++-- rules/retrieve.smk | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b2f5c31..cd30439 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Approximate runtimes: - Installation (`pixi install`): ~5 minutes - Full model (`model_trade_all`): ~5 hours +By default, the model solves with [HiGHS](https://highs.dev/), a license-free +solver. If you have a [Gurobi](https://www.gurobi.com/) license, set +`solver.name: gurobi` in `config/config.yaml` for faster solves. + > [!TIP] > For a quick, low-resolution run, check out the > [`demo` branch](https://github.com/energyLS/shift/tree/demo), which uses diff --git a/config/config.yaml b/config/config.yaml index c42c3ef..3609a2e 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -254,8 +254,8 @@ plot: bus_size: 2.0e-7 link_width: 3.0e-8 solver: - name: gurobi - options: gurobi-default + name: highs # license-free by default; set to "gurobi" (with a valid license) for faster solves + options: highs-default compute_iis: False # Set to false to skip expensive IIS computation for infeasible models solver_options: highs-default: diff --git a/rules/retrieve.smk b/rules/retrieve.smk index 5d44969..47ca33f 100644 --- a/rules/retrieve.smk +++ b/rules/retrieve.smk @@ -3,11 +3,10 @@ storage: keep_local=True, retries=3, + rule retrieve_data: input: - data_url=storage( - f"https://zenodo.org/records/21875103/files/shift_data.zip" - ), + data_url=storage(f"https://zenodo.org/records/21875103/files/shift_data.zip"), output: bus_locations="data/bus_locations.csv", ip_market_fabrication="data/demand/ip_market__fabrication.csv", @@ -17,6 +16,7 @@ rule retrieve_data: unido_raw="data/labour/unido-raw/data.csv", iron_ore_production="data/owid-iron-ore/iron-ore-crude-ore-production.csv", political_stability="data/political-stability/globaleconomy.csv", + trade_opt="data/trade_opt.csv", renewable_profiles_geojson="data/renewable_profiles_global_merged.geojson", renewable_profiles_nc="data/renewable_profiles_global_merged.nc", log: @@ -27,4 +27,4 @@ rule retrieve_data: params: folder=".", run: - unpack_archive(input.data_url, params.folder) \ No newline at end of file + unpack_archive(input.data_url, params.folder) From b242a084d40b446adecf10bfbbe7e2704b02c846 Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 19:01:25 +0200 Subject: [PATCH 5/7] docs: point license badge to opensource.org/licenses/MIT --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b97d301..75d307b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SHIFT – Steel & Hydrogen Integrated Freight Trade -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENCE) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21875103.svg)](https://doi.org/10.5281/zenodo.21875103) **SHIFT** is a spatially resolved techno-economic optimization of global iron From d5f884118142fb7cc6dbe4b41fcc260be7a4bf0c Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 19:21:01 +0200 Subject: [PATCH 6/7] perf: skip crossover for LCOX solves, keep it for the trade LP duals --- config/config.yaml | 17 ++++++++++++++++- workflow/scripts/calculate_lcox.py | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 3609a2e..dadceba 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -255,7 +255,8 @@ plot: link_width: 3.0e-8 solver: name: highs # license-free by default; set to "gurobi" (with a valid license) for faster solves - options: highs-default + options: highs-default # used for the trade LP, where crossover-derived duals (nodal prices) matter + options_lcox: highs-lcox # used for regional LCOX/supply-curve solves, which only consume the primal solution compute_iis: False # Set to false to skip expensive IIS computation for infeasible models solver_options: highs-default: @@ -270,6 +271,20 @@ solver_options: ipm_optimality_tolerance: 1e-6 parallel: "on" random_seed: 123 + highs-lcox: + # No crossover: calculate_lcox.py only reads network.objective and the + # primal capacity mix, never duals, so a basic (vertex) solution is not + # required and skipping crossover saves the simplex clean-up pass. + threads: 4 + solver: "ipm" + run_crossover: "off" + small_matrix_value: 1e-6 + large_matrix_value: 1e15 + primal_feasibility_tolerance: 1e-6 + dual_feasibility_tolerance: 1e-6 + ipm_optimality_tolerance: 1e-5 + parallel: "on" + random_seed: 123 gurobi-default: threads: 4 method: 2 # barrier diff --git a/workflow/scripts/calculate_lcox.py b/workflow/scripts/calculate_lcox.py index c3832b0..a7397ad 100644 --- a/workflow/scripts/calculate_lcox.py +++ b/workflow/scripts/calculate_lcox.py @@ -365,7 +365,8 @@ def solve_network(network, config): solver_cfg = config.get("solver", {}) solver_name = os.getenv("SHIFT_SOLVER", solver_cfg.get("name", "glpk")) solver_options_key = os.getenv( - "SHIFT_SOLVER_OPTIONS", solver_cfg.get("options", "default") + "SHIFT_SOLVER_OPTIONS", + solver_cfg.get("options_lcox", solver_cfg.get("options", "default")), ) solver_options = config.get("solver_options", {}).get(solver_options_key, {}) From 050c62ab9e2f41d3ec879104dd1281bd6cf27982 Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Mon, 31 Aug 2026 19:37:41 +0200 Subject: [PATCH 7/7] perf: let HiGHS choose the algorithm for LCOX solves instead of forcing IPM --- config/config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index dadceba..fbb5c72 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -275,8 +275,9 @@ solver_options: # No crossover: calculate_lcox.py only reads network.objective and the # primal capacity mix, never duals, so a basic (vertex) solution is not # required and skipping crossover saves the simplex clean-up pass. + # solver left as "choose" so HiGHS can pick simplex over IPM where cheaper. threads: 4 - solver: "ipm" + solver: "choose" run_crossover: "off" small_matrix_value: 1e-6 large_matrix_value: 1e15