Honglin Li
  • Research
  • Projects
  • Publications
  • Software
  • Teaching
  • Learn
  • Notes
  • CV
  • Journeys

How do you read a formulation, and check that a model is right?

Read a dispatch model line by line, hunt five planted bugs, and check a solved model’s balance and duals

Bridge B3 of Energy Systems, Step by Step: read a published-style dispatch model (sets, parameters, variables, objective, constraints) in plain words and units, hunt five planted bugs and run each with a real solver, then check a solved model’s energy balance and dual signs, and tell verification from validation.
  1. Learn
  2. B3
  • Analyst to Modeler · L2–L3
  • 30 min guided · about 45 min practice
  • After B1
  • Completed
  1. 1Step by step
  2. 2Explain
  3. 3Check
  4. 4Sources

Prairie Town's dispatch, 17:00 to 20:00 on 3 September 2025, as a published model would write it

  1. min Σt∈T Σg∈G cg pg,t Δt + Σt∈T V ut Δt
  2. Σg∈G pg,t + ut = dt ∀ t ∈ T (balance)
  3. pg,t ≤ P̄g ∀ g ∈ G, t ∈ T (sizes)
  4. pg,t ≤ ag,t ∀ g ∈ {wind, solar}, t ∈ T (weather)
  5. −R Δt ≤ pcc,t − pcc,t−1 ≤ R Δt ∀ t ∈ T (ramp; the start pcc,16 = 45 MW is given)
  6. pnuc,t = P̄nuc ∀ t ∈ T (nuclear runs flat); p, u ≥ 0
Symbol key and input values
Symbol Meaning Unit Value
nuc, wind, solar, cc, pk the plants in G: nuclear, wind farm, solar farm, combined-cycle gas plant, peaker
dt demand in hour t MW 17:00 349, 18:00 344, 19:00 331, 20:00 319
awind,t wind the weather allows MW 17:00 54, 18:00 59, 19:00 72, 20:00 89
asolar,t sun the weather allows MW 17:00 130, 18:00 70, 19:00 14, 20:00 0
cg running cost of plant g $/MWh nuc 10, wind 0, solar 0, cc 40, pk 100
P̄g size of plant g MW nuc 100, wind 150, solar 200, cc 150, pk 100
R how far the cc plant can move in an hour MW per hour 40
pcc,16 cc output at 16:00, the start: given, not chosen MW 45
V charge for each MWh of unserved demand $/MWh 10,000
Δt length of one step h 1

Its solution costs $22,600: the combined-cycle plant makes 75, 115, 145 and 130 MW, the peaker nothing, and the balance holds in all four hours.

With JavaScript on, you read it line by line, hunt five planted bugs and check the solution with a real solver.

  • Demand, wind and solar: the real hourly shapes of 3 September 2025 on the Southwest Power Pool grid (EIA-930), scaled as in lesson 0.
  • Start: the combined-cycle plant's 45 MW at 16:00, from lesson 0's cheapest-first plan.
  • Plant sizes and costs are Prairie Town's; the $10,000/MWh charge for unserved demand is illustrative.
  • Solver: HiGHS 1.15, in your browser.

What you just did, as diagrams

Reading sequence
Sets, parameters, variables, objective, constraints: what is counted, given, chosen, scored and ruled out.
Indices and sums
p with indices g and t is a table; Σ over g adds a column, Σ over t a row.
Units
$/MWh × MW × h = $: every term of the objective in dollars, with Δt written out.
For all
One line with ∀ t ∈ T stands for one row per hour.
Verification
Does the model do what its equations say? Units, signs, balance, duals, a hand check.
Validation
Is the model right enough for the question? Compare with real data and expert judgement.
Go deeper · AnalystWhy the balance dual is $0 at 17:00 and $80 at 18:00

