Peaky Flexers

Get Flexing

A practical guide to understanding and using the Peaky Flexers electricity market model

← Back to the model

Contents

  1. The Big Picture
  2. Understanding the Inputs
    1. Load Duration Curve Blocks
    2. Renewables Availability Profile (Sub-Blocks)
    3. Demand Tiers & Expandable Demand
    4. Supply-Side Technology Costs
  3. How the Optimisation Works
    1. In Plain Language
    2. The Formal Problem
  4. Reading the Outputs
    1. Market Equilibrium Summary
    2. Optimal Capacity Mix
    3. Input Load Duration Curve
    4. Generation Duration Curve
    5. Price Duration Curve
    6. Demand & Supply by Sub-Block (GW)
    7. Energy by Sub-Block (GWh)
    8. Demand Flexibility (GW)
    9. Energy Transfers (GWh)
    10. Storage Activity
    11. Detailed Sub-Block Results
  5. Using the AI Chat Assistant

1. The Big Picture

Peaky Flexers is a welfare-maximising linear program (LP) for an electricity market. It answers a deceptively simple question: if we had to design an electricity system from scratch, what mix of generation and storage capacity would maximise the total value that consumers get from electricity, minus the cost of providing it?

The model works with five supply-side elements—renewables (zero variable cost), nuclear (firm baseload), gas peakers, battery storage, and transmission & distribution—and a demand side that can flex: consumers can shift demand to cheaper periods, expand consumption when prices are low, or curtail when the cost of supply exceeds the value of the electricity to them.

The key output is a set of market-clearing prices—one for each time period. These prices emerge naturally from the optimisation: they are the shadow prices on the energy-balance constraints, representing the cost to the system of serving one more megawatt-hour of demand in that period. In a well-functioning market, these are the prices that would prevail.

Why does this matter? Understanding how electricity prices form—and what drives them to differ across time periods—is essential for anyone thinking about energy policy, investment in generation or storage, or the economics of demand flexibility.

2. Understanding the Inputs

The model page has four input sections. Each represents a distinct part of the electricity system. Hover over the ⓘ button next to any section heading on the model page to see a condensed version of the guide for that section. Below is the full detail for each input.

Beta access: This beta version of the model may be protected by a simple password gate. If you see the access pop-up, enter the beta password you were given or use the contact link to request access.

2.1 Load Duration Curve Blocks

Real electricity demand varies hour by hour across the year. Rather than modelling all 8,760 hours individually, the model uses a Load Duration Curve (LDC)—a standard tool in energy economics that sorts hours by demand level.

The year is divided into three blocks:

BlockWhat it representsDefault hours
Winter PeakThe coldest, darkest hours when demand is highest300
ShoulderA large middle band—spring, autumn, and milder winter days3,000
Low DemandSummer and overnight hours when demand is lowest and (often) renewables are abundant5,460

You only set the hours for each block. The total should sum to 8,760 (one year). The demand levels come from the tier definitions below.

Intuition: These blocks are not calendar months. Think of them as buckets: all hours with similar demand and weather conditions are grouped together. The Winter Peak block might include just 300 hours spread across December and January; Low Demand captures thousands of hours in summer and at night.

2.2 Renewables Availability Profile (Sub-Blocks)

The wind does not blow constantly during winter, nor does the sun always shine in summer. To capture this intermittency, each LDC block is split into two sub-blocks:

For each sub-block you set two parameters:

ParameterMeaning
% HoursWhat fraction of the block's hours fall in this sub-block (must sum to 100%)
% Renewables AvailabilityWhat fraction of installed renewables capacity is available during these hours

For example, the default Winter Peak is split 10/90: for just 10% of winter peak hours (30 hours), only 15% of installed renewables capacity is available. For the remaining 90% (270 hours), 80% is available. This creates a large price differential between the two sub-blocks, and it is precisely this differential that makes storage valuable within a block—storage can charge when renewables are plentiful and discharge when they are scarce, even within the same season.

Key insight: Without sub-blocks, the model would see each season as uniform, and storage would only be valuable for shifting energy between seasons. Sub-blocks make storage valuable even within a single season—which is how real batteries operate.

2.3 Demand Tiers & Expandable Demand

Not all electricity demand is equally valuable. A hospital's life-support system has a very different willingness to pay than a dishwasher that could run at 3am instead of 6pm. The model captures this by dividing demand in each block into three tiers:

