Skip to content

Unit commitment (TSO)

Public API for UnitCommitmentEnv and the TSO benchmark factories. For physics, see Physics → Transmission.

UnitCommitmentEnv

from powerzoojax.envs import (
    UnitCommitmentEnv,
    UCState,
    UCParams,
    make_uc_params,
)

Step contract

  • Action: Box(2 * n_units) in [-1, 1] = [commitment_signal (n_units) | dispatch_target (n_units)].
  • Reward: -reward_scale * (gen_cost + startup_cost + no_load_cost).
  • Constraint costs: costs = (w_th * cost_thermal_overload, cost_reserve_shortfall, cost_min_updown). cost_min_updown is currently always 0 because masking guarantees feasibility.

Observation layout

[unit_status | time_in_state_norm | last_dispatch_norm | unit_cost_b_norm | line_flow_norm | load_norm | reserve_ratio | sin(t) | cos(t) | future_total_load_norm[t+1:t+H]]. Total dim 4 * n_units + n_lines + 4 + H, where H = forecast_horizon_steps. This is the policy input vector, not a separate raw telemetry API. For field-by-field semantics, see Physics → Transmission.

powerzoojax.envs.grid.unit_commitment.UnitCommitmentEnv

Bases: Environment

Unit Commitment environment — DC power flow with UC state machine.

Box(2 * n_units) in [-1, 1].

First n_units → commitment intent; > 0.0 → commit (if enable_uc). Last n_units → dispatch intent. Direct-PF mode: maps directly to [p_min, p_max] then clipped to ramp. DC-OPF mode : used as a preference bias — OPF cost is shifted by −dispatch_preference_weight × target_mw so the OPF solution moves toward the agent's preferred dispatch while still respecting physical constraints.

Env enforces
  • Min-up / min-down constraints via commitment masking
  • Ramp constraints via modified p_min/p_max in DCOPF
  • Startup cost accounting (off→on transition)
  • No-load cost (per ON unit per step)
  • Reserve margin check

Reward: -reward_scale * (gen_cost + startup_cost + no_load_cost) Constraint costs: thermal_overload, reserve_shortfall, min_updown

reset(key, params)

step(key, state, action, params)

Run one UC environment step.

[commit_intent(n_units) | dispatch_intent(n_units)]

commit_intent ∈ [-1, 1]: > 0 → want to commit (if enable_uc). dispatch_intent ∈ [-1, 1]: maps to [eff_p_min, eff_p_max]. Direct-PF mode: used as dispatch setpoint. DC-OPF mode : biases OPF cost toward preferred dispatch.

observation_space(params)

action_space(params)

powerzoojax.envs.grid.unit_commitment.UCState

Bases: GridState

Unit Commitment environment state (extends GridState).

Additional UC state-machine fields beyond GridState

unit_status: Current on/off for each unit (1=on, 0=off). time_in_state: Steps in current on/off state (≥ 1 after first step). last_dispatch: Previous step actual dispatch [MW] (0 for off units). startup_cost_accum: Episode-accumulated startup cost [$].

powerzoojax.envs.grid.unit_commitment.UCParams

Bases: TransGridParams

Unit Commitment environment parameters (extends TransGridParams).

UC-specific fields

min_up_steps: Minimum consecutive ON steps per unit. min_down_steps: Minimum consecutive OFF steps per unit. startup_cost: One-time startup cost per unit [\(]. no_load_cost_per_step: Fixed running cost per step per unit [\)/step]. ramp_up_mw: Max ramp-up per step per unit [MW/step]. ramp_down_mw: Max ramp-down per step per unit [MW/step]. reserve_margin_frac: Required headroom above total load (e.g. 0.05). enable_uc: If False, all units always ON — pure economic dispatch mode. enable_reserve: If False, reserve shortfall not charged as cost. forecast_horizon_steps: Number of future total-load forecast steps appended to the observation. 0 keeps the legacy no-forecast layout. init_unit_status: Initial on/off status for reset. init_time_in_state: Initial time-in-state for reset [steps]. init_dispatch: Initial dispatch for reset [MW]. sample_start_on_reset: If True, reset samples a fresh 48-step episode start uniformly from the bound load_profiles pool. fixed_episode_start_idx: Deterministic start index used when sampling is disabled (the eval/default path).

powerzoojax.envs.grid.unit_commitment.make_uc_params(case, load_profiles=None, max_steps=48, delta_t_hours=0.5, steps_per_day=48, reserve_margin_frac=0.05, enable_uc=True, enable_reserve=True, forecast_horizon_steps=0, reward_scale=0.0001, cost_thermal_weight=1.0, solver_mode=1, dcopf_max_iter=100, dcopf_tol=0.001, sample_start_on_reset=False, fixed_episode_start_idx=0)

Create UCParams from a CaseData with UC fields.

Ramp conversion

