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

Model a city’s energy system: an energy hub with grid limits and screening fairness outputs

Write Prairie City’s energy hub as a linear program with a ceiling on each substation, read its duals, let it choose under a CO2 cap, and keep the household estimates apart

Modeler lesson M12 of Energy Systems, Step by Step: a fictional city’s heat pumps, retrofits, district heat, car charging, rooftop solar and batteries in one linear program with a limit on each district’s substation; the limits’ and a CO2 cap’s duals; bills by household group as screening estimates from an accounting layer.
  1. Learn
  2. M12
  • Modeler · L3
  • 45 min guided · 60 min lab · about 2 h practice
  • After M4 and A15 and A13
  • Completed
  1. 1Step by step
  2. 2Explain
  3. 3Check
  4. 4Sources

The lesson in one table: Prairie City's districts, run as one linear program (2025 dollars, illustrative)

Plan Yearly cost against 2025 CO₂ of the districts (a year) Substation upgrades Burden, homes below 80% of area median income (AMI; screening)
2025 as it is $0.0M 1,921,977 t 0 MW 6.1%
Electrify heat and cars −$65.8M 1,527,234 t 91 MW 5.4%
Electrify, managed charging, 40 MW of batteries −$60.5M 1,527,266 t 48 MW 5.5%
The LP's choice, CO₂ ≤ 80% of 2025 −$86.2M 1,537,582 t 5 MW 5.1%

Precomputed with HiGHS on 6 November 2026. Cost includes the cars' fuel and charging, not their prices; equipment and upgrades as yearly payments.

With JavaScript on, you run each plan with a real solver in your browser, read the substations' duals, let the LP choose under a CO₂ cap, and change who adopts first in the household table. Prairie City is fictional; its numbers are illustrative.

  • Illustrative: Prairie City, its three districts, one substation each and its household groups (prairie-city.json); retrofit, district-heat and upgrade costs are set for teaching, fixed here at their defaults (the inputs table lists them; the City Planner changes them).
  • Based on public data: Kansas's 2025 prices (EIA), Wichita's weather normals (NOAA), SPP's 2025 hourly shapes (EIA-930), eGRID's 2023 SPP North CO₂ rate (EPA), DOE LEAD's income bands; heat pumps and rooftop solar from EIA, batteries from NREL, 2025 dollars.
  • Time: eight representative days of 2025, weighted to 365 days; a cold design day and the summer peak day kept. Weather: NOAA's normals on SPP's 2025 days (synthetic).
  • Solver: HiGHS (open source), loaded on your first run (about 3.5 MB, once).

Build it in Python · notebook lab, about 60 minutes, then 120 minutes of practice

The engine's hub with scipy.optimize.linprog and HiGHS.

  • The LP: balances, substation rows and their duals, managed charging, batteries, the heat network.
  • Choosing: the building shares as decisions under a CO₂ cap.
  • After the LP: the household layer.

What it checks: assert cells match the browser's busiest hours, upgrades, costs, CO₂, the duals and the LP's chosen shares.

  1. Download the notebook and the two data files; put them in one folder.
  2. Upload all three to Google Colab (File → Upload notebook, then the folder icon), or open the notebook locally with Python 3, NumPy and SciPy 1.9 or later.
  3. Run all cells, then try the practice tasks at the end.

Notebook (.ipynb) Prairie City (JSON) Engine settings (JSON)

What you just did, as diagrams

The hub
Each district-hour, electricity bought through the substation, rooftop sun and batteries meet the base load, heating and car charging.
Building shares
Heat is split into shares by envelope and heating system, so heating power is linear in the decisions.
The substation's ceiling
Each hour's purchase stays under the limit plus any upgrade; its dual is the value of one more MW of room in that hour.
The cap's dual
When the LP chooses under a CO₂ cap, the cap's dual is the cost of the last tonne cut, under this model's assumptions.
Kept apart
Bills and energy burden by household group come from an accounting layer after the LP, with a stated rule for who adopts first.
Go deeper · ModelerThe hub in symbols

Every hour lasts \(\Delta t = 1\) h, so a MW held for an hour is a MWh. Days \(k\) (8), hours \(h\) (24), districts \(d\) (3).

