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 iscap_existing[y, z, te], so the integer number of units iscap / 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 * dtgen[h] >= online[h] * unit_size * p_min_pu * dtThese REPLACE the standard
gen <= cap_existing * p_max_pu * dtbound for UC-eligible techs (the standard one is now redundant becauseonline <= 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 hourno_load_cost[te] * unit_size[te] * online[h] * dtper 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. Default0.tech_unit_size.csv--tech, value(MW). Default1(one cluster = one unit at full cap, equivalent to LP behaviour).tech_min_up_time.csv--tech, value(hours). Default1.tech_min_down_time.csv--tech, value(hours). Default1.tech_startup_cost.csv--tech, value($/MW). Default0.tech_no_load_cost.csv--tech, value($/MW-h). Default0.
- class prepshot._model.unit_commitment.AddUnitCommitmentConstraints(model)[source]¶
Bases:
objectClustered unit-commitment constraints + cost terms.
- Parameters
model (object) --
- min_down_rule(h, m, y, z, te)[source]¶
(N_units - online[h]) >= sum_{i=0..MinDown-1} shutdown[h-i].Symmetric to
min_up_rule: the lookback over absolute hours[h - md + 1, h]pulls in-window shutdowns frommodel.shutdownand pre-window shutdowns fromparams['prior_uc_shutdown'][(z, te, h_abs)].
- 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.The lookback spans absolute hours
[h - mu + 1, h]. Hours that fall inside the current window pullmodel.startup[h_abs, ...]; hours that fall before the window's first hour pull the carried-over count fromparams['prior_uc_startup'][(z, te, h_abs)](populated by the previous PCM window's_extract_window_state). Missing prior values default to 0, equivalent to "no startup recorded that hour" -- a safe under-count that only affects very early hours of the first run.
- n_unit_bound_rule(h, m, y, z, te)[source]¶
online[h] <= N_unitsand 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].At the first hour of a window,
online[h-1]does not exist in this LP, so the rule consultsparams['prior_uc_online'][(z, te)](terminal online count from the previous PCM window). When that lookup is missing (very first window of the run, or non-PCM CEM model) the boundary condition degenerates to "online[h0] free, no startup / shutdown linkage" -- same behaviour as before.
- 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_factorand divided byweightto align with the rest ofcost_var.Returns a zero ExprBuilder when UC is disabled, so callers can add it unconditionally.
- Return type
ExprBuilder