Add Time Series Fuel Cost Data

This how-to guide demonstrates how to add time-varying fuel costs to a thermal generator that uses a ThermalGenerationCost with a FuelCurve. This is useful when fuel prices vary over time, such as with natural gas prices that change throughout the day or across seasons.

Overview

This guide assumes you have already defined a System with a thermal generator (e.g., ThermalStandard) that has a ThermalGenerationCost containing a FuelCurve. The generator's FuelCurve must specify a heat rate curve (fuel consumption at different power outputs) and an initial scalar fuel cost value, which will be replaced with time series data.

To add time-varying fuel costs, you need to:

  1. Create time series fuel cost data: Prepare your fuel price data as either SingleTimeSeries (for simple time-varying data like historical prices) or Deterministic (for forecast windows used in day-ahead scheduling with rolling horizons).

  2. Attach the time series to the generator: Use the set_fuel_cost! function to attach the time series data to the generator component. The component must already be added to the system before attaching time series.

  3. Verify and retrieve the data: Use get_fuel_cost to retrieve the time series data and verify it was attached correctly.

Key requirements:

  • The generator must use a FuelCurve (not a CostCurve) in its ThermalGenerationCost to enable time series fuel costs
  • Time series resolution should match your simulation resolution (e.g., Hour(1) for hourly simulations)
  • Fuel cost units should be in $/GJ (or $/MBtu, etc.) and heat rate in GJ/MWh (or MBtu/MWh); their product gives the effective cost in $/MWh

Step 1: Create Time Series Fuel Cost Data

Create time series data representing fuel costs that vary throughout the day. This example uses hourly natural gas prices with SingleTimeSeries:

julia> # Define the initial time and resolution
       initial_time = DateTime("2024-01-01T00:00:00")2024-01-01T00:00:00
julia> resolution = Hour(1)1 hour
julia> # Create hourly fuel cost data for 24 hours # Prices are higher during peak hours (midday to early evening) and lower at night fuel_cost_data = [ 4.5, 4.3, 4.2, 4.1, 4.2, 4.5, # 00:00 - 05:00 (low overnight prices) 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, # 06:00 - 11:00 (morning ramp) 8.0, 8.0, 7.8, 7.8, 7.5, 7.0, # 12:00 - 17:00 (afternoon peak) 6.5, 6.0, 5.5, 5.0, 4.8, 4.6, # 18:00 - 23:00 (evening decline) ]24-element Vector{Float64}: 4.5 4.3 4.2 4.1 4.2 4.5 5.0 5.5 6.0 6.5 ⋮ 7.8 7.5 7.0 6.5 6.0 5.5 5.0 4.8 4.6
julia> # Create timestamps for each data point timestamps = collect(initial_time:resolution:(initial_time + Hour(length(fuel_cost_data) - 1)))24-element Vector{Dates.DateTime}: 2024-01-01T00:00:00 2024-01-01T01:00:00 2024-01-01T02:00:00 2024-01-01T03:00:00 2024-01-01T04:00:00 2024-01-01T05:00:00 2024-01-01T06:00:00 2024-01-01T07:00:00 2024-01-01T08:00:00 2024-01-01T09:00:00 ⋮ 2024-01-01T15:00:00 2024-01-01T16:00:00 2024-01-01T17:00:00 2024-01-01T18:00:00 2024-01-01T19:00:00 2024-01-01T20:00:00 2024-01-01T21:00:00 2024-01-01T22:00:00 2024-01-01T23:00:00
julia> # Create a TimeArray with timestamps and data time_array = TimeArray(timestamps, fuel_cost_data)24×1 TimeSeries.TimeArray{Float64, 1, Dates.DateTime, Vector{Float64}} 2024-01-01T00:00:00 to 2024-01-01T23:00:00 ┌─────────────────────┬─────┐ │ │ A │ ├─────────────────────┼─────┤ │ 2024-01-01T00:00:00 │ 4.5 │ │ 2024-01-01T01:00:00 │ 4.3 │ │ 2024-01-01T02:00:00 │ 4.2 │ │ 2024-01-01T03:00:00 │ 4.1 │ │ 2024-01-01T04:00:00 │ 4.2 │ │ 2024-01-01T05:00:00 │ 4.5 │ │ 2024-01-01T06:00:00 │ 5.0 │ │ 2024-01-01T07:00:00 │ 5.5 │ │ ⋮ │ ⋮ │ │ 2024-01-01T17:00:00 │ 7.0 │ │ 2024-01-01T18:00:00 │ 6.5 │ │ 2024-01-01T19:00:00 │ 6.0 │ │ 2024-01-01T20:00:00 │ 5.5 │ │ 2024-01-01T21:00:00 │ 5.0 │ │ 2024-01-01T22:00:00 │ 4.8 │ │ 2024-01-01T23:00:00 │ 4.6 │ └─────────────────────┴─────┘ 9 rows omitted
julia> # Create a SingleTimeSeries from the TimeArray fuel_cost_timeseries = SingleTimeSeries(; name = "fuel_cost", data = time_array, )SingleTimeSeries("fuel_cost", 24×1 TimeSeries.TimeArray{Float64, 1, Dates.DateTime, Vector{Float64}} 2024-01-01T00:00:00 to 2024-01-01T23:00:00, Dates.Millisecond(3600000), nothing, InfrastructureSystems.InfrastructureSystemsInternal(Base.UUID("a4a8b398-c728-4710-8649-e5370ea22805"), nothing, nothing, nothing))

