Your first spec#
Write a least-cost dispatch spec one section at a time, check it, and print it as math. Install mathspec first.
Dimensions#
Make a file dispatch.yaml with a description and two
dimensions, the sets the spec is indexed
over:
description: Least-cost dispatch of a generator fleet against an hourly load.
dimensions:
snapshot: { dtype: int, description: dispatch periods }
generator: { description: generating units }
Check the file:
The check accepts the file, but advises that nothing uses the dimensions yet:
dimension 'snapshot' is never used: nothing is indexed by it, nothing sums into it, and no relation has a column over it. Remove it, or keep it if the entries that use it are still to be written.
dimension 'generator' is never used: nothing is indexed by it, nothing sums into it, and no relation has a column over it. Remove it, or keep it if the entries that use it are still to be written.
Parameters and a variable#
Add three parameters, the data
the spec expects, and one variable,
the decision the solver makes. The where: line leaves out every generator with
no capacity.
parameters:
capacity: { dims: [generator], description: installed capacity }
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]
where: "capacity > 0"
bounds: { lower: 0, upper: capacity }
Print the math, with --no-legend to leave out the tables of symbols:
Rendered output
Least-cost dispatch of a generator fleet against an hourly load.
Variable domains#
dispatch
Constraint and objective#
Add one constraint, which meets the load in every snapshot, and the objective:
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
objective:
sense: minimize
expression: sum(dispatch * cost)
Check the file again. This time the check prints nothing and exits with status 0.
The whole file
description: Least-cost dispatch of a generator fleet against an hourly load.
dimensions:
snapshot: { dtype: int, description: dispatch periods }
generator: { description: generating units }
parameters:
capacity: { dims: [generator], description: installed capacity }
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]
where: "capacity > 0"
bounds: { lower: 0, upper: capacity }
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
objective:
sense: minimize
expression: sum(dispatch * cost)
An undeclared name#
Change load to loads in the constraint, and check the file. The check
refuses it and exits with status 1:
Constraint 'power_balance': 'loads' not found.
Variables: ['dispatch']
Parameters: ['capacity', 'cost', 'load']
Check the spelling, or declare 'loads'.
Change loads back to load.
The math#
Print the whole spec:
Rendered output
Least-cost dispatch of a generator fleet against an hourly load.
Sets#
| Symbol | Meaning |
|---|---|
| \(\mathcal{T}\) | index \(t\) — snapshot — dispatch periods |
| \(\mathcal{G}\) | index \(g\) — generator — generating units |
Parameters#
| Symbol | Meaning |
|---|---|
| \(\mathrm{capacity}\) | capacity over \(\mathcal{G}\) — installed capacity |
| \(\mathrm{load}\) | load over \(\mathcal{T}\) — demand to be met |
| \(\mathrm{cost}\) | cost over \(\mathcal{G}\) — marginal cost |
Variables#
| Symbol | Meaning |
|---|---|
| \(\mathit{dispatch}\) | dispatch over \(\mathcal{T} \times \mathcal{G}\) — output of a generator in a snapshot |
Variable domains#
dispatch
Objective#
Subject to#
power_balance
Where to next#
- The language gives every rule a file obeys.
- Examples shows larger specs beside the math they print.
- Print a spec as math prints LaTeX and Typst.