For each tier you set three parameters:

ParameterMeaning
Quantity (GW)How many gigawatts of this tier's demand are present during the block
VoLL (£/MWh)Value of Lost Load: the maximum price this demand is willing to pay. If the clearing price exceeds VoLL, this demand goes unserved ("curtailed").
Shift Cost (£/MWh)The cost of moving this demand to a later, cheaper block. Demand can only shift downward: Winter Peak → Shoulder → Low Demand. It cannot shift upward.

Expandable demand represents new consumption that would switch on if prices fell low enough—think of energy-intensive industries that would locate near cheap power, or electric heating that becomes attractive when electricity prices drop. You specify a quantity (GW) and an activation value (£/MWh). If the clearing price drops below this value, the expandable demand activates.

Intuition: Demand tiers create a downward-sloping demand curve for each block. High-value demand bids high and is served first. Low-value demand may get curtailed if supply is expensive. The shift cost determines when it is worthwhile for demand to move to a cheaper time period rather than be served (or curtailed) in its original block.

2.4 Supply-Side Technology Costs

The model does not pre-set any generation capacities. Instead, it decides how much of each technology to build, balancing capital costs against the value of the electricity they produce. There are five supply-side elements:

Renewables (Zero Variable Cost)

Wind and solar. Once built, they produce electricity at zero fuel cost, but their output depends on weather conditions (captured by the availability profile above). The only input is the annualised capital cost (£/kW/year).

Nuclear

Firm baseload capacity with zero carbon emissions. You set:

Unlike renewables, nuclear is not affected by the renewables availability profile. Its effective capacity in non-peak periods is capacity × (1 − planned outage); during winter peak sub-blocks it is further derated to capacity × (1 − planned outage) × (1 − peak unavailability).

Gas Peaker

A flexible thermal plant that can run whenever needed but burns gas. You set:

Battery Storage

Storage is specified in terms of physical CapEx parameters that are familiar to anyone looking at battery project costs:

The model converts these internally using the capital recovery factor (CRF):

When the discount rate is zero, CRF = 1/n (straight-line). For r > 0, CRF > 1/n, so annual costs reflect the time value of money.

A duration constraint ensures that energy capacity (GWh) = power capacity (GW) × duration (h), so the optimiser determines how much storage to build as a single decision, with the duration as a design parameter.

Because the LDC representation can only track one storage cycle through the sub-block sequence, the model scales the storage energy level constraints by cycles per year. This gives the LP a realistic annual throughput budget (physical energy capacity × cycles) while keeping full annual capital costs in the objective. The result is that the LP makes correct investment decisions: it compares the full annual CapEx against the full annual arbitrage value from repeated cycling.

No fuel cost for storage: Unlike gas, storage has no direct fuel cost. Its "cost" comes from efficiency losses and capital amortisation. The model works this out endogenously—the implied cycling cost is an output, not an input.

Transmission & Distribution (T&D)

T&D capacity represents the cost of the wires, transformers, and infrastructure needed to deliver electricity from generators to consumers. You set a single parameter:

T&D capacity is determined endogenously by the model. The constraint binds at peak total generation dispatched (renewables + gas + storage discharge) across all sub-blocks, so the system must build enough T&D to handle the highest simultaneous power flow.

3. How the Optimisation Works

3.1 In Plain Language

The model asks: what system design and operating pattern makes society best off?

It simultaneously decides:

  1. How much capacity to build for each technology (renewables, nuclear, gas, storage, T&D)
  2. How to dispatch each technology in every sub-block (6 sub-blocks total)
  3. How much demand to serve, shift, or curtail in each tier and sub-block
  4. How to operate storage—when to charge, when to discharge, and how much energy to hold

The objective is to maximise net welfare: the total value that consumers place on the electricity they receive, minus the total cost of providing it (both capital and operating costs).

Think of it as a social planner trying to make the best possible use of available resources. The planner values each MWh of served demand at its VoLL, credits shifted demand at VoLL minus the shift cost, and charges for nuclear and gas generation at their variable costs and all technologies at their capital costs. Internally, the model converts GW × hours into MWh (×1000) and GW/GWh into kW/kWh (×1,000,000), so all welfare and cost outputs are reported in full annual currency units rather than “thousands”.

The optimisation is subject to physical and economic constraints:

