From dispatch to locational prices: the linear program behind the market
Solve a day of dispatch, read each hourly price as a dual, then congest a line and watch one price split into three
The idea in one picture: noon, with the Ridge–Town line full
With JavaScript on, you build this model step by step and solve it with a real solver in your browser: first a day with every plant in one place, then the same day on this network.
Demand, wind and solar follow lesson 0's real day, 3 September 2025 on the Southwest Power Pool grid (EIA-930), scaled to the town. Prairie Town, its plants, costs, network and line limits are illustrative. The solver is HiGHS (open source), loaded on your first solve (about 3.5 MB, once).
Build it in Python · notebook lab, about 45 minutes, then 90 minutes of practice
The same linear program in scipy.optimize.linprog(method="highs"); assert cells check every browser number.
- Download the notebook; the data are inside it.
- Upload it to Google Colab (File → Upload notebook), or open it locally with Python 3, NumPy and SciPy 1.9 or later.
- Run all cells, then try the practice questions at the end.
Notebook (.ipynb) Lesson data (JSON)
Need a refresher? Toolbox K8 (Git and reproducible notebooks).
What you just did, as diagrams
- Linear program
- Decisions (outputs, flows), a goal (lowest running cost) and rules (balance, sizes, ramp, network), all linear.
- Dual of a balance row
- The extra cost per MWh of a small change in that row's demand: the price at that bus and hour. At a corner of the model the step up and the step down differ.
- Ramp prices
- A slow plant links hours and produces $0 and $80 prices; the $80 matches no plant's offer.
- DC power flow
- Power splits over every path by the lines' reactance: two thirds on the direct line of an equal triangle.
- Congestion
- A full line splits one price into locational prices. Loads then pay more than generators are paid; the difference is the congestion rent, $13,200 at noon with the line at 110 MW.
Go deeper · ModelerPrices from PTDFs, and where the congestion money goes
Take Prairie Town as the reference bus. A power transfer distribution factor \(\text{PTDF}_{\ell n}\) is the share of 1 MW injected at bus \(n\), and taken out in town, that flows on line \(\ell\). In an equal triangle, an injection at the Ridge puts \(2/3\) on Ridge–Town and \(1/3\) on the path through the Gas Hub. In a lossless DC model, with \(\mu_\ell\) the value of 1 MW more limit on line \(\ell\) in that hour:
\[\text{LMP}_n = \text{LMP}_\text{Town} - \sum_\ell \text{PTDF}_{\ell n}\,\mu_\ell .\]
At noon with the line at 110 MW, \(\mu = \$120\): the Ridge gets \(80 - \tfrac{2}{3} \times 120 = \$0\) and the Gas Hub \(80 - \tfrac{1}{3} \times 120 = \$40\).
Congestion rent is what loads pay minus what generators are paid, each at its own bus’s price:
| Noon, line at 110 MW | $ in the hour |
|---|---|
| Loads pay: 311 MWh × $80 | $24,880 |
| Nuclear plant, in town: 100 MWh × $80 | $8,000 |
| Gas Hub: 92 MWh × $40 | $3,680 |
| Wind Ridge: 119 MWh × $0 | $0 |
| Congestion rent: loads minus generators | $13,200 for the hour |
In this DC model the rent also equals each full line’s \(\mu\) times its flow, \(120 \times 110\) MW. It is not the price gap between the line’s two ends times its flow (\(80 \times 110 = \$8{,}800\)).
Many organized markets use congestion revenue to fund financial transmission rights, under their own settlement and funding rules. Their prices also add a third part for losses, which a DC model leaves out (FERC Energy Primer, p. 64).
Go deeper · ModelerWhen a price is not unique
A dual is a slope. At a corner of the model the slope differs on each side, so check both sides. At 14:00 with the line at 110 MW, the gas combined-cycle plant runs at exactly its size, 150 MW:
| In town at 14:00 | Per MWh |
|---|---|
| Step up: one more MWh needs the peaker | costs $200 |
| Step down: one MWh less | saves only $80 |
| The solver’s dual | $80, one end of that range |
If the two sides differ, say which side your question is about. A mixed-integer solve (M2) does not provide these LP shadow prices; after fixing its on/off decisions, a dispatch LP gives prices conditional on them.
Go deeperWhat this model leaves out
- Losses, voltage magnitudes and reactive power: a DC model uses only voltage-angle differences, holds voltage magnitudes fixed and is lossless. A17 estimates line heating and feeder voltage with short formulas to show when that matters, and says when an AC power flow is needed to check.
- Outages: real dispatch keeps flows safe if any one line or plant fails (the N-1 rule).
- Start-ups and minimum run times: those need on/off decisions, a mixed-integer program (M2).
- Offers and price-responsive demand: here costs stand in for offers, and demand is fixed.
- Size: real markets price thousands of locations; the algebra is the same.
Modeler's note: M3 adds investment decisions to this model, and the Modeler checkpoint CK-M asks you to formulate, solve and verify a model you have not seen. The Researcher studio R5 makes verification and validation a routine.
Check yourself
Myth or fact? “A bus price always equals the offer of some plant.”
- Myth
- Fact
Answer
Myth. At noon the town's $80 matches no offer: it is 2 × $40 − 1 × $0, set by the full line's physics.
Myth or fact? “When the line out of a wind area is full, the price at the wind farm can fall to zero.”
- Myth
- Fact
Answer
Fact. Wind Ridge spills power it cannot send, so one more MWh there is free: its price is $0.
Myth or fact? “The dual of a balance row is the price a real market must charge.”
- Myth
- Fact
Answer
Myth. It is a marginal value under this model's assumptions: fixed plants, costs as offers, no losses, this network and day. Markets clear real offers under many more rules.
At noon the full Ridge–Town line (110 MW) has μ = $120. If its limit rose to 111 MW for the noon interval only, the day's running cost would…
- fall by $120
- fall by $80
- fall by $40
- not change
Answer
Fall by $120. Swapping 1 MW of Gas Hub output for Ridge output adds only 2/3 − 1/3 = 1/3 MW to this line, so 1 MW more room lets 3 MW of free Ridge power replace 3 MW of $40 gas.
Which change brings the three noon prices back together?
- Add 50 MW of solar on Wind Ridge
- Raise the Ridge–Town limit to 140 MW
- Raise the gas price
- Lower the town's demand by 1 MW
Answer
Raise the limit to 140 MW: at noon the line then needs only 134 MW, so it has room and one price returns. More Ridge solar would only add to the spill.
Numbers, sources and what’s next
Numbers to remember
| Number | What it means | Source |
|---|---|---|
| 3 parts | A locational marginal price is an energy charge, a congestion charge and a charge for losses. | FERC Energy Primer (PDF), p. 64 · April 2020 edition |
| about 2/3 | Share of U.S. electricity load served in regions whose grid operator runs an organized market with such prices. | FERC, Electric Power Markets · page accessed 2 Nov 2026 |
| 2/3 and 1/3 | How an equal triangle of lines splits power sent from one corner to another: direct line, and the path around. | DC power flow; this lesson's network (illustrative) |
| $80 = 2 × $40 − 1 × $0 | The town's noon price with the line full: two gas MWh in, one Ridge MWh out. | This lesson's model (illustrative) |
Next
In the real world
Grid operators that run markets compute a price at each location from the same kind of model, with losses, security rules and many more locations.
Sources and further reading
- FERC staff (2020). Energy Primer: A Handbook of Energy Market Basics (PDF), chapter 3: locational marginal pricing.
- FERC. Electric Power Markets: the regions with organized markets.
- EIA. Hourly Electric Grid Monitor (Form EIA-930): the Southwest Power Pool data behind lesson 0's day.
- HiGHS. Documentation of the open-source solver used in the page and, through SciPy, in the notebook.
Spotted an error, or stuck? Write to hlli@ksu.edu. Corrections are made in place and dated here.
Text licensed CC BY 4.0, code MIT: teachers and students may reuse and adapt it, with credit to Honglin Li.