A balance dual is the change in the cheapest total cost when one hour’s demand rises by 1 MWh.

  • 19:00 and 20:00: $40. The combined-cycle plant simply makes 1 MW more.
  • 18:00: $80. The plant already climbs its full 40 MW from 17:00, so 1 MW more at 18:00 needs 1 MW more at 17:00 too, where it pushes out free wind: $40 + $40 = $80, still below the $100 peaker.
  • 17:00: $0. The plan already spills 10 MW of wind and sun to warm the plant up for the evening; one more MWh there just spills less.
  • Linked hours. The ramp links the hours, so it links their prices. The Modeler lesson M1 reads such duals as marginal values for a whole day.
Go deeper · ModelerThe objective and the balance in Pyomo

Each line of the formulation becomes one line of code, with the sets doing the copying. Here are the objective and the balance in Pyomo, with c, d, V and dt holding the parameters; the sizes, weather, ramp and nuclear lines are left out:

from pyomo.environ import *
m = ConcreteModel()
m.T = Set(initialize=[17, 18, 19, 20])
m.G = Set(initialize=["nuc", "wind", "solar", "cc", "pk"])
m.p = Var(m.G, m.T, within=NonNegativeReals)   # MW
m.u = Var(m.T, within=NonNegativeReals)        # MW
m.cost = Objective(expr=sum(c[g] * m.p[g, t] * dt for g in m.G for t in m.T)
                        + sum(V * m.u[t] * dt for t in m.T))
m.balance = Constraint(m.T, rule=lambda m, t:
    sum(m.p[g, t] for g in m.G) + m.u[t] == d[t])

Suspect 3 in code is a single balance row for hour 17, in place of the indexed one:

m.balance = Constraint(expr=sum(m.p[g, 17] for g in m.G) + m.u[17] == d[17])
  • Drop * dt: the objective is then right only at one-hour steps.
  • The skill: reading code against the formulation, line by line, as in this lesson.
Go deeper · ResearcherValidation in published energy studies

Validating an optimization model is hard: it describes what would be cheapest, not what will happen.

Approach Evidence Limit
Look back For the UK’s electricity transition from 1990 to 2014, the cumulative cost of the real path deviated by 9 to 23% from the cost-optimal paths of a model, under the study’s alternative assumptions (Trutnevyte, 2016). One country and one model; the real path was never meant to be cost-optimal.
Good practice Guidance for energy-system optimization studies asks for documented, verifiable models and for uncertainty to be explored, not hidden (DeCarolis et al., 2017). A standard to meet, not a test that passes or fails.

The Researcher studio R5 turns both into a routine.

Check yourself

Myth or fact? “A model that solves to ‘optimal’ has passed verification.”

  • Myth
  • Fact
Answer

Myth. All five suspects solved to optimal. The solver checks the mathematics, not whether it says what you meant.

Myth or fact? “A balance dual can never be negative.”

  • Myth
  • Fact
Answer

Myth. Here all four are ≥ 0, but when output is forced above demand, more demand saves money: cut 17:00 demand to 105 MW and its dual becomes −$140. Real markets see negative prices for the same reason.

Myth or fact? “Adding up p in MW over the hours gives energy in MWh.”

  • Myth
  • Fact
Answer

Myth. Multiply by Δt first. With one-hour steps the number happens to be the same; at 15-minute steps the plain sum is four times too big.

A model's cost is far below your hand estimate, and the dearest plant runs first. Which check finds the bug fastest?

  • The units of every parameter
  • The balance in every hour
  • Counting rows
  • The signs of the duals
Answer

The units: a cost in $/kWh read as $/MWh makes a plant look a thousand times cheaper, as suspect 1 showed. The balance still holds.

How many rows does p(g,t) ≤ P̄(g) ∀ g ∈ G, t ∈ T stand for, with 5 plants and a whole day of 24 hours?

  • 5
  • 24
  • 120
  • 29
Answer

120: one row for each plant in each hour, 5 × 24.

Practice: nine exercises in three sets · about 39 min