Symbol What it is Unit Decided or given
\(imp_{dkh}\) bought through district \(d\)’s substation MW decided, \(\ge 0\)
\(pv_{dkh}\), \(ev_{dkh}\) rooftop solar used; car charging (managed) MW decided
\(c_{dkh}\), \(o_{dkh}\), \(q_{dkh}\) battery in, out, stored MW, MW, MWh decided
\(y_{d,e,s}\) share of district \(d\)’s heat in envelope \(e\) (0 as built, 1 retrofitted) with system \(s\) share given in a run; decided in step 6
\(up_d\) upgrade of \(d\)’s substation MW decided
\(w_k\) days day \(k\) stands for (they add to 365) days given
\(p_d\), \(a\) \(d\)’s 2025 electricity price; the upgrade’s yearly cost $/MWh; $ per MW a year given
\(B_{dkh}\), \(Q_{dkh}\) base load; heat needed MW; MW of heat given (prairie-city.json)
\(\sigma\), \(COP_{kh}\) heat a retrofit saves; heat pump’s heat per unit of power share; MWh/MWh given
\(L_d\), \(S_{dkh}\), \(E_{dk}\) substation limit; rooftop output; the day’s charging energy MW; MW; MWh given
\(pl_{kh}\) the heat network’s plant power (core only): its heat pump’s heat \(\div\) 3 MW decided
\(hp_{kh}\), \(boil_{kh}\), \(si_{kh}\), \(so_{kh}\) the network’s heat pump, gas boiler (assumed to exist: fuel only), store in and out MW of heat decided

\[\min\; \sum_k w_k \sum_h \sum_d p_d\, imp_{dkh} \;+\; a \sum_d up_d \;+\; \text{fuel}(y) \;[+\; \text{equipment}(y, \text{sizes})]\]

Each district-hour (the balance; its dual is the marginal cost of one more MWh there):

\[imp + pv + o - c - ev - \sum_{e,s} Q_{dkh}\,(1 - \sigma e)\; y_{d,e,s}\;\kappa_s - [d = \text{core}]\, pl_{kh} = B_{dkh}, \qquad \kappa_{res} = 1,\; \kappa_{hp} = \frac{1}{COP_{kh}},\; \kappa_{fuel} = \kappa_{dh} = 0\]

The heat network in the core (its own heat balance, with 10% lost in the pipes and a store that loses 0.5% an hour):

\[hp_{kh} + boil_{kh} + so_{kh} - si_{kh} = \frac{1}{0.9}\sum_{e} Q_{\text{core},kh}\,(1 - \sigma e)\; y_{\text{core},e,dh}, \qquad pl_{kh} = \frac{hp_{kh}}{3}\]

The substation (its dual: what one more MW of room is worth that hour), the sun, the battery and the day’s charging:

\[imp_{dkh} - up_d \le L_d, \qquad pv_{dkh} \le S_{dkh}, \qquad q_{dkh} = q_{dk,h-1} + 0.85\, c_{dkh} - o_{dkh},\; q_{dk,-1} = q_{dk,23}, \qquad \sum_h ev_{dkh} = E_{dk}\]

When the LP chooses (step 6): \(\sum_{e,s} y_{d,e,s} = 1\), furnaces and resistance no more than in 2025, retrofits and district heat up to their maxima, and \(\text{CO}_2(imp, y) \le cap\). Shares sit inside the LP in percent (0 to 100), which keeps HiGHS’s numbers close in size.

Go deeper · ModelerWhen two answers cost the same: the tie rule

With one price all day, many schedules tie. Small stated costs, left out of every reported number, pick one:

Tie cost Size
Each district's busiest hour $20 a year per MW
The three districts' busiest hour together $10 per MW
Out of a battery $1 per MWh
Out of the heat store $0.50 per MWh
Managed charging $0.10 per MWh × the hour's share of SPP's peak demand
  • The LP minimises the cost plus these small costs: on a few plans it pays under $30 a year, in the engine's test, to keep a busiest hour that is under its limit lower.
  • The engine's test finds the lowest and highest value of each busiest hour, each upgrade and the energy bought over every plan within $1 of the best cost: they agree.
  • The tie costs also enter the balance duals, by a few dollars at most on the busiest hours: read them as "about".
  • The substation duals summed over the year are checked as cost slopes: the cost moves by the same amount when the limit moves 0.1 MW up or down.
Go deeper · ResearcherWhere this model stops
  • One ceiling per substation stands for a whole distribution network; real planning checks each feeder's power flow and voltage (A17).
  • Storage resets every representative day: no carrying heat or charge between days, and no full-year check here.
  • Many plans cost nearly the same; methods that map near-optimal plans show the choice is wider than one optimum.

Check yourself

