Skip to content
julia
begin
    using AustralianElectricityMarkets
    using PowerSystems
    using PowerSimulations
    using HydroPowerSimulations

    using Chain
    using DataFrames
    using AlgebraOfGraphics, CairoMakie
    using TidierDB
    using Dates
    using HiGHS
end

Market Clearing

In the NEM, generators submit bids consisting of up to 10 price-quantity bands for each 5-minute dispatch interval. Prices can range from the market floor (currently -1,000/MWh) to the market price cap (currently 17,500/MWh).

The following section demonstrates the definition of a market clearing problem, where all units in the NEM need to to be dispatched according to their energy bids to meet the aggregate demand at each region. In this example, we still ignore network constraints to simplify the problem, and adopt a "Copper Plate" formulation.

Setup the system

Initialise a connection to manage the market data via duckdb

Get the data first!

You will first need to download the data from the monthly archive, saving them locally in parquet files.

julia
tables = table_requirements(RegionalNetworkConfiguration())
map(tables) do table
    fetch_table_data(table, date_range)
end;

Only the data requirements for a RegionalNetworkConfiguration are downloaded.

julia
db = aem_connect(duckdb());

Instantiate the system

julia
sys = nem_system(db, RegionalNetworkConfiguration())
System
Property Value
Name
Description
System Units Base SYSTEM_BASE
Base Power 100.0
Base Frequency 60.0
Num Components 602
Static Components
Type Count
ACBus 12
Arc 12
Area 6
AreaInterchange 8
EnergyReservoirStorage 31
HydroDispatch 84
Line 14
PowerLoad 6
RenewableDispatch 222
ThermalStandard 199
TransmissionInterface 8

Set the horizon to consider for the simulation

julia
interval = Minute(5)
horizon = Hour(24)
start_date = DateTime(2025, 1, 2, 4, 0)
date_range = start_date:interval:(start_date + horizon)
@show date_range
Dates.DateTime("2025-01-02T04:00:00"):Dates.Minute(5):Dates.DateTime("2025-01-03T04:00:00")

Set deterministic time series