With JavaScript on, each exercise runs the solver, gives hints one at a time and checks your answer.

Read a line

Say what a line means, the unit of every symbol, and how many rows it stands for.

  1. The ramp line, word by word (worked example, about 2 min)

    −R Δt ≤ pcc,t − pcc,t−1 ≤ R Δt   ∀ t ∈ T

    • In words. From one hour to the next, the combined-cycle plant's output changes by at most R, up or down.
    • Units. p is in MW; R = 40 MW per hour times Δt = 1 h is MW too: every side in MW.
    • Rows. Two limits per hour, one on each side: 4 hours give 8 rows.
    • First hour. At t = 17, p(cc, 16) is not a variable but the start, 45 MW: a parameter.

    How many rows would this line stand for over a whole day of 24 hours?

    Answer

    Two rows per hour, 2 × 24 = 48.

  2. A storage line: the units (partly worked, about 3 min)

    et = et−1 + η qt Δt − wt Δt   ∀ t ∈ T

    The energy in a battery at the end of hour t is what it held an hour before, plus what charging adds after losses, minus what it discharges.

    • et, energy stored: MWh (given)
    • Δt, the step: h (given)

    Give the unit of each: qt, charging power, η, the share kept, wt, discharging power. Rows for the 4 hours of T?

    Answer

    q(t): MW; η: no unit; w(t): MW. MWh = MWh + (no unit × MW × h) − (MW × h), and 4 rows, one per hour.

  3. A reserve line, from scratch (from scratch, about 5 min)

    Σg∈{cc, pk} (P̄g − pg,t) ≥ rt   ∀ t ∈ T

    What does this line ask for?

    1. Every hour, the two gas plants keep at least r(t) of unused capacity in hand.
    2. Every hour, the two gas plants make at least r(t).
    3. Over the whole day, the gas plants' unused capacity adds up to at least r.
    4. Every hour, each gas plant keeps r(t) unused.

    The unit of r(t)? Its rows over a day of 24 hours? Rows of the 24-hour model with this line added?

    Answer

    Every hour, the two gas plants keep at least r(t) of unused capacity in hand. Unused gas capacity in MW, one row per hour; 264 rows for the day plus 24 reserve rows: 288.

Hunt the bug

