transport¶
A network: generators sit on buses, lines connect buses, and power balances at every bus.
The problem¶
Each sum is over the lines or generators a coordinate map sends to bus \(b\) — \(\mathrm{bus}\), \(\mathrm{to}\) and \(\mathrm{from}\) are the coordinates the dimensions declare, not sets in their own right. Load is \(d\) here, because \(\ell\) is already the line index.
The model¶
The same model, as math
Sets¶
| Symbol | Meaning |
|---|---|
| \(\mathcal{S}\) | index \(s\) --- snapshot --- dispatch periods |
| \(\mathcal{G}\) | index \(g\) --- generator with \(\mathrm{bus}: \mathcal{G} \to \mathcal{B}\) --- generating units |
| \(\mathcal{B}\) | index \(b\) --- bus --- network nodes |
| \(\mathcal{L}\) | index \(\ell\) --- line with \(\mathrm{from}: \mathcal{L} \to \mathcal{B},\enspace \mathrm{to}: \mathcal{L} \to \mathcal{B}\) --- transmission lines, each joining two buses |
Parameters¶
| Symbol | Meaning |
|---|---|
| \(\bar p\) | p_max over \(\mathcal{G}\) --- installed capacity |
| \(c\) | cost over \(\mathcal{G}\) --- marginal cost |
| \(\bar f\) | cap over \(\mathcal{L}\) --- forward transmission limit |
| \(\underline{f}\) | neg_cap over \(\mathcal{L}\) --- reverse transmission limit |
| \(d\) | load over \(\mathcal{S} \times \mathcal{B}\) --- demand at each bus |
Variables¶
| Symbol | Meaning |
|---|---|
| \(p\) | p over \(\mathcal{S} \times \mathcal{G}\) --- output of generator \(g\) in snapshot \(s\) |
| \(f\) | f over \(\mathcal{S} \times \mathcal{L}\) --- flow on line \(\ell\), signed towards its to bus |
Objective¶
total_cost
Subject to¶
balance
Variable domains¶
p
f
dimensions:
snapshot:
dtype: int
generator:
dtype: str
coords: [bus] # every generator sits on a bus
bus:
dtype: str
line:
dtype: str
coords: {from: bus, to: bus} # both endpoints are buses
parameters:
p_max:
dims: [generator]
cost:
dims: [generator]
cap:
dims: [line]
neg_cap:
dims: [line]
load:
dims: [snapshot, bus]
variables:
p:
foreach: [snapshot, generator]
bounds:
lower: 0
upper: p_max
f:
foreach: [snapshot, line]
bounds:
lower: neg_cap
upper: cap
# Naming the two halves of the nodal balance. Pure substitution before either
# backend sees the model, so this costs nothing at build and nothing at solve —
# what it buys is a constraint that reads as the sentence it is.
expressions:
gen_at_bus: group_sum(p, over=generator, by=bus)
net_inflow: group_sum(f, over=line, by=to) - group_sum(f, over=line, by=from)
constraints:
balance:
foreach: [snapshot, bus]
expression: gen_at_bus + net_inflow == load
objectives:
total_cost:
sense: minimize
expression: p * cost
What it exercises¶
Three group_sum calls, and they are what a network is in this language.
A dimension can carry coordinates — generator carries bus, line
carries from and to — and group_sum(f, over=line, by=to) sums along a
line's to coordinate, landing the result on bus. The same f is summed
twice through two different coordinates, once as an inflow and once as an
outflow.
No adjacency matrix, and no join written by the modeller: the topology is data on the dimension.
examples/transport.yaml · back to all models