Skip to content
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# SHIFT – Steel & Hydrogen Integrated Freight Trade

[![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
and steel supply chains under decarbonization. It explores how
hydrogen-based direct reduced iron (DRI) production and hot-briquetted iron
Expand All @@ -10,6 +13,8 @@ orchestrated with [Snakemake](https://snakemake.readthedocs.io/).

## Quick start – installation & execution

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
cd shift
Expand All @@ -22,6 +27,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
Expand Down
20 changes: 18 additions & 2 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,9 @@ 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 # 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:
Expand All @@ -270,6 +271,21 @@ 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.
# solver left as "choose" so HiGHS can pick simplex over IPM where cheaper.
threads: 4
solver: "choose"
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
Expand Down
8 changes: 4 additions & 4 deletions rules/retrieve.smk
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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:
Expand All @@ -27,4 +27,4 @@ rule retrieve_data:
params:
folder=".",
run:
unpack_archive(input.data_url, params.folder)
unpack_archive(input.data_url, params.folder)
3 changes: 2 additions & 1 deletion workflow/scripts/calculate_lcox.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, {})

Expand Down
Loading