REAP is a decision-analytic framework for robust and resilient energy planning under uncertainty. It pairs a capacity expansion model (PREP-SHOT) with a scenario-design layer (factorial + Latin-Hypercube Sampling, LHS) to quantify how candidate plans perform across thousands of plausible futures.
A typical REAP study has three stages, covered by this repository:
- Design the scenarios (factorial + LHS over uncertain drivers).
- Generate one input set per scenario.
- Solve each scenario with PREP-SHOT.
Downstream aggregation of the netCDF results into robustness metrics is left to the analyst — REAP is agnostic to the post-processing toolchain.
This repository contains the PREP-SHOT capacity expansion model, the scenario-generation pipeline, and runners for single-scenario and MPI-parallel batch execution.
This repository accompanies the manuscript:
Shuyue Yan, Zhanwei Liu, and Xiaogang He. Robust pathways to net-zero power sectors in resource-constrained cities under deep uncertainty (Under Review). Department of Civil and Environmental Engineering, National University of Singapore.
REAP targets Python 3.9+. Install via conda using the environment file:
conda env create -f environment.yml
conda activate prep-shotThe default solver is Gurobi (a license is
required; free academic licenses are available). To use a different solver,
edit config.json and set solver_parameters.solver to any Pyomo-
compatible backend (highs, cbc, …) and install it separately.
For MPI batches, also install mpi4py (pip install mpi4py) and an MPI
runtime such as Open MPI.
Tested environment. The released version has been tested on Linux
(Ubuntu 22.04 LTS) with Python 3.9.23, Pyomo 6.4.4, PyOptInterface 0.2.5, and
Gurobi 10.0.2. Exact versions of all dependencies are pinned in
environment.yml.
Hardware. No non-standard hardware is required. The figures below were measured on a workstation with an Intel Xeon w9-3495X (56 cores / 112 threads) and 503 GB of RAM; Gurobi parallelises across available cores, so run times on a typical desktop will be longer. A single-scenario run at the default 8,760-hour resolution peaks at about 5.3 GB of resident memory, so 8 GB of RAM is sufficient. MPI batch runs scale with the number of ranks.
Installation time. Creating the conda environment takes approximately 3 minutes (measured: 173 s) with a warm conda package cache. A first-time installation on a clean machine is slower, since all packages must be downloaded.
Demo runtime. The example single-scenario run described in
Quick start takes approximately 4.5 minutes end to end
(measured: 4 min 31 s), of which about 3.4 minutes is spent in Gurobi; the
remainder is spent reading the Excel inputs, building the Pyomo model, and
writing output/year.nc.
prepshot/ Model package (data loading, model, solver, rules)
data/ Source data (templates, sample input, scenario design)
├── default_parameters/ Parameter Excel files copied verbatim into every scenario
├── full_factorial_parameters/ Pre-baked variants picked by factorial level (e.g. demand_0.028.xlsx)
├── lhs_parameters/ Templates whose cells get filled with each scenario's LHS sample
├── full_factorial_template_prep_shot.csv Factorial-level definitions
├── exp_design_FF_LHS_template_prep_shot_20251024.csv Per-variable LHS bounds + flags
└── experimental_design.csv Generated design table — one row per scenario
config.json Solver + general-parameter configuration
params.json Mapping from internal names to Excel input files
environment.yml Conda environment specification
generate_scenarios.R Step 1 — builds the factorial × LHS design table
generate_inputs.py Step 2 — builds per-scenario input folders from templates
run.py Step 3 — single-scenario solver
run_batch.py Step 3 — MPI batch solver
# 1. Activate environment
conda env create -f environment.yml
conda activate prep-shot
# 2. Generate the per-scenario input folders under generated_inputs/
Rscript generate_scenarios.R # writes data/experimental_design.csv (needs install.packages("lhs"))
python generate_inputs.py # writes generated_inputs/input_s1_…/, etc.
# 3. Solve one scenario
python run.py
# → results land in output/year.ncrun.py defaults to solving
generated_inputs/input_s1_diversified_0.028/. Override with -i <path>
to solve a different scenario, or set input_folder in config.json. For
multi-scenario sweeps see Workflow.
Step 1 ─ Design scenarios
─────────────────────────────────────────────────
data/full_factorial_template_prep_shot.csv
data/exp_design_FF_LHS_template_prep_shot_*.csv
│
▼
generate_scenarios.R
│
▼
data/experimental_design.csv
Step 2 ─ Generate inputs
─────────────────────────────────────────────────
data/experimental_design.csv
data/default_parameters/
data/full_factorial_parameters/
data/lhs_parameters/
│
▼
generate_inputs.py
│
▼
generated_inputs/input_s1_…/
generated_inputs/input_s2_…/
⋮
Step 3 ─ Solve
─────────────────────────────────────────────────
│
▼
run.py / run_batch.py
│
▼
output/year.nc / output_batch/output_*/year.nc
REAP scenarios are produced from a factorial design (discrete settings such as technology portfolios) crossed with a Latin-Hypercube sample of continuous uncertainties (fuel prices, carbon limits, reserve margins, …).
The design table is generated with generate_scenarios.R. Two template
files parameterise it:
full_factorial_template_prep_shot.csv— discrete factorial levels (e.g.outlook∈ {diversified, hydrogen, import_with_australia, import_without_australia},demandgrowth rate, …).exp_design_FF_LHS_template_prep_shot_20251024.csv— for each remaining variable, its default, its LHS lower/upper bounds, and whether it varies in the factorial or LHS dimension.
The script requires R and the lhs package (install.packages("lhs") or
conda install -c conda-forge r-lhs). The constants at the top of
generate_scenarios.R default to reading templates from data/; edit them
only if your templates live elsewhere or you want a different LHS size:
exp_dir <- "data"
design_info_file <- file.path(exp_dir, "exp_design_FF_LHS_template_prep_shot_20251024.csv")
export_name <- "experimental_design.csv"
n_points <- 1000 # LHS sample size; total scenarios = factorial × n_pointsRun from the repo root:
Rscript generate_scenarios.RThis produces data/experimental_design.csv (factorial × LHS). A pre-built
example with 1,000 LHS points × the factorial grid (12,000 rows) is already
checked in if you want to skip this step.
For every row of the design table, generate_inputs.py composes a
per-scenario input folder under generated_inputs/ by combining three
sources:
data/default_parameters/— copied verbatim into every scenariodata/full_factorial_parameters/— one variant picked per factorial level (e.g.demand_0.028.xlsx→demand.xlsx)data/lhs_parameters/— templates whose target cells are overwritten with the scenario's LHS sample values
python generate_inputs.py
# → generated_inputs/input_s0_diversified_0.028/
# generated_inputs/input_s1_diversified_0.028/
# ...Each folder contains one complete PREP-SHOT input set (one Excel per parameter).
run.py solves a single scenario folder and writes output/year.nc. The
default input folder is set in config.json (general_parameters.input_folder,
shipped as generated_inputs/input_s1_diversified_0.028); override
per-invocation with -i <path>. Other CLI flags map onto parameter file
suffixes — run python run.py --help for the full list.
run_batch.py iterates over generated_inputs/ and shards scenarios across
MPI ranks. Each rank r of N solves scenarios where i % N == r,
skipping any whose year.nc is already on disk — so the batch is safely
resumable after a crash.
mpirun -n 4 python run_batch.pyPer-rank progress is written to log/rank_<NNN>.log.
PREP-SHOT and the broader REAP modelling effort build on the following work:
-
Liu, Z. & He, X. Balancing-oriented hydropower operation makes the clean energy transition more affordable and simultaneously boosts water security. Nature Water 1, 778–789 (2023). doi:10.1038/s44221-023-00126-0
-
Xu, B., Liu, Z., Yan, S., Schmitt, R. J. P. & He, X. Strategizing renewable energy transitions to preserve sediment transport integrity. Nature Sustainability (2025). doi:10.1038/s41893-025-01626-5
-
Xie, J., Liu, Z., Yan, S., Ziegler, A. D., Shi, X., Xu, B., Srinuansom, K., Peng, X., Yoshimura, K. & He, X. Variable renewable energy pathways in the Lower Mekong Basin under projected river flow extremes. Communications Earth & Environment 6, 928 (2025). doi:10.1038/s43247-025-02861-6
-
Liu, Z. & He, X. A renewable tango for drought-stricken power grids. Nature Water 4, 545–547 (2026). doi:10.1038/s44221-026-00625-w
See LICENSE.