The market-clearing prices are not directly chosen. They emerge as shadow prices on the energy-balance constraints—they tell you the marginal value to society of one additional MWh of supply in each sub-block. In an efficient market, these would be the wholesale electricity prices.

3.2 The Formal Problem

For those who want the mathematics, here is the LP formulation. The model maximises:

max   1000 · ∑b,i hb,i · [ ∑t VoLLb,t · servedb,i,t + vbexp · expandb,i − cgasvar · gasb,i ]   +   1000 · ∑shifts hsrc · (VoLLt − shiftcostt) · shift_outsrc,t,dest   −   106 · [ Cren · Kren + Cgas · Kgas + Csto_pw · Ksto_pw + Csto_en · Ksto_en + Ctd · Ktd ]

Where b indexes blocks, i indexes sub-blocks within each block, t indexes demand tiers, h are hours, K are capacity variables, and C are capital costs. Csto_pw and Csto_en are derived from the connection and cell CapEx inputs using the CRF. The factor 1000 converts GWh into MWh in the flow terms; the factor 106 converts GW/GWh into kW/kWh in the capital terms. The variable cost of gas includes any carbon adder: cgasvar = variable_cost + carbon_price × emission_factor.

Subject to (for all sub-blocks b,i):

Shadow prices on the energy-balance constraints, divided by the sub-block's hours, give clearing prices in £/MWh.

4. Reading the Outputs

After you click Optimise the System, the results page shows several sections. Here is what each one tells you.

4.1 Market Equilibrium Summary

A row of metric cards showing the headline results at a glance:

What to look for: If prices are very high in one sub-block, the system is capacity-constrained there. If prices are very similar everywhere, there may be excess capacity or very effective storage/shifting smoothing prices across periods.

4.2 Optimal Capacity Mix

Two charts side by side:

Together, these tell you how the system spends its investment budget. A system dominated by renewables will have high renewables capital cost but zero variable cost. A system with more gas will have lower capital cost but higher variable cost. T&D costs appear as a separate wedge.

4.3 Input Load Duration Curve

This shows the raw demand profile before any optimisation. Sub-blocks are sorted from highest to lowest GW, and the three demand tiers are stacked within each sub-block (low-value at the bottom, high-value at the top). This is what the demand side "looks like" before the model decides what to do with it.

Use this chart as a reference point. After you look at the optimised results, come back here to see how much has changed—how much demand was shifted, curtailed, or served by different sources.

4.4 Generation Duration Curve

This is the post-optimisation counterpart of the input LDC. It shows total generation in each sub-block, broken down by source (renewables in green, gas in red, storage discharge in blue). Sub-blocks are sorted by total generation from left to right.

Hover over any block in the chart to see a pop-out with the sub-block name, total generation, supply stack, and clearing price. Hatched areas indicate curtailed demand.

How to read it: The shape of this curve tells you about the system's economics. If renewables fill most of the curve and gas only appears on the left (high-demand periods), renewables are dominant. If there is a lot of blue (storage discharge) in the high-demand blocks, storage is playing an important peaking role.

4.5 Price Duration Curve

This chart sorts sub-blocks from highest to lowest clearing price, with price on the Y-axis and cumulative hours on the X-axis. Hover over any block to see a pop-out summarising the key activity in that sub-block:

How to read it: The shape of the price duration curve reveals the system's price structure. A steep left-hand side means a few hours of very high prices (scarcity events). A flat right-hand side means many hours at similar (low) prices. The gap between the highest and lowest prices is the maximum arbitrage opportunity for storage and demand shifting.

4.6 Demand & Supply by Sub-Block (GW)

A 2×3 grid of stacked bar charts (one per sub-block). Each chart has two bars:

All six charts share the same Y-axis so you can visually compare the scale of demand and supply across sub-blocks. The title of each chart shows the clearing price.

Storage charging appears as demand (it consumes electricity) while storage discharging appears as supply (it provides electricity). This is physically correct—charging is a load on the system.

4.7 Energy by Sub-Block (GWh)

The same structure as the GW charts, but multiplied by hours to show energy (GWh). Each sub-block has its own Y-axis scale because the blocks have very different durations (300 hours vs. 5,460 hours), which would make the shorter blocks invisible if they shared an axis.

These charts are important for understanding the total energy balance. A sub-block might have low GW but high GWh if it lasts many hours. Storage is particularly visible here: you can see how much energy in GWh is being moved around the system.

4.8 Demand Flexibility (GW)