Three more colleagues, three more planted errors: run each model and let its numbers point to the line.

  1. The penalty in the wrong unit (worked example, about 3 min)

    1. c = (10, 0, 0, 40, 100) $/MWh for (nuc, wind, solar, cc, pk); V = 10 $/kWh (costs)
    2. min Σt∈T Σg∈G cg pg,t Δt + Σt∈T V ut Δt (objective)
    3. Σg∈G pg,t + ut = dt   ∀ t ∈ T (balance)
    4. pg,t ≤ P̄g   ∀ g ∈ G, t ∈ T (sizes)
    5. pg,t ≤ ag,t   ∀ g ∈ {wind, solar}, t ∈ T (weather)
    6. −R Δt ≤ pcc,t − pcc,t−1 ≤ R Δt   ∀ t ∈ T (ramp)
    7. pnuc,t = P̄nuc   ∀ t ∈ T (nuclear runs flat)

    The solved plan:

    The solved plan, MW, by plant and hour
    MW 17:00 18:00 19:00 20:00
    nuclear 100 100 100 100
    wind 54 59 72 89
    solar 130 70 14 0
    combined-cycle 5 0 0 0
    peaker 0 0 0 0
    unserved 60 115 145 130
    demand 349 344 331 319
    • Symptom. Optimal at $8,700. 60–145 MW unserved every hour, while the combined-cycle plant makes at most 5 MW.
    • Caught by. The units of every parameter: V = 10 $/kWh is $10,000/MWh, yet the model used 10.
    • Also caught by. The duals: every balance dual is $10/MWh, below the $40 of the cheapest gas plant. Unserved demand became the cheapest “plant”.
    • Fix. Convert first: 10 $/kWh × 1,000 kWh per MWh = $10,000/MWh.

    Which number in the solution gives the bug away first?

    1. 60–145 MW unserved while a gas plant idles
    2. Nuclear at 100 MW every hour
    3. Wind at 89 MW at 20:00
    4. No output from the peaker
    Answer

    60–145 MW unserved while a gas plant idles. Demand left unserved while a cheaper plant could run is the first thing to explain.

  2. Nuclear no longer flat (partly worked, about 5 min)

    Optimal at $22,500: $100 less than the right model's $22,600. Nuclear makes 90 MW at 17:00.

    The solved plan, MW, by plant and hour
    MW 17:00 18:00 19:00 20:00
    nuclear 90 100 100 100
    wind 54 59 72 89
    solar 130 70 14 0
    combined-cycle 75 115 145 130
    peaker 0 0 0 0
    unserved 0 0 0 0
    demand 349 344 331 319
    1. c = (10, 0, 0, 40, 100) $/MWh for (nuc, wind, solar, cc, pk) (costs)
    2. min Σt∈T Σg∈G cg pg,t Δt + Σt∈T V ut Δt (objective)
    3. Σg∈G pg,t + ut = dt   ∀ t ∈ T (balance)
    4. pg,t ≤ P̄g   ∀ g ∈ G, t ∈ T (sizes)
    5. pg,t ≤ ag,t   ∀ g ∈ {wind, solar}, t ∈ T (weather)
    6. −R Δt ≤ pcc,t − pcc,t−1 ≤ R Δt   ∀ t ∈ T (ramp)
    7. pnuc,t ≤ P̄nuc   ∀ t ∈ T (nuclear runs flat)

    Which line was changed, and which check catches it: Units of every parameter; The balance, hour by hour; Outputs against what each plant must do; Counting rows?

    Answer

    = became ≤ in line (5). The 17:00 balance dual moves from $0 to $10: one more MWh of demand now raises nuclear from 90 to 91 MW, at $10. Caught by: outputs against what each plant must do.

  3. A plant counted twice (from scratch, about 7 min)

    1. c = (10, 0, 0, 40, 100) $/MWh for (nuc, wind, solar, cc, pk) (costs)
    2. min Σt∈T Σg∈G cg pg,t Δt + Σt∈T V ut Δt (objective)
    3. Σg∈G pg,t + pwind,t + ut = dt   ∀ t ∈ T (balance)
    4. pg,t ≤ P̄g   ∀ g ∈ G, t ∈ T (sizes)
    5. pg,t ≤ ag,t   ∀ g ∈ {wind, solar}, t ∈ T (weather)
    6. −R Δt ≤ pcc,t − pcc,t−1 ≤ R Δt   ∀ t ∈ T (ramp)
    7. pnuc,t = P̄nuc   ∀ t ∈ T (nuclear runs flat)

    The solved plan:

    The solved plan, MW, by plant and hour
    MW 17:00 18:00 19:00 20:00
    nuclear 100 100 100 100
    wind 51.5 59 72 89
    solar 130 70 14 0
    combined-cycle 16 56 73 41
    peaker 0 0 0 0
    unserved 0 0 0 0
    demand 349 344 331 319

    Supply at 19:00, all five plants? Shortfall at 19:00? Which line causes it?

    Answer

    259 MW against 331: 72 MW short, exactly the wind output. The balance line counts wind twice, so the model believes it is balanced.

Check a solution