julia
set_demand!(sys, db, date_range; resolution = interval)
set_renewable_pv!(sys, db, date_range; resolution = interval)
set_renewable_wind!(sys, db, date_range; resolution = interval)
set_hydro_limits!(sys, db, date_range; resolution = interval)
set_market_bids!(sys, db, date_range)
[ Info: Setting loads to 0 for SNOWY1 Load
[ Info: Setting PV power time series
[ Info: Setting wind power time series
[ Info: Setting loads to 0 for EILDON3
[ Info: Setting loads to 0 for HLMSEW01
[ Info: Setting loads to 0 for PINDARI
[ Info: Setting loads to 0 for PALOONA
[ Info: Setting loads to 0 for KEEPIT
[ Info: Setting loads to 0 for RUBICON
[ Info: Setting loads to 0 for COPTNHYD
[ Info: Setting loads to 0 for PUMP2
[ Info: Setting loads to 0 for WYANGALA
[ Info: Setting loads to 0 for YWNGAHYD
[ Info: Setting loads to 0 for CLOVER
[ Info: Setting loads to 0 for ROWALLAN
[ Info: Setting loads to 0 for GUTHNL1
[ Info: Setting loads to 0 for GLENMAG1
[ Info: Setting loads to 0 for WYANGALB
[ Info: Setting loads to 0 for BROWNMT
[ Info: Setting loads to 0 for L_W_CNL1
[ Info: Setting loads to 0 for MURAYNL3
[ Info: Setting loads to 0 for BURRIN
[ Info: Setting loads to 0 for CLUNY
[ Info: Setting loads to 0 for PUMP1
[ Info: Setting loads to 0 for REPULSE
[ Info: Setting loads to 0 for KAREEYA5
[ Info: Setting loads to 0 for PO110NL1
[ Info: Setting loads to 0 for TUMT3NL2
[ Info: Setting loads to 0 for WYA252B1
[ Info: Setting loads to 0 for GLBWNHYD
[ Info: Setting loads to 0 for JOUNAMA1
[ Info: Setting loads to 0 for JNDABNE1
[ Info: Setting loads to 0 for SNOWYGJP
[ Info: Setting loads to 0 for GOVILLB1
[ Info: Setting loads to 0 for BAPS
[ Info: Setting loads to 0 for TUMT3NL1
[ Info: Setting loads to 0 for TRIBNL1
[ Info: Setting loads to 0 for THEDROP1
[ Info: Setting loads to 0 for ADPMH1
[ Info: Setting loads to 0 for MURAYNL2
[ Info: Setting loads to 0 for BUTLERSG
[ Info: Setting loads to 0 for TUMT3NL3
[ Info: Setting loads to 0 for BDONGHYD
[ Info: Setting loads to 0 for WILLHOV1
[ Info: Setting loads to 0 for MURAYNL1
[ Info: Setting loads to 0 for WYB252B1
Warning: No bid data for generator APPIN, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator SHEP1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WINGF1_1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator DRYCNL, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator SNUGNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator STGEORG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BOLIVAR1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GROSV1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CALLNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BBASEHOS, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TAHMOOR1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CLAYTON, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TORNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TOWER, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TABMILL2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator VICMILL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator EASTCRK, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TGNSS1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TATURA01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HALAMRD1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator JACKSGUL, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MORANBAH, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HASTING1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator VPNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GRANGEAV, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TARNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ERNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator EASTCRK2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GLADNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WILGB01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator YWNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LUCAS2S2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GERMCRK, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LIDDNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MINTNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator OAKY2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MPNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WINGF2_1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator RPCG, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LYNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator STAPYLTON1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HASTING3, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WESTCBT1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WILGAPK, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWWDG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BPLANDF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator INVICTA, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ERGT01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MBAHNTH, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator OAKYCREK, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WDLNGN01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWWDG2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WOLLERT1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TATIARA1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WESTILL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BROOKLYN, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BWTR1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ICSM, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PIONEER, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LUCASHGT, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GB01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWWBG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TITREE, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GLENNCRK, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GROSV2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator RACOMIL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LONGFORD, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CONDONG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BOWWDG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HASTING2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator STANNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator SHOAL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CULLRGWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ROYALLA1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GRIFSF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MLWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BARCSF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PORTWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator NASF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWWPV1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CODRNGTON, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator YSWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TOORAWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator VALDORA1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MLSP1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWWPV2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CHALLHWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WHILL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CESF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator DIAPURWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator FSWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WOOLNTH1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MAROOWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ADPPV2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CHPSTWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WONWP, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator SKSF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BAKING1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HUGSF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TIMWEST, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator LRSF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator YAMBUKWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WAUBRAWF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HEPWIND1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator YAWWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ADPPV3, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CBWF1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CAPTL_WF, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator EILDON3, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator HLMSEW01, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PINDARI, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PALOONA, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator KEEPIT, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator RUBICON, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator COPTNHYD, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PUMP2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WYANGALA, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator YWNGAHYD, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CLOVER, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ROWALLAN, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GUTHNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GLENMAG1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WYANGALB, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BROWNMT, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator L_W_CNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MURAYNL3, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BURRIN, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator CLUNY, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PUMP1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator REPULSE, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator KAREEYA5, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator PO110NL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TUMT3NL2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WYA252B1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GLBWNHYD, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator JOUNAMA1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator JNDABNE1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator SNOWYGJP, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator GOVILLB1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BAPS, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TUMT3NL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TRIBNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator THEDROP1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator ADPMH1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MURAYNL2, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BUTLERSG, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator TUMT3NL3, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator BDONGHYD, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WILLHOV1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator MURAYNL1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator WYB252B1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:490
Warning: No bid data for generator KESSB1, setting to unavailable.
@ AustralianElectricityMarkets ~/work/AustralianElectricityMarkets.jl/AustralianElectricityMarkets.jl/src/parser.jl:531

Derive forecasts from the deterministic time series

julia
transform_single_time_series!(
    sys,
    horizon, # horizon
    interval, # interval
);

@show sys
System
Property Value
Name
Description
System Units Base SYSTEM_BASE
Base Power 100.0
Base Frequency 60.0
Num Components 602
Static Components
Type Count
ACBus 12
Arc 12
Area 6
AreaInterchange 8
EnergyReservoirStorage 31
HydroDispatch 84
Line 14
PowerLoad 6
RenewableDispatch 222
ThermalStandard 199
TransmissionInterface 8
StaticTimeSeries Summary
owner_type owner_category name time_series_type initial_timestamp resolution count time_step_count
String String String String String Dates.CompoundPeriod Int64 Int64
HydroDispatch Component max_active_power SingleTimeSeries 2025-01-02T04:00:00 5 minutes 84 288
PowerLoad Component max_active_power SingleTimeSeries 2025-01-02T04:00:00 5 minutes 6 288
RenewableDispatch Component max_active_power SingleTimeSeries 2025-01-02T04:00:00 5 minutes 222 288
Forecast Summary
owner_type owner_category name time_series_type initial_timestamp resolution count horizon interval window_count
String String String String String Dates.CompoundPeriod Int64 Dates.CompoundPeriod Dates.CompoundPeriod Int64
EnergyReservoirStorage Component decremental_initial_input Deterministic 2025-01-02T04:00:00 5 minutes 30 1 day empty period 1
EnergyReservoirStorage Component decremental_variable_cost Deterministic 2025-01-02T04:00:00 5 minutes 30 1 day empty period 1
EnergyReservoirStorage Component incremental_initial_input Deterministic 2025-01-02T04:00:00 5 minutes 30 1 day empty period 1
EnergyReservoirStorage Component variable_cost Deterministic 2025-01-02T04:00:00 5 minutes 30 1 day empty period 1
HydroDispatch Component incremental_initial_input Deterministic 2025-01-02T04:00:00 5 minutes 41 1 day empty period 1
HydroDispatch Component max_active_power DeterministicSingleTimeSeries 2025-01-02T04:00:00 5 minutes 84 1 day 5 minutes 1
HydroDispatch Component variable_cost Deterministic 2025-01-02T04:00:00 5 minutes 41 1 day empty period 1
PowerLoad Component max_active_power DeterministicSingleTimeSeries 2025-01-02T04:00:00 5 minutes 6 1 day 5 minutes 1
RenewableDispatch Component incremental_initial_input Deterministic 2025-01-02T04:00:00 5 minutes 186 1 day empty period 1
RenewableDispatch Component max_active_power DeterministicSingleTimeSeries 2025-01-02T04:00:00 5 minutes 222 1 day 5 minutes 1
RenewableDispatch Component variable_cost Deterministic 2025-01-02T04:00:00 5 minutes 186 1 day empty period 1
ThermalStandard Component incremental_initial_input Deterministic 2025-01-02T04:00:00 5 minutes 127 1 day empty period 1
ThermalStandard Component variable_cost Deterministic 2025-01-02T04:00:00 5 minutes 127 1 day empty period 1

Define the problem

julia
begin
    template = ProblemTemplate()
    set_device_model!(template, Line, StaticBranch)
    set_device_model!(template, PowerLoad, StaticPowerLoad)
    set_device_model!(template, RenewableDispatch, RenewableFullDispatch)
    set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment)
    set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver)
    set_network_model!(template, NetworkModel(CopperPlatePowerModel))
    template
end
Network Model
Network Model PowerSimulations.CopperPlatePowerModel
Slacks false
PTDF false
Duals None
HVDC Network Model None
Device Models
Device Type Formulation Slacks
PowerSystems.ThermalStandard PowerSimulations.ThermalBasicUnitCommitment false
PowerSystems.PowerLoad PowerSimulations.StaticPowerLoad false
PowerSystems.RenewableDispatch PowerSimulations.RenewableFullDispatch false
PowerSystems.HydroDispatch HydroPowerSimulations.HydroDispatchRunOfRiver false
Branch Models
Branch Type Formulation Slacks
PowerSystems.Line PowerSimulations.StaticBranch false

The dispatch problem will be solved with open source solver HiGHS, and a relatively large mip gap for the purposes of this example.

julia
solver = optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.05)


problem = DecisionModel(template, sys; optimizer = solver, horizon = horizon)
build!(problem; output_dir = joinpath(tempdir(), "out"))
InfrastructureSystems.Optimization.ModelBuildStatusModule.ModelBuildStatus.BUILT = 0

Solve the problem

julia
solve!(problem)
InfrastructureSystems.Simulation.RunStatusModule.RunStatus.SUCCESSFULLY_FINALIZED = 0

Observe the results

julia
res = OptimizationProblemResults(problem)

Start: 2025-01-02T04:00:00

End: 2025-01-03T03:55:00

Resolution: 5 minutes

PowerSimulations Problem Auxiliary variables Results
TimeDurationOff__ThermalStandard
TimeDurationOn__ThermalStandard
HydroEnergyOutput__HydroDispatch
PowerSimulations Problem Expressions Results
ProductionCostExpression__ThermalStandard
ProductionCostExpression__HydroDispatch
ActivePowerBalance__System
ProductionCostExpression__RenewableDispatch
PowerSimulations Problem Parameters Results
IncrementalPiecewiseLinearSlopeParameter__RenewableDispatch
ActivePowerTimeSeriesParameter__HydroDispatch
ActivePowerTimeSeriesParameter__PowerLoad
ActivePowerTimeSeriesParameter__RenewableDispatch
IncrementalPiecewiseLinearBreakpointParameter__RenewableDispatch
IncrementalPiecewiseLinearBreakpointParameter__ThermalStandard
IncrementalPiecewiseLinearBreakpointParameter__HydroDispatch
IncrementalPiecewiseLinearSlopeParameter__ThermalStandard
IncrementalCostAtMinParameter__ThermalStandard
IncrementalPiecewiseLinearSlopeParameter__HydroDispatch
PowerSimulations Problem Variables Results
ActivePowerVariable__RenewableDispatch
ActivePowerVariable__ThermalStandard
ActivePowerVariable__HydroDispatch
OnVariable__ThermalStandard
StopVariable__ThermalStandard
StartVariable__ThermalStandard

Let's observe how the units are dispatched

julia
begin

    function filter_non_all_zero(df, group_by, value)
        gdf = groupby(df, group_by)
        is_all_zero = combine(gdf, :value => (x -> all(x == 0)) => :all_zero)
        subset!(is_all_zero, :all_zero => x -> .!x)
        return innerjoin(df, is_all_zero, on = group_by)
    end

    renewables = read_variable(res, "ActivePowerVariable__RenewableDispatch")
    thermal = read_variable(res, "ActivePowerVariable__ThermalStandard")
    hydro = read_variable(res, "ActivePowerVariable__HydroDispatch")
    gens_long = vcat(renewables, thermal, hydro)
    select!(gens_long, :DateTime, :name => :DUID, :value)

    by_fuel = @chain select(
        read_units(db),
        [:DUID, :STATIONID, :CO2E_ENERGY_SOURCE, :REGIONID]
    ) begin
        rightjoin(gens_long, on = :DUID)
        groupby([:CO2E_ENERGY_SOURCE, :REGIONID, :DateTime])
        combine(:value => sum => :value)
        dropmissing!
        select!(
            :DateTime, :REGIONID, :CO2E_ENERGY_SOURCE => :Source,
            :value
        )
        filter_non_all_zero([:REGIONID, :Source], :value)
    end


    loads = @chain res begin
        read_parameter("ActivePowerTimeSeriesParameter__PowerLoad")
        transform!(
            :name => ByRow(x -> split(x, " ")[1]) => :REGIONID
        )
        subset!(:REGIONID => ByRow(!=("SNOWY1")))
        insertcols!(
            :Source => "Region demand"
        )
        select!(
            :DateTime, :REGIONID, :Source,
            :value => ByRow(-) => :value
        )
    end


    demand = data(loads) * mapping(
        :DateTime, :value, color = :Source, layout = :REGIONID
    ) * visual(Lines, linestyle = (:dash, :dense))
    generation = data(by_fuel) * mapping(
        :DateTime, :value, color = :Source, layout = :REGIONID
    ) * visual(Lines)

    draw(
        demand + generation;
        figure = (; size = (1000, 800)),
        legend = (; position = :bottom)
    )
end

Let's observe the dispatch of a few thermal generators

julia
begin
    thermals_non_zero = filter_non_all_zero(thermal, :name, :value)
    sample = first(unique(thermals_non_zero.name), 5)
    sample = subset!(thermals_non_zero, :name => ByRow(in(sample)))
    spec = data(sample) * mapping(:DateTime, :value, color = :name) * visual(Lines)
    draw(spec; figure = (; size = (500, 500)))
end

Let's observe the dispatch of a few renewable generators

julia
begin
    renewables_non_zero = filter_non_all_zero(renewables, :name, :value)
    sample = first(unique(renewables_non_zero.name), 5)
    sample = subset!(renewables_non_zero, :name => ByRow(in(sample)))
    data(sample) * mapping(:DateTime, :value, color = :name) * visual(Lines) |> draw
end

Notice that most solar generators are actually not dispatched during the day here even though the solar output is definitely non-zero.

julia
begin
    ren = get_component(RenewableDispatch, sys, "COLEASF1")
    ts = get_time_series_array(Deterministic, ren, "max_active_power") |> DataFrame
    index, values = ts.timestamp, ts.A * 100
    fig = Figure()
    ax = Axis(fig[1, 1], xlabel = "timestamp", title = "Max active power [MW]", ylabel = "MW")
    lines!(index, values; label = "COLEASF1")
    axislegend(ax)
    fig
end

This was not observed in the Economic dispatch example, and many factors can explain this behaviour. For instance:

  • Negative Bidding: In the NEM, many generators (especially coal) have high "cycling costs": it is expensive for them to turn off and restart. To avoid this, they often bid at very low or even negative prices, ensuring they are dispatched even when demand is low or renewables are abundant.

  • Contractual Obligations: Some generators may have hedged their risk with future contracts, requiring them to generate regardless of the spot price.

  • Strategic Behavior: The 10-band bidding system allows for complex strategies that simple cost-minimization models do not capture.