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

  1. Through M3-linkages (this documentation): set models_to_run = ["COPPER", "PRAS"] in a scenario's config.toml, run python 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.
  2. pras-linkage standalone: point a config.yaml at 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_run may not combine PRAS with CIMS or SILVER; to assess a CIMS-COPPER scenario, run it first, then run PRAS against its COPPER outputs (the --skip flag 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.yaml inside 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.