Step 2: Attach Time Series to the Generator

Use the set_fuel_cost! function to attach the time series data to your previously defined System and generator (e.g., ThermalStandard):

julia> # Add the time series fuel cost to the generator
       set_fuel_cost!(sys, generator, fuel_cost_timeseries)FuelCurve:
  value_curve: PiecewisePointCurve (a type of InputOutputCurve) where function is: piecewise linear y = f(x) connecting points:
    (x = 100.0, y = 7.0)
    (x = 200.0, y = 8.0)
    (x = 300.0, y = 9.5)
  power_units: UnitSystem.NATURAL_UNITS = 2
  fuel_cost: StaticTimeSeriesKey(SingleTimeSeries, "fuel_cost", Dates.DateTime("2024-01-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}())
  startup_fuel_offtake: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
  vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0

Step 3: Verify and Retrieve Time Series Data

Now the generator has time-varying fuel costs. You can retrieve the time series data:

julia> # Get the fuel cost time series starting at the initial time
       fuel_forecast = get_fuel_cost(generator; start_time = initial_time)24×1 TimeSeries.TimeArray{Float64, 1, Dates.DateTime, Vector{Float64}} 2024-01-01T00:00:00 to 2024-01-01T23:00:00
┌─────────────────────┬─────┐
│                     │ A   │
├─────────────────────┼─────┤
│ 2024-01-01T00:00:00 │ 4.5 │
│ 2024-01-01T01:00:00 │ 4.3 │
│ 2024-01-01T02:00:00 │ 4.2 │
│ 2024-01-01T03:00:00 │ 4.1 │
│ 2024-01-01T04:00:00 │ 4.2 │
│ 2024-01-01T05:00:00 │ 4.5 │
│ 2024-01-01T06:00:00 │ 5.0 │
│ 2024-01-01T07:00:00 │ 5.5 │
│          ⋮          │  ⋮  │
│ 2024-01-01T17:00:00 │ 7.0 │
│ 2024-01-01T18:00:00 │ 6.5 │
│ 2024-01-01T19:00:00 │ 6.0 │
│ 2024-01-01T20:00:00 │ 5.5 │
│ 2024-01-01T21:00:00 │ 5.0 │
│ 2024-01-01T22:00:00 │ 4.8 │
│ 2024-01-01T23:00:00 │ 4.6 │
└─────────────────────┴─────┘
               9 rows omitted
julia> # Display the first few values first(TimeSeries.values(fuel_forecast), 6)6-element Vector{Float64}: 4.5 4.3 4.2 4.1 4.2 4.5

You can also query for a specific time window:

julia> # Get fuel costs for a specific 12-hour period starting at 6 AM
       morning_time = DateTime("2024-01-01T06:00:00")2024-01-01T06:00:00
julia> fuel_forecast_morning = get_fuel_cost(generator; start_time = morning_time, len = 12)12×1 TimeSeries.TimeArray{Float64, 1, Dates.DateTime, Vector{Float64}} 2024-01-01T06:00:00 to 2024-01-01T17:00:00 ┌─────────────────────┬─────┐ │ │ A │ ├─────────────────────┼─────┤ │ 2024-01-01T06:00:00 │ 5.0 │ │ 2024-01-01T07:00:00 │ 5.5 │ │ 2024-01-01T08:00:00 │ 6.0 │ │ 2024-01-01T09:00:00 │ 6.5 │ │ 2024-01-01T10:00:00 │ 7.0 │ │ 2024-01-01T11:00:00 │ 7.5 │ │ 2024-01-01T12:00:00 │ 8.0 │ │ 2024-01-01T13:00:00 │ 8.0 │ │ 2024-01-01T14:00:00 │ 7.8 │ │ 2024-01-01T15:00:00 │ 7.8 │ │ 2024-01-01T16:00:00 │ 7.5 │ │ 2024-01-01T17:00:00 │ 7.0 │ └─────────────────────┴─────┘
julia> # Display these values TimeSeries.values(fuel_forecast_morning)12-element Vector{Float64}: 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.0 7.8 7.8 7.5 7.0

See Also