Unit commitment#
Unit commitment is least-cost dispatch with an on/off decision for each unit in each dispatch period (a snapshot).
The file states the cases of previous_status once, under
cases:. always_on and boundary
each have a when: condition, and
otherwise: sets the value at every combination of labels
(a coordinate) that no case covers. So otherwise: applies only to a committable
unit after the first snapshot, where the
shift in otherwise: always has
a previous status to take. The shift of dispatch in ramp_up has
edge=0, so that constraint has a row at the first snapshot.
description: >-
Unit commitment with a start-up ramp, in which one named expression sets the
commitment state of a unit at the start of a snapshot. That state has three cases:
a unit that is never off, the first snapshot, and every later one.
dimensions:
snapshot: { dtype: int, description: dispatch periods, ordered: true }
generator: { description: generating units }
parameters:
committable: { dims: [generator], dtype: bool, description: whether the unit may be switched off }
status_initial: { dims: [generator], description: whether the unit was running before the horizon }
capacity: { dims: [generator], description: installed capacity }
min_output: { dims: [generator], description: output floor while running }
ramp_limit: { dims: [generator], description: how far output may move between snapshots while running }
start_up_limit: { dims: [generator], description: how far output may move in the snapshot a unit starts in }
load: { dims: [snapshot], description: demand to be met }
cost: { dims: [generator], description: marginal cost }
variables:
dispatch:
description: output of a generator in a snapshot
dims: [snapshot, generator]
bounds: { lower: 0, upper: capacity }
status:
description: whether the unit is running in a snapshot
dims: [snapshot, generator]
domain: binary
expressions:
previous_status:
description: the commitment state of a unit at the start of a snapshot
dims: [snapshot, generator]
cases:
always_on:
when: "not committable"
expression: 1
boundary:
when: "committable and position(snapshot) == 0"
expression: status_initial
otherwise: shift(status, along=snapshot, offset=1)
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
upper:
description: a unit that is not running produces nothing
dims: [snapshot, generator]
expression: dispatch <= status * capacity
lower:
description: a running unit produces at least its floor
dims: [snapshot, generator]
expression: dispatch >= status * min_output
ramp_up:
description: >-
one inequality for a unit already running and a unit starting up: the
first is held to `ramp_limit`, and the second to `start_up_limit`.
dims: [snapshot, generator]
expression: >-
dispatch - shift(dispatch, along=snapshot, offset=1, edge=0)
<= ramp_limit * previous_status + start_up_limit * (1 - previous_status)
assumptions:
output_floor_fits_under_the_cap:
holds: "min_output <= capacity"
where: "committable"
description: >-
`lower` and `upper` bound one dispatch from both sides, so a floor above
the cap makes a running unit infeasible rather than expensive. A tool
checks the assumption only for committable units.
objective:
sense: minimize
expression: sum(dispatch * cost)
Unit commitment with a start-up ramp, in which one named expression sets the commitment state of a unit at the start of a snapshot. That state has three cases: a unit that is never off, the first snapshot, and every later one.
Sets#
| Symbol | Meaning |
|---|---|
| \(\mathcal{G}\) | index \(g\) — generator — generating units |
| \(\mathcal{T}\) | index \(t\) — snapshot — dispatch periods |
Parameters#
| Symbol | Meaning |
|---|---|
| \(\mathrm{capacity}\) | capacity over \(\mathcal{G}\) — installed capacity |
| \(\mathrm{committable}\) | committable over \(\mathcal{G}\) — whether the unit may be switched off |
| \(\mathrm{cost}\) | cost over \(\mathcal{G}\) — marginal cost |
| \(\mathrm{load}\) | load over \(\mathcal{T}\) — demand to be met |
| \(\mathrm{min\_output}\) | min_output over \(\mathcal{G}\) — output floor while running |
| \(\mathrm{ramp\_limit}\) | ramp_limit over \(\mathcal{G}\) — how far output may move between snapshots while running |
| \(\mathrm{start\_up\_limit}\) | start_up_limit over \(\mathcal{G}\) — how far output may move in the snapshot a unit starts in |
| \(\mathrm{status}^{\mathrm{initial}}\) | status_initial over \(\mathcal{G}\) — whether the unit was running before the horizon |
Variables#
| Symbol | Meaning |
|---|---|
| \(\mathit{dispatch}\) | dispatch over \(\mathcal{G} \times \mathcal{T}\) — output of a generator in a snapshot |
| \(\mathit{status}\) | status over \(\mathcal{G} \times \mathcal{T}\) — whether the unit is running in a snapshot |
Definitions#
| Symbol | Meaning |
|---|---|
| \(\mathit{previous\_status}\) | previous_status over \(\mathcal{G} \times \mathcal{T}\) — the commitment state of a unit at the start of a snapshot |
Notation#
| Symbol | Meaning |
|---|---|
| \(t \boxminus_{v} k\) | edge=v — \(t-k\), and \(v\) past the edge |
| \(\mathrm{pos}(t)\) | position() — the position of \(t\), counted from \(0\); \(t\) is the label |
Variable domains#
dispatch
status
Definitions#
previous_status
Objective#
Subject to#
lower
power_balance
ramp_up
upper
Assumptions#
output_floor_fits_under_the_cap
See also
cases, for how mathspec checks that no two cases overlap, and what it refuses in themshift, foredge=and the vacated position- The composed spec, for commitment written as a patch over a component library