unit_ramp_up / unit_ramp_down in CaseData are fractions per hour. ramp_mw_per_step = ramp_frac * p_max * delta_t_hours

min_up_time / min_down_time in CaseData are in steps (30-min res).

keep_time in CaseData is in steps; abs value = initial time-in-state.

Parameters:

Name Type Description Default
case CaseData

CaseData with UC fields populated (unit_ramp_up, unit_min_up_time, unit_startup_cost, unit_no_load_cost, unit_init_state, unit_keep_time).

required
load_profiles Array

(T, n_loads) MW load profiles. None → flat midpoint.

None
max_steps int

Episode length.

48
delta_t_hours float

Step duration in hours (0.5 = 30-min).

0.5
steps_per_day int

Steps per day (48 for 30-min resolution).

48
reserve_margin_frac float

Required reserve headroom fraction.

0.05
enable_uc bool

If False, all units always ON (ED mode).

True
enable_reserve bool

If False, no reserve cost.

True
forecast_horizon_steps int

Number of future total-load steps appended to the observation.

0
reward_scale float

Scalar for reward = -reward_scale * operating_cost.

0.0001
cost_thermal_weight float

Weight for thermal overload in CMDP cost.

1.0
solver_mode int

0 = direct dispatch PF, 1 = DC-OPF (recommended for SCUC).

1
dcopf_max_iter int

Max ADMM iterations for the DC-OPF redispatch.

100
dcopf_tol float

ADMM convergence tolerance for the DC-OPF redispatch.

0.001
sample_start_on_reset bool

Whether reset samples a new episode start uniformly from the bound load-profile pool.

False
fixed_episode_start_idx int

Deterministic episode start used when sample_start_on_reset is False.

0

TSO factories

from powerzoojax.envs import (
    make_tso_case118_params,
    make_tso_case14_params,
    make_tso_ed_params,
    make_tso_uc_params,
    make_tso_scuc_params,
)

powerzoojax.tasks.tso.make_tso_case118_params(load_profiles=None, max_steps=48, delta_t_hours=0.5, reserve_margin_frac=0.05, enable_uc=True, enable_reserve=True, forecast_horizon_steps=0, reward_scale=0.0001, cost_thermal_weight=1.0, solver_mode=1, dcopf_max_iter=100, dcopf_tol=0.001, sample_start_on_reset=False, fixed_episode_start_idx=0, data_loader=None, split='train')

Create UCParams for the case118 TSO-SCUC main task.

Uses IEEE 118-bus system with 54 generators and UC fields from case data. Load profiles default to synthetic net-load (intraday sinusoidal). Pass data_loader to use real GB demand / generation data.

Parameters:

Name Type Description Default
load_profiles Optional[Array]

Pre-built (T, n_loads) profiles [MW]. If None, generated from GB data (if data_loader given) or synthetic.

None
max_steps int

Episode length (48 steps = 24 hours at 30-min).

48
delta_t_hours float

Step duration in hours.

0.5
reserve_margin_frac float

Required reserve headroom fraction of load.

0.05
enable_uc bool

True=SCUC mode, False=pure ED.

True
enable_reserve bool

True=charge reserve shortfall as cost.

True
forecast_horizon_steps int

Number of future total-load steps appended to the observation.

0
reward_scale float

Multiplier for reward = -reward_scale * operating_cost.

0.0001
cost_thermal_weight float

Weight on thermal overload in CMDP cost.

1.0
solver_mode int

0=direct PF, 1=DC-OPF (recommended).

1
dcopf_max_iter int

Max ADMM iterations for the DC-OPF redispatch.

100
dcopf_tol float

ADMM convergence tolerance for the DC-OPF redispatch.

0.001
sample_start_on_reset bool

Whether reset samples a fresh episode start uniformly from the bound load-profile pool.

False
fixed_episode_start_idx int

Deterministic start index used when sampling is disabled.

0
data_loader

Optional DataLoader for GB demand / wind / solar data.

None
split str

"train" or "iid" split for data_loader.

'train'

Returns:

Type Description
UCParams

UCParams ready for use with UnitCommitmentEnv.

powerzoojax.tasks.tso.make_tso_case14_params(load_profiles=None, max_steps=48, delta_t_hours=0.5, reserve_margin_frac=0.05, enable_uc=True, enable_reserve=True, forecast_horizon_steps=0, reward_scale=0.0001, solver_mode=1, dcopf_max_iter=100, dcopf_tol=0.001)

Create UCParams for the case14 small-scale sanity / debug task.

IEEE 14-bus system with 5 generators. UC fields come from create_case14() (same table layout as case118). Suitable for small-scale UC / ED tests.

powerzoojax.tasks.tso.make_tso_ed_params(case_id='118', max_steps=48, delta_t_hours=0.5)

Variant: TSO-ED — all units always ON, pure economic dispatch.

