Resource adequacy (COPPER-PRAS)¶
The COPPER-PRAS linkage takes a capacity plan produced by a Capacity Expansion Model (CEM), in M3's case COPPER, and asks whether that plan would actually keep the lights on: hour by hour, across many random draws of generator and transmission outages, with limited-energy resources such as storage and reservoir hydro tracked explicitly.
The adequacy engine is PRAS, NREL's Probabilistic Resource Adequacy Suite, written in Julia. PRAS runs a sequential Monte Carlo simulation and reports reliability metrics, chiefly:
- LOLE, loss of load expectation (event-hours per year), and
- EUE, expected unserved energy (MWh per year),
for the system and for each region, together with the hourly shortfall, interface utilisation and storage state-of-charge traces behind them.
Between COPPER and PRAS sits pras-linkage, a preprocessing and orchestration layer that builds the PRAS system model. It is usable on its own, and the M3 runner drives it.
End-to-end flow¶
scenarios/<scenario>/config.toml models_to_run = ["COPPER", "PRAS"]
|
v
linkage.py -> COPPER stage capacity, generation, demand, new
| transmission for the target year
v
scripts/pras_runner.py reads [Models.PRAS] from config.toml,
| writes pras-linkage's config.yaml
v
pras-linkage/main.py (mode: cem)
+--> CODERS API : nodes, existing transmission topology, fleet,
| hydro and VRE capacity factors (the "backbone")
+--> COPPER CSVs : *_output_summary.csv (+ *_input_summary_IDEA.csv)
| capacity by type and region, demand, hydro CFs,
| storage efficiency, new transmission
+--> merge, assign generators to nodes, scale nodal demand
+--> build hourly capacity, outage and repair probabilities
+--> optional weather multipliers, optional provincial aggregation
+--> write PRAS text groups and one <scenario>.pras HDF5 file
|
v
PRAS_analysis.jl (Julia) sequential Monte Carlo
|
v
<scenario>_1/pras/pras-output/ global_metrics.txt (LOLE, EUE),
hourly_outages.csv, ...
One-way and non-iterative: nothing flows back from PRAS into COPPER. The adequacy result is a check on a plan, not a constraint on it.
What comes from where¶
| Element of the PRAS system | Source in CEM mode |
|---|---|
| Regions (nodes or provinces), transmission lines and interfaces | CODERS backbone; COPPER's new transmission added by new_transmission_mode (distribute across existing corridors, or new_line) |
| Thermal, nuclear, VRE and run-of-river hydro generators | COPPER capacity by type and region for the target year, placed on CODERS nodes; hourly VRE availability from CODERS/MERRA capacity factors (merra_year) |
Reservoir hydro (hydro_daily, hydro_monthly) |
Modelled as PRAS GeneratorStorage: inflow = capacity factor × nameplate, energy capacity = inflow × hours in the scheduling period |
| Battery and other storage | COPPER storage capacity with round-trip efficiency from COPPER inputs |
| Demand | COPPER demand for demand_year, distributed to nodes by CODERS load shares (Alberta uses zonal AESO shapes) |
| Outage and repair probabilities | pras-linkage constants by generator type, optionally scaled by weather multipliers |
The mechanics of each step, and the full list of PRAS groups written, are in the
pras-linkage README on its dev branch.
Two ways to run it¶
- Through M3-linkages (this documentation): set
models_to_run = ["COPPER", "PRAS"]in a scenario'sconfig.toml, runpython linkage.py -sc <scenario>, and the runner executes COPPER and then PRAS, keeping all outputs in the scenario's iteration folder. See the Quick-start. - pras-linkage standalone: point a
config.yamlat any existing COPPER results folder (mode: cem,cem_path: ...) or skip COPPER entirely and assess the current fleet from CODERS alone (mode: coders). This is also the only route to the EFC and ELCC capacity-credit analyses and the US-BC intertie option.
Repositories and versions¶
| Component | Repository | Branch | Notes |
|---|---|---|---|
| Linkage runner | https://gitlab.com/sesit/M3-linkages | PRAS |
Adds COPPER-PRAS to the orchestrator, scripts/pras_runner.py and the SLURM wrapper scripts/pras_runner.sh. Not yet merged to main as of 2026-09-22. |
| pras-linkage | https://gitlab.com/sesit/pras-linkage | dev |
Preprocessor, Julia analysis scripts, weather-multiplier configurations, shortfall dashboard. The M3 installer (cli.py) clones main; check out dev for the documented behaviour. The Electricity Canada scenarios are on building_grid_resilience, branched from dev. |
| COPPER | https://gitlab.com/sesit/copper | lmp_testing_clean |
Branch used for the Electricity Canada analysis (pinned, with its scenarios, on building_grid_resilience). The installer default is dev; any branch that writes *_output_summary.csv works. |
| PRAS | https://github.com/NREL/PRAS | Julia package | Installed into the Julia depot with PRASCapacityCredits for EFC/ELCC. |
| CODERS | https://coders.cme-emh.ca/ | API | An API key is required in CEM and CODERS modes. |
Constraints to know about¶
- PRAS is COPPER-only in the M3 runner.
models_to_runmay not combinePRASwithCIMSorSILVER; to assess a CIMS-COPPER scenario, run it first, then run PRAS against its COPPER outputs (the--skipflag reuses existing COPPER results). - PRAS evaluates one target year (
year, default 2050), so the COPPER run must cover it. - The runner writes pras-linkage's scenario as
scenarios/pras/config.yamlinside the pras-linkage repository on every call, so concurrent runs on one checkout will overwrite each other's configuration. - The CODERS backbone defines the node set. Provinces requested in
[CODERS].regions(or[Models.PRAS.Config].provinces) are mapped to pras-linkage's two-letter codes automatically.
Documentation¶
- Setup guide: repositories, environments, Julia packages, the
[Models.PRAS]configuration block. - Quick-start: a first COPPER-PRAS run, reading the outputs, re-running PRAS alone, weather multipliers, EFC, SLURM.
This page was written from the code on the branches listed above on 2026-09-22. Where it disagrees with the code, the code wins; please fix the page.