unit_commitment

Unit-commitment (UC) overlay -- clustered MILP formulation.

Standard "clustered UC" representation, used by GenX, PowNet, and similar planning models that need the MILP fidelity without modelling each plant individually:

  • Each UC-eligible tech (typically thermal: coal, gas, oil) is a cluster of identical units of size tech_unit_size[te] MW. The total cluster capacity is cap_existing[y, z, te], so the integer number of units is cap / unit_size.

  • New decision variables per (h, m, y, z, te):

    • online[h] -- number of units online (integer, 0..N_units).

    • startup[h] -- number of units started this hour (integer >=0).

    • shutdown[h] -- number of units shut down this hour (integer >=0).

  • New constraints:

    • State evolution (h > hour[0]): online[h] - online[h-1] = startup[h] - shutdown[h]

    • Capacity bound on dispatch: gen[h] <= online[h] * unit_size * p_max_pu * dt gen[h] >= online[h] * unit_size * p_min_pu * dt

      These REPLACE the standard gen <= cap_existing * p_max_pu * dt bound for UC-eligible techs (the standard one is now redundant because online <= N_units = cap/unit_size).

    • Minimum up time (online >= sum of recent startups): online[h] >= sum_{i=0..MinUp-1} startup[h-i]

    • Minimum down time (offline >= sum of recent shutdowns): (N_units - online[h]) >= sum_{i=0..MinDown-1} shutdown[h-i]

  • New cost terms (added to the objective):

    • startup_cost[te] * unit_size[te] * startup[h] per hour

    • no_load_cost[te] * unit_size[te] * online[h] * dt per hour

    Both NPV-discounted via var_factor[y, z] like the rest of the variable cost.

This module turns PREP-SHOT into a MILP when enabled. HiGHS solves it; runtime grows several-fold relative to the LP. Recommended only for small-to-medium scenarios -- three_zone (48 hours) takes a few seconds; full-year 8760-hour PCM mode with UC is feasible only in rolling-horizon windows (see prepshot.pcm).

Configuration

Add to config.json:

"uc_parameters": {
    "is_uc": true,
    "uc_relaxation": "integer"   // or "continuous" for LP relaxation
}

When is_uc is missing or false, the module is a no-op and PREP-SHOT stays LP. When uc_relaxation is "continuous", the binaries become continuous in their natural ranges -- useful for scaling tests and for warm-starting an integer solve.

Inputs

All optional (rows missing or files missing -> safe defaults):

  • tech_uc_eligible.csv -- tech, eligible. Default 0.

  • tech_unit_size.csv -- tech, value (MW). Default 1 (one cluster = one unit at full cap, equivalent to LP behaviour).

  • tech_min_up_time.csv -- tech, value (hours). Default 1.

  • tech_min_down_time.csv -- tech, value (hours). Default 1.

  • tech_startup_cost.csv -- tech, value ($/MW). Default 0.

  • tech_no_load_cost.csv -- tech, value ($/MW-h). Default 0.

class prepshot._model.unit_commitment.AddUnitCommitmentConstraints(model)[source]

Bases: object

Clustered unit-commitment constraints + cost terms.

Parameters

model (object) --

gen_low_uc_rule(h, m, y, z, te)[source]

gen[h] >= online[h] * unit_size * p_min_pu * dt.

gen_up_uc_rule(h, m, y, z, te)[source]

gen[h] <= online[h] * unit_size * p_max_pu * dt.

min_down_rule(h, m, y, z, te)[source]

(N_units - online[h]) >= sum_{i=0..MinDown-1} shutdown[h-i].

min_up_rule(h, m, y, z, te)[source]

online[h] >= sum_{i=0..MinUp-1} startup[h-i] -- if a unit started in any of the last MinUp hours, it must be online now.

n_unit_bound_rule(h, m, y, z, te)[source]

online[h] <= N_units and force online=startup=shutdown=0 for non-eligible (z, te) cells.

state_evolution_rule(h, m, y, z, te)[source]

online[h] - online[h-1] = startup[h] - shutdown[h] for every hour after the first in the modelled set. The first hour's online state is free (initialised by the LP optimum).

prepshot._model.unit_commitment.add_uc_cost_terms(model)[source]

Return the UC cost contribution (startup + no-load) as an ExprBuilder, NPV-discounted by var_factor and divided by weight to align with the rest of cost_var.

Returns a zero ExprBuilder when UC is disabled, so callers can add it unconditionally.

Return type

ExprBuilder