Electrifying heat only adds yearly kWh; the grid sees a small rise.

  • Myth
  • Fact
Answer

Myth. The limit binds in the coldest night's hours, when heat pumps' COP is lowest and every home heats at once; the yearly total hides that hour.

Where the LP buys an upgrade, the substation's duals summed over the year equal the upgrade's yearly cost per MW.

  • Myth
  • Fact
Answer

Fact. One more MW of limit saves one MW of upgrade; the test checks it as a cost slope both ways.

The LP tells you how a plan changes each household group's energy burden.

  • Myth
  • Fact
Answer

Myth. The LP gives the city's cost, CO₂ and peaks; who pays comes from an accounting layer with its own stated assumptions.

Numbers, sources and what’s next

Inputs the model uses

Input Value Source
Substation limits: core · suburbs · fringe 250 · 230 · 60 MW prairie-city.json: each district's 2025 busiest hour × 1.15, rounded up to the next 10 MW (17%, 20% and 25% above it; teaching)
Electricity, Kansas 2025: homes · businesses 14.44¢ · 11.19¢ per kWh Electric Power Annual, Table 2.10: Average Price of Electricity to Ultimate Customers by End-Use Sector, by State, 2025 and 2024 (EIA)
Gas, Kansas 2025: homes · businesses $14.81 · $11.90 per thousand cubic feet Natural Gas Prices, Kansas (annual) (EIA)
Grid CO₂ 862 lb per MWh, plus 5% losses EPA eGRID2023, SPP North
Heat pump COP, an illustrative curve 2.4 at −15 °C; 3.2 at 0 °C; 1 below −23 °C anchored to DOE's cold-climate challenge target, 2.4 at −15 °C (U.S. Department of Energy, 24 Sep 2021); the rest is the course's curve (lesson F3), with resistance backup assumed below −23 °C
Heat pump, per home $7,355, 15 years EIA AEO2026, residential (2022 dollars, converted)
Rooftop solar $4,738 per kW, 25 years EIA AEO2026, residential (2022 dollars, converted)
Battery, 4 hours $1,371 per kW, 15 years NREL 2025 update (2024 dollars, converted)
Retrofit: cost a home · heat saved · life $9,000 · 18% · 30 years set for teaching (illustrative); fixed here at the defaults: change them in the City Planner or the notebook
Heat network: per home-equivalent · plant heat pump · heat store $12,000 (40 years) · $1,200 per kW of heat, COP 3 (25 years) · $3,000 per MWh (30 years) set for teaching (illustrative); 10% of the heat lost in the pipes; the gas boiler (90%) is assumed to exist already: its fuel is counted, not its construction
Substation upgrade $800 per kW, 40 years set for teaching (illustrative); fixed here at the defaults: change them in the City Planner or the notebook
Managed charging any hours of the same day, at most a sixth of the day's charge in one hour set for teaching: cars plugged in at home or work whenever needed (an upper bound on what managed charging can do)
Yearly payments 4% real, over each item's life lesson 13's rate (NLR ATB 2025)

Keep going

Back to the course map

Related lab: a SciPy/HiGHS notebook that rebuilds engine E3's hub and asserts the browser's numbers, about 60 minutes, then 120 minutes of practice.

Built on and used in

  • M4 (storage and coupled carriers in one LP) and M1 (duals as marginal values).
  • The same engine runs the City Planner and the capstone C3.
  • Open tools for city and regional models: PyPSA, JuMP and Pyomo.

Sources and further reading

  • Geidl and others (2007). Energy hubs for the future. IEEE Power and Energy Magazine 5(1), 24–30.
  • EIA. Electric Power Annual, Table 2.10: average price of electricity by state and sector, 2025.
  • EPA. eGRID summary data, eGRID2023 (revision 2).
  • DOE. Low-Income Energy Affordability Data (LEAD) Tool.
  • EIA. Assumptions to the Annual Energy Outlook 2026: Residential Demand Module, Tables 2–3.
  • Cole, Ramasamy and Turan (2025). Cost Projections for Utility-Scale Battery Storage: 2025 Update. NREL/TP-6A40-93281.
  • Tonn and others (2014). Weatherization Works: Summary of Findings from the Retrospective Evaluation of the U.S. Department of Energy's Weatherization Assistance Program. ORNL/TM-2014/338, Oak Ridge National Laboratory (pp. xiv and 12).
  • HiGHS. Documentation of the open-source solver in your browser and in the notebook (through SciPy's linprog).

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