Benchmarks overview¶
The benchmark layer collects the paper-facing experiments in PowerZooJax. The envs, wrappers, tasks, trainers, and reporting scripts are all organized around this layer.
This page is a top-level map: the five tasks, the shared workflow, the result schema, and the backend/device comparison contract. For benchmark workflow terms such as campaign, NormScore, IQM, primary split, primary metric, convergence target, or leaderboard quantity, see the Benchmark workflow glossary.
First-time users¶
If you are new to PowerZooJax, the easiest starting point is usually DSO: it is single-agent, physically interpretable, and has a short run.py workflow. A minimal first run is:
python benchmarks/dso/run.py baseline --seeds 0
python benchmarks/dso/run.py train --algo ppo --seed 0
python benchmarks/dso/run.py eval --run-id <run_id> --split iid
python benchmarks/dso/run.py summarize
After that first pass, inspect benchmarks/dso/results/summary/latest.json first. For a beginner, the simplest success signal is: the pipeline finishes end-to-end, writes a run record plus summary, and reports physically sensible DSO metrics such as total_loss_mwh, voltage_violation, and NormScore.
If you want a more targeted entry point, use this shortcut:
| If you want to start with... | Read first |
|---|---|
| single-agent distribution control | DSO |
| safe RL with explicit CMDP language | TSO |
| cooperative MARL on the grid | DERs |
| competitive MARL / market bidding | GenCos |
| multi-objective microgrid control | DC Microgrid |
The five tasks¶
| Task | Pillar | Case | Agents | Steps | RL paradigm |
|---|---|---|---|---|---|
| TSO | Security dispatch | case118 |
1 | 48 x 30 min | safe RL on SCUC |
| DSO | Intertemporal DER control | case33bw |
1 | 48 x 30 min | single-agent demand response |
| DERs | Intertemporal DER control | case141 |
12 | 48 x 30 min | cooperative MARL |
| DC Microgrid | Intertemporal DER control | self-contained | 1 | 288 x 5 min | multi-objective robust RL |
| GenCos | Market Lite | case5 |
5 | 48 x 30 min | competitive MARL |
Current evidence snapshot as of 2026-04-25:
- TSO has complete 5-seed evidence, but the strict zero-violation safety gate is negative.
- DSO has complete 5-seed evidence; the official eval split is IID only.
- DERs uses
case141; Phase 1 has complete 5-seed evidence and the mandatory seed-0 backend/device matrix is complete. - GenCos Phase-2 Python rows use frozen self-play IL, not random-opponent baselines.
- DC Microgrid has complete Phase-2 backend evidence and execution-scaling artifacts; strict exact-zero feasibility has a numerical-tail caveat.
Shared terms used across the task pages:
OOD split: an out-of-distribution evaluation setting whose data distribution differs from training.reward shaping: the underlying physics stay unchanged, but the training reward adds fixed penalties or bonuses.CMDP: a constrained Markov decision process, where reward and cost are reported through separate channels.NormScore: a diagnostic task-normalized score anchored to frozen non-learning baselines. Primary tables rank by each task's raw primary metric unlessnorm_score_status=ok.
The five tasks are intentionally heterogeneous. They are not meant to reward one universal algorithm; they are meant to stress different combinations of physics, uncertainty, temporal coupling, and agent interaction under one reporting contract.
What Is Actually Trained¶
This table removes one common source of confusion: the physical env, the benchmark task, and the formal training path are related, but they are not the same layer.
| Task | Agent setting | Benchmark task type | Current formal training path | Primary leaderboard quantity | Main safety / audit gate |
|---|---|---|---|---|---|
| TSO | single-agent | MDP / CMDP SCUC dispatch | PPO or PPO-Lagrangian | total_operating_cost |
zero thermal overload and zero reserve shortfall |
| DSO | single-agent | demand-response MDP / CMDP | PPO, SAC, Sauté PPO, or PPO-Lagrangian | total_loss_mwh for interpretation; current convergence target is total_reward |
zero voltage-violation rate |
| DERs | 12-agent MARL | cooperative constrained task | reward-shaped IPPO / IPPO-safe / IPPO-Lagrangian | mean_p_loss_mw |
zero voltage-violation target |
| DC Microgrid | single-agent | multi-objective constrained task | reward-shaped PPO / SAC | episode_reward |
SLA / temperature / deficit channels are audited |
| GenCos | 5-agent MARL | competitive Markov game | IPPO | total_profit |
market-concentration audit via market_HHI |
One naming detail is easy to miss: NormScore is the benchmark concept, while norm_score is often the serialized metric key written into result records.
flowchart LR
SD["Security Dispatch"] --> TSO
DERC["Intertemporal DER Control"] --> DSO
DERC --> DERS["DERs"]
DERC --> DCM["DC Microgrid"]
MKT["Market Lite"] --> GC["GenCos"]
Benchmark workflow¶
Each task page follows the same reader-facing structure:
- task definition and frozen setup
- baselines
- training algorithms
- eval splits
- metrics
- quick-start commands
- output artifacts
If a task depends on real data, formal benchmark runs must fail rather than silently fall back to synthetic data. Development presets may still exist for local checks, but they are not benchmark records.
The formal workflow has two phases:
- Phase 1: rerun the canonical
jax_rejax + GPUbenchmark path from scratch for the current campaign. Theseed=0chain must pass the initial readiness checks before multi-seed runs are treated as formal. - Phase 2: run the backend/device comparison matrix on the same frozen task setup. The exact cells are task-specific; the current paper-facing matrices use
jax_rejax + gpu/jax_rejax + cpuplus Python backend rows such assb3 + cuda,sb3 + cpuwhere configured, andsbx + cudawhere a formal SBX row is part of the task matrix.
Unified result schema¶
Every baseline, train, and eval command writes a result record with at least:
- task
- algorithm
- backend / device
- seed
- split
- scalar metrics
- artifact paths
Because the schema is shared across all five tasks, summary tables and plots can be regenerated from the task manifests without task-specific parsing logic.
Cross-task statistics¶
Cross-seed summaries use robust statistics such as IQM (interquartile mean) and task-normalized NormScore.
The exact normalization anchor differs by task:
- TSO and DSO normalize against physically meaningful non-learning dispatch / control baselines.
- DERs normalizes against
no_controland the strongervolt_drooprule. - DC Microgrid currently normalizes on
episode_reward, because the frozen convergence target is also reward-based. - GenCos normalizes market performance on
total_profitagainst frozen bidding baselines.
This keeps each task physically interpretable while still supporting one cross-task summary figure.
Hardware contract¶
The hardware contract freezes the assumptions behind throughput comparisons:
- 1 x NVIDIA RTX 4500 Ada (24 GB) GPU on a single workstation (AMD Ryzen Threadripper PRO 7985WX, 64 cores, 256 GB RAM); the same workstation runs all paper-facing experiments
- one GPU per training or eval run
- within a task, seeds run in parallel; algorithms run serially; tasks run serially
num_envshas two distinct meanings depending on which YAML it appears in, both kept frozen per task:
| Task | Training num_envs (train_<algo>.yaml, paper Table 1) |
Throughput-cap num_envs (task.yaml) |
|---|---|---|
| DSO | 128 (PPO/PPO-Lag/Sauté) / 64 (SAC) | 512 |
| TSO | 256 (PPO/PPO-Lag/penalty) / 64 (SAC) | 1024 |
| DERs | 128 | 128 |
| DC Microgrid | 64 | 256 |
| GenCos | 256 | 256 |
The training value drives the actual policy update and matches paper Table 1 (tab:speed) and Appendix H.2. The throughput-cap value in task.yaml is metadata used only by the cross-backend speed harness; train.py ignores it. Each RunRecord stores throughput_sps, so the cross-task throughput table can be reconstructed from manifest.json alone.
Run-script flow¶
Typical commands look like:
python benchmarks/dso/run.py baseline --seeds 0,1,2,3,4
python benchmarks/dso/run.py train --algo ppo --seed 0
python benchmarks/dso/run.py eval --run-id <run_id> --split iid
python benchmarks/ders/run_all.py --only train --algos ippo ippo_safe ippo_lagrangian --seeds 0 1 2 3 4
python benchmarks/gencos/run_all.py --only eval
python benchmarks/dso/run.py summarize
python benchmarks/dso/run.py plots
baseline: runs the non-learning baselines.train: trains a policy and writes a run record plus checkpoint artifacts.eval: re-evaluates a trained checkpoint on a specified split.summarize: aggregatesmanifest.jsonintoresults/summary/latest.json.plots: regenerates the task-level figures inresults/figures/.
flowchart LR
BL["baseline"] --> TR["train"]
TR --> EV["eval"]
EV --> SU["summarize"]
SU --> PL["plots"]
Backend / device comparisons¶
For backend or device comparisons, keep the task config fixed and vary only the backend or device:
| Mode | Command surface | Notes |
|---|---|---|
| JAX + GPU | each task's own run.py / run_all.py with CUDA_VISIBLE_DEVICES=<id> |
canonical PowerZooJax path |
| JAX + CPU | same command with JAX_PLATFORM_NAME=cpu JAX_PLATFORMS=cpu |
same seeds, timesteps, splits |
| Python + GPU | python -m benchmarks.common.powerzoo_bridge driver ... --device cuda |
required sb3 row in the minimum matrix |
| Python + CPU | same driver with --device cpu |
required sb3 row in the minimum matrix |
All rows in a backend/device table must keep the same:
- case
- real data source
- split definition
- seed set
- total timesteps
- eval-episode count
- reward scaling
- safety thresholds
Reading order¶
If the task pages mention unfamiliar power-system terms, start with Concepts and the relevant Physics / Physics / Physics / Physics page. Then go to the task you care about:
- TSO: security-constrained unit commitment on
case118 - DSO: flexible-load loss minimization on
case33bwwith Ausgrid data - DERs: 12-agent cooperative DER control on
case141 - DC Microgrid: grid-connected data-center microgrid with PV, battery, diesel, and a capped grid-import port (islanded under simulated outages)
- GenCos: 5-agent rolling competitive electricity market on
case5