Per-block Sankey diagrams showing what happens to demand in each block. Left-side nodes are demand sources (tiers + shifted-in demand + storage charging). Right-side nodes are destinations:

The width of each flow band is proportional to the GW. This chart only appears when there is flexibility activity (shifting, curtailment, or storage) in the system.

4.9 Energy Transfers (GWh)

A system-level Sankey diagram showing energy transfers between sub-blocks. This is fundamentally different from the flexibility Sankeys above: while those show what happens within a block, this shows what moves between blocks.

Left nodes are energy exporters (sub-blocks that charge storage or shed demand). Right nodes are energy importers (sub-blocks that discharge storage or receive shifted demand), plus efficiency losses.

The diagram visually distinguishes two types of flows:

This is perhaps the most informative single chart. It reveals the full pattern of energy arbitrage: where is energy coming from, where is it going, and how much is lost to efficiency?

4.10 Storage Activity

Two charts plus summary metrics:

The implied cycling cost is the effective cost per MWh of using storage, calculated from the prices at which it charges and discharges and the efficiency loss. If the average charge price is £65/MWh and discharge price is £120/MWh with 95% efficiency, the implied cost is 65/0.95 − 120 ≈ −£52/MWh (a profit, not a cost). This number tells you whether the price spread is enough to justify the capital investment.

4.11 Detailed Sub-Block Results

The final section gives you the full numerical detail for each of the 6 sub-blocks: every demand tier (available, served, lost, shifted out), every supply technology (dispatched vs available), expandable demand activation, storage level, and the clearing price.

This is where you go to verify specific numbers or understand exactly what is happening in a particular sub-block. If a Sankey diagram shows an unexpected flow, the detail tables will tell you exactly which tiers and technologies are involved.

4.12 Household Bill Optimisation (Optional)

This optional section lets you model a single household as a price-taker in the wholesale market. After the system optimisation determines clearing prices, the household minimises its annual electricity bill given those prices.

Enable it by expanding the “Household Bill Optimisation” section in the inputs and ticking the checkbox. You specify:

The output shows total annual spending (energy cost and battery cost separately), average unit cost (p/kWh), and a per-sub-block breakdown of consumption, curtailment, battery activity, and spend. This is useful for understanding how retail consumers would respond to the wholesale price signals the model produces.

5. Using the AI Chat Assistant

Peaky Flexers includes a built-in AI assistant powered by Anthropic's Claude. Click the AI Chat button in the bottom-right corner to open the chat panel.

What can you ask?

The AI has access to the complete model source code, your current input values, and your latest optimisation results. This means it can reason about your specific scenario—not just generic electricity economics. Good questions include:

Here is an example of the kind of conversation you might have:

Why are Winter Peak prices at £441/MWh? That seems very high.

The price in Winter Peak Low Renewables reflects extreme scarcity. During these 30 hours, only 15% of installed renewables capacity is available. The marginal consumer willing to pay up to their VoLL sets the price.

Looking at the results: all High-value demand (VoLL £15,000/MWh) is served, all Mid-value demand (VoLL £800/MWh) is served, but some Low-value demand (VoLL £100/MWh) may be curtailed or shifted. The clearing price settles between the VoLL of the last tier being served and the marginal cost of the next unit of supply.

Storage is discharging at full power here (if built), and gas peakers are running flat out. The high price is what is needed to justify the capital investment in gas peakers that only run for a few hundred hours per year.

Getting an API key

To use the AI chat, you need an Anthropic API key. The model defaults to Claude Opus 4.6, which provides excellent analysis of the model's economics. To get a key:

  1. Visit Claude API Keys
  2. Create an account (or sign in)
  3. Click Create Key, give it a name, and copy the key
  4. Paste it into the API key field in the chat panel

Your API key is stored in your browser's local storage and is only sent to the Peaky Flexers server to proxy requests to Anthropic. It is never stored on the server.

A note of caution: Claude Opus 4.6 is remarkably good at interpreting the model's results and explaining electricity market economics. However, like all AI models, it can occasionally make mistakes—particularly with complex numerical reasoning or edge cases in the LP formulation. Treat its answers as a knowledgeable colleague's interpretation, not as gospel. If something seems wrong, check the detailed sub-block results tables, or ask the AI to show its working.

The Clear Chat button resets the conversation history, which is useful when you change input parameters and run a new optimisation—the old context will no longer match the new results.

← Back to the model — get flexing!