Before you trust a solution: the balance in an hour, the cost by hand, and the signs and sizes of the duals.

  1. Three checks on the right solution (worked example, about 3 min)

    The solved plan:

    The solved plan, MW, by plant and hour
    MW 17:00 18:00 19:00 20:00
    nuclear 100 100 100 100
    wind 44 59 72 89
    solar 130 70 14 0
    combined-cycle 75 115 145 130
    peaker 0 0 0 0
    unserved 0 0 0 0
    supply 349 344 331 319
    demand 349 344 331 319
    • Balance at 19:00. 100 + 72 + 14 + 145 + 0 = 331 MW, the demand ✓
    • Cost by hand. nuclear 400 MWh × $10 = $4,000; combined-cycle 465 MWh × $40 = $18,600; total $22,600, the solver's objective ✓
    • Duals. $0, $80, $40 and $40 per MWh: all ≥ 0 ✓

    If the peaker made 10 MW at 19:00 in place of 10 MW of combined-cycle output, how much would the cost rise?

    Answer

    10 × ($100 − $40) = $600, which is why the solver leaves the peaker off.

  2. Check the evening, 18:00 to 21:00 (partly worked, about 4 min)

    The combined-cycle plant starts from 65 MW at 17:00, lesson 0's cheapest-first plan.

    The solved plan, MW, by plant and hour
    MW 18:00 19:00 20:00 21:00
    nuclear 100 100 100 100
    wind 59 72 89 98
    solar 70 14 0 0
    combined-cycle 105 145 130 105
    peaker 10 0 0 0
    unserved 0 0 0 0
    demand 344 331 319 303
    • Balance at 18:00. 100 + 59 + 70 + 105 + 10 = 344 MW, the demand ✓
    • Nuclear. 400 MWh × $10 = $4,000
    • Combined-cycle. 485 MWh × $40 = $19,400

    Peaker cost? Total, by hand?

    Answer

    Peaker $1,000. $24,400, the solver's objective too: the model's cost and a hand count agree.

  3. Check the solar dip, 14:00 to 17:00 (from scratch, about 7 min)

    The combined-cycle plant starts from 45 MW at 13:00, lesson 0's cheapest-first plan.

    The solved plan, MW, by plant and hour
    MW 14:00 15:00 16:00 17:00
    nuclear 100 100 100 100
    wind 33 37 47 54
    solar 112 147 161 130
    combined-cycle 85 60 45 65
    peaker 10 0 0 0
    unserved 0 0 0 0
    demand 340 344 353 349

    Supply at 14:00? Cost by hand, all four hours? Your guess for the 14:00 balance dual?

    Answer

    Balanced (340 MW), $15,200 by hand, the solver's objective, and a $100 dual: the peaker is the marginal plant at 14:00. The solver's balance duals: 14:00 $100, 15:00 $40, 16:00 $40 and 17:00 $40 per MWh.

The models are this lesson's dispatch of 3 September 2025, solved by HiGHS in your browser (a precomputed answer if it cannot load). The 65 MW and 45 MW starts are lesson 0's cheapest-first plan at 17:00 and 13:00; the storage and reserve lines are illustrative.

Checks, sources and what’s next

Which check catches which bug

Bug What the solver says Caught by
unit optimal, with the dearest plant running first units of every parameter
sign optimal, with demand unmet in every hour balance, hour by hour
index optimal, balanced at 17:00 only counting rows; balance
double optimal, cost far above a hand calculation a hand-calculated cost
lunch optimal, wind above what the wind allowed outputs against their limits

Next

M1 · From dispatch to locational prices: the linear program behind the market

Sources and further reading

  • EIA. Hourly Electric Grid Monitor (Form EIA-930): the Southwest Power Pool data behind Prairie Town's day, 2025.
  • DeCarolis, J. et al. (2017). Formalizing best practice for energy system optimization modelling. Applied Energy 194.
  • Trutnevyte, E. (2016). Does cost optimization approximate the real-world energy transition? Energy 106.
  • Pyomo, JuMP and HiGHS: the modelling languages and the solver of the Modeler tier.
  • First time with a linear program? Bridge B1, from algebra to a linear program.

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.

© 2026 Honglin Li · Kansas State University · hlli@ksu.edu

 

Last updated: November 2026 · Built with Quarto