No UC constraints, no startup/no_load cost, no reserve check. Equivalent to TransGridEnv in DCOPF mode but wrapped in UCParams.

powerzoojax.tasks.tso.make_tso_uc_params(case_id='118', max_steps=48, delta_t_hours=0.5)

Variant: TSO-UC — commitment + min-up/down + startup cost, NO reserve cost.

enable_uc=True, enable_reserve=False. Reserve shortfall is still tracked in info but not charged as CMDP cost.

powerzoojax.tasks.tso.make_tso_scuc_params(case_id='118', max_steps=48, delta_t_hours=0.5, reserve_margin_frac=0.05)

Variant: TSO-SCUC-Safe — full SCUC with reserve cost in CMDP cost channel.

enable_uc=True, enable_reserve=True. Task-level CMDP selection consumes thermal overload + reserve shortfall. Intended for PPO-Lagrangian / SafeRLWrapper training.

TSO net-load helpers

powerzoojax.tasks.tso.make_tso_net_load_profiles(n_steps=48, wind_frac=0.7, solar_frac=0.5, load_d_max=None, gross_demand_mw=None, wind_mw=None, solar_mw=None, delta_t_hours=0.5)

Construct (n_steps, n_loads) net-load profiles.

Net-load = gross_demand - wind_frac * wind - solar_frac * solar Then rescaled per bus by load_d_max.

When real data arrays are not provided, generates synthetic intraday profiles: - gross_demand: sinusoidal daily curve (peak at hour 18) - wind: higher at night / lower midday - solar: bell curve around noon

Parameters:

Name Type Description Default
n_steps int

Number of time steps.

48
wind_frac float

Fraction of wind that is must-take (default 0.7).

0.7
solar_frac float

Fraction of solar that is must-take (default 0.5).

0.5
load_d_max Optional[Array]

(n_loads,) per-bus maximum demand [MW]. If None, returns normalised profiles in [0, 1].

None
gross_demand_mw Optional[Array]

(n_steps,) total system demand [MW]. None → synthetic.

None
wind_mw Optional[Array]

(n_steps,) wind available [MW]. None → synthetic.

None
solar_mw Optional[Array]

(n_steps,) solar available [MW]. None → synthetic.

None
delta_t_hours float

Step duration (used for synthetic profile phase).

0.5

Returns:

Type Description
Array

(n_steps, n_loads) float32 JAX array of load profiles [MW].

Array

If load_d_max is None, shape is (n_steps, 1) with values in [0, 1].

powerzoojax.tasks.tso.make_tso_net_load_profiles_from_data(data_loader, case, split='train', episode_start_idx=0, n_steps=48, wind_frac=0.7, solar_frac=0.5, allow_synthetic_fallback=False)

Load net-load profiles from GB data via DataLoader.

Uses the DataLoader JAX API (load_jax_profiles) with semantic signal names load.actual_mw, wind.available_mw, solar.available_mw.

Parameters:

Name Type Description Default
data_loader

DataLoader instance.

required
case CaseData

CaseData for load_d_max scaling.

required
split str

"train" or "iid" (selects GB_TRAIN_ or GB_IID_ date range).

'train'
episode_start_idx int

Starting row index within the loaded window.

0
n_steps int

Number of steps to extract.

48
wind_frac float

Must-take wind fraction (default 0.7).

0.7
solar_frac float

Must-take solar fraction (default 0.5).

0.5
allow_synthetic_fallback bool

If True, fall back to synthetic profiles when data loading fails instead of raising. Default False — callers must opt in to the fallback explicitly so failures are not silent.

False

Returns:

Type Description
Array

(n_steps, n_loads) float32 JAX array.

Raises:

Type Description
RuntimeError

If data loading fails and allow_synthetic_fallback=False.

Non-learning baselines

from powerzoojax.envs import tso_all_on_rollout, tso_merit_order_rollout

powerzoojax.tasks.tso.tso_all_on_rollout(env, params, key)

Reference baseline: all units always ON; economic dispatch by DC-OPF.

Returns episode metrics dict.

powerzoojax.tasks.tso.tso_merit_order_rollout(env, params, key, n_commit=None)

Priority-list (merit-order) commitment, then OPF dispatch (cheapest units first).

Parameters:

Name Type Description Default
n_commit Optional[int]

Number of units to commit each step. None → choose a count from total load (commit just enough nameplate capacity to cover load + reserve).

None

Metrics

powerzoojax.tasks.tso.compute_tso_metrics(rollout_results, baseline_results=None)

Aggregate episode-level TSO metrics.

Parameters:

Name Type Description Default
rollout_results Dict[str, Any]

Dict from tso_*_rollout or custom policy rollout.

required
baseline_results Optional[Dict[str, Any]]

Optional reference (e.g. all_on) for relative metrics.

None

Returns:

Type Description
Dict[str, float]

Dict of scalar metrics.