Parse Time Series Data from .csv's

This example shows how to parse time series data from .csv files to add to a System. For example, a System created by parsing a MATPOWER file doesn't contain any time series data, so a user may want to add time series to be able to run a production cost model.

Let's use a predefined 5-bus System with some renewable generators and loads that we want to add time-series data to:

julia> sysSystem
┌───────────────────┬─────────────┐
│ Property          │ Value       │
├───────────────────┼─────────────┤
│ Name              │             │
│ Description       │             │
│ System Units Base │ SYSTEM_BASE │
│ Base Power        │ 100.0       │
│ Base Frequency    │ 60.0        │
│ Num Components    │ 30          │
└───────────────────┴─────────────┘

Static Components
┌──────────────────────────┬───────┐
│ Type                     │ Count │
├──────────────────────────┼───────┤
│ ACBus                    │ 5     │
│ Arc                      │ 6     │
│ Area                     │ 1     │
│ Line                     │ 5     │
│ LoadZone                 │ 1     │
│ PhaseShiftingTransformer │ 2     │
│ PowerLoad                │ 3     │
│ RenewableDispatch        │ 2     │
│ ThermalStandard          │ 5     │
└──────────────────────────┴───────┘

Define pointers to time series files

PowerSystems requires a metadata file that maps components to their time series data in order to be able to automatically construct time_series from .csv data files.

For example, if we want to add a bunch of time series files, say one for each load and one for each renewable generator, we need to define pointers to each time series .csv file with the following fields:

  • simulation: User description of simulation
  • resolution: Resolution of time series in seconds
  • module: Module that defines the abstract type of the component
  • category: Type of component. Must map to abstract types defined by the "module" entry (Bus, ElectricLoad, Generator, LoadZone, Reserve)
  • component_name: Name of component
  • name: User-defined name for the time series data.
  • normalization_factor: Controls normalization of the data. Use 1.0 for pre-normalized data. Use 'Max' to divide the time series by the max value in the column. Use any float for a custom scaling factor.
  • scaling_factor_multiplier_module: Module that defines the accessor function for the scaling factor
  • scaling_factor_multiplier: Accessor function of the scaling factor
  • data_file: Path to the time series data file

Notes:

  • The module, category, and component_name entries must be valid arguments to retrieve a component using get_component(${module}.${category}, sys, $name).
  • The scaling_factor_multiplier_module and the scaling_factor_multiplier entries must be sufficient to return the scaling factor data using ${scaling_factor_multiplier_module}.${scaling_factor_multiplier}(component).

PowerSystems supports this metadata in either CSV or JSON formats.

In this example, we will use the JSON format. The example file can be found here, and this is what its pointers look like in the required format:

[
    {
        "simulation": "DAY_AHEAD",
        "resolution": 3600,
        "category": "Generator",
        "component_name": "SolarBusC",
        "module": "PowerSystems",
        "type": "SingleTimeSeries",
        "name": "max_active_power",
        "scaling_factor_multiplier": "get_max_active_power",
        "scaling_factor_multiplier_module": "PowerSystems",
        "normalization_factor": 1,
        "data_file": "./gen/Renewable/PV/da_solar5.csv"
    },
    {
        "simulation": "DAY_AHEAD",
        "resolution": 3600,
        "category": "Generator",
        "component_name": "WindBusA",
        "module": "PowerSystems",
        "type": "SingleTimeSeries",
        "name": "max_active_power",
        "scaling_factor_multiplier": "get_max_active_power",
        "scaling_factor_multiplier_module": "PowerSystems",
        "normalization_factor": 1,
        "data_file": "./gen/Renewable/WIND/da_wind5.csv"
    },
    {
        "simulation": "DAY_AHEAD",
        "resolution": 3600,
        "category": "ElectricLoad",
        "component_name": "bus2",
        "module": "PowerSystems",
        "type": "SingleTimeSeries",
        "name": "max_active_power",
        "scaling_factor_multiplier": "get_max_active_power",
        "scaling_factor_multiplier_module": "PowerSystems",
        "normalization_factor": 1,
        "data_file": "./load/da_load5.csv"
    },
    {
        "simulation": "DAY_AHEAD",
        "resolution": 3600,
        "category": "ElectricLoad",
        "component_name": "bus3",
        "module": "PowerSystems",
        "type": "SingleTimeSeries",
        "name": "max_active_power",
        "scaling_factor_multiplier": "get_max_active_power",
        "scaling_factor_multiplier_module": "PowerSystems",
        "normalization_factor": 1,
        "data_file": "./load/da_load5.csv"
    },
    {
        "simulation": "DAY_AHEAD",
        "resolution": 3600,
        "category": "ElectricLoad",
        "component_name": "bus4",
        "module": "PowerSystems",
        "type": "SingleTimeSeries",
        "name": "max_active_power",
        "scaling_factor_multiplier": "get_max_active_power",
        "scaling_factor_multiplier_module": "PowerSystems",
        "normalization_factor": 1,
        "data_file": "./load/da_load5.csv"
    }
]

Read and assign time series to System using these parameters.

julia> fname = joinpath(FORECASTS_DIR, "timeseries_pointers_da.json")"/home/runner/.julia/artifacts/afb608473cf4d5eb22147856de1a1a651f36d40b/PowerSystemsTestData-3.1/5-Bus/5bus_ts/timeseries_pointers_da.json"
julia> add_time_series!(sys, fname)5-element Vector{TimeSeriesKey}: StaticTimeSeriesKey(SingleTimeSeries, "max_active_power", Dates.DateTime("2024-10-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}()) StaticTimeSeriesKey(SingleTimeSeries, "max_active_power", Dates.DateTime("2024-10-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}()) StaticTimeSeriesKey(SingleTimeSeries, "max_active_power", Dates.DateTime("2024-10-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}()) StaticTimeSeriesKey(SingleTimeSeries, "max_active_power", Dates.DateTime("2024-10-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}()) StaticTimeSeriesKey(SingleTimeSeries, "max_active_power", Dates.DateTime("2024-10-01T00:00:00"), Dates.Millisecond(3600000), 24, Dict{String, Any}())

You can print the System to see a new table summarizing the time series data that has been added:

julia> sysSystem
┌───────────────────┬─────────────┐
│ Property          │ Value       │
├───────────────────┼─────────────┤
│ Name              │             │
│ Description       │             │
│ System Units Base │ SYSTEM_BASE │
│ Base Power        │ 100.0       │
│ Base Frequency    │ 60.0        │
│ Num Components    │ 30          │
└───────────────────┴─────────────┘

Static Components
┌──────────────────────────┬───────┐
│ Type                     │ Count │
├──────────────────────────┼───────┤
│ ACBus                    │ 5     │
│ Arc                      │ 6     │
│ Area                     │ 1     │
│ Line                     │ 5     │
│ LoadZone                 │ 1     │
│ PhaseShiftingTransformer │ 2     │
│ PowerLoad                │ 3     │
│ RenewableDispatch        │ 2     │
│ ThermalStandard          │ 5     │
└──────────────────────────┴───────┘

Time Series Summary
┌───────────────────┬────────────────┬──────────────────┬───────────────────────
│ owner_type        │ owner_category │ time_series_type │ time_series_category ⋯
│ String            │ String         │ String           │ String               ⋯
├───────────────────┼────────────────┼──────────────────┼───────────────────────
│ PowerLoad         │ Component      │ SingleTimeSeries │ StaticTimeSeries     ⋯
│ RenewableDispatch │ Component      │ SingleTimeSeries │ StaticTimeSeries     ⋯
└───────────────────┴────────────────┴──────────────────┴───────────────────────
                                                               3 columns omitted

See also: