Basics

This tutorial shows some basic operations that you can do in PowerSystems.jl with your data.

Load Packages

julia> using PowerSystems
       # For displaying subtypes
julia> import TypeTree: tt
julia> docs_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "utils");

Types in PowerSystems

PowerSystems.jl provides a type hierarchy for specifying power system data. Data that describes infrastructure components is held in structs. For example, a Bus is defined as follows with fields for the parameters required to describe a bus (along with an internal field used by InfrastructureSystems to improve the efficiency of handling data).

julia> print_struct(ACBus)mutable struct ACBus
    number::Int64
    name::String
    bustype::Union{Nothing, ACBusTypes}
    angle::Union{Nothing, Float64}
    magnitude::Union{Nothing, Float64}
    voltage_limits::Union{Nothing, @NamedTuple{min::Float64, max::Float64}}
    base_voltage::Union{Nothing, Float64}
    area::Union{Nothing, Area}
    load_zone::Union{Nothing, LoadZone}
    ext::Dict{String, Any}
    internal::InfrastructureSystems.InfrastructureSystemsInternal
end

Type Hierarchy

PowerSystems is intended to organize data containers by the behavior of the devices that the data represents. To that end, a type hierarchy has been defined with several levels of abstract types starting with InfrastructureSystemsType. There are a bunch of subtypes of InfrastructureSystemsType, but the important ones to know about are:

  • Component: includes all elements of power system data
    • Topology: includes non physical elements describing network connectivity
    • Service: includes descriptions of system requirements (other than energy balance)
    • Device: includes descriptions of all the physical devices in a power system
  • InfrastructureSystems.DeviceParameter: includes structs that hold data describing the

dynamic, or economic capabilities of Device.

  • TimeSeriesData: Includes all time series types
    • Forecast: includes structs to define time series of forecasted data where multiple

values can represent each time stamp

  • StaticTimeSeries: includes structs to define time series with a single value for each

time stamp

  • System: collects all of the Components

The following code displays the hierarchy, but concrete types are omitted for brevity:

julia> print(join(tt(PowerSystems.IS.InfrastructureSystemsType, concrete = false), ""))InfrastructureSystems.InfrastructureSystemsType
 ├─ InfrastructureSystems.DeviceParameter
 │   ├─ DynamicComponent
 │   │   ├─ PowerSystems.DynamicGeneratorComponent
 │   │   │   ├─ AVR
 │   │   │   ├─ Machine
 │   │   │   ├─ PSS
 │   │   │   ├─ Shaft
 │   │   │   └─ TurbineGov
 │   │   ├─ PowerSystems.DynamicInverterComponent
 │   │   │   ├─ Converter
 │   │   │   ├─ DCSource
 │   │   │   ├─ Filter
 │   │   │   ├─ FrequencyEstimator
 │   │   │   ├─ InnerControl
 │   │   │   └─ PowerSystems.InverterLimiter
 │   │   └─ PowerSystems.InverterComponent
 │   ├─ PowerSystems.ActivePowerControl
 │   ├─ PowerSystems.OperationalCost
 │   └─ PowerSystems.ReactivePowerControl
 ├─ InfrastructureSystems.InfrastructureSystemsComponent
 │   ├─ Component
 │   │   ├─ Device
 │   │   │   ├─ Branch
 │   │   │   │   ├─ ACBranch
 │   │   │   │   └─ DCBranch
 │   │   │   ├─ DynamicInjection
 │   │   │   └─ StaticInjection
 │   │   │       ├─ ElectricLoad
 │   │   │       │   ├─ ControllableLoad
 │   │   │       │   └─ StaticLoad
 │   │   │       ├─ Generator
 │   │   │       │   ├─ HydroGen
 │   │   │       │   ├─ RenewableGen
 │   │   │       │   └─ ThermalGen
 │   │   │       ├─ StaticInjectionSubsystem
 │   │   │       └─ Storage
 │   │   ├─ Service
 │   │   │   └─ AbstractReserve
 │   │   │       ├─ Reserve
 │   │   │       └─ ReserveNonSpinning
 │   │   └─ Topology
 │   │       ├─ AggregationTopology
 │   │       └─ Bus
 │   └─ TimeSeriesData
 │       ├─ Forecast
 │       │   └─ AbstractDeterministic
 │       └─ StaticTimeSeries
 ├─ InfrastructureSystems.TimeSeriesMetadata
 │   ├─ InfrastructureSystems.ForecastMetadata
 │   └─ InfrastructureSystems.StaticTimeSeriesMetadata
 └─ PowerSystemCaseBuilder.PowerSystemCaseBuilderType
     └─ PowerSystemCaseBuilder.SystemCategory

TimeSeriesData

Read the Docs! Every Component has a time_series_container::InfrastructureSystems.TimeSeriesContainer field. TimeSeriesData are used to hold time series information that describes the temporally dependent data of fields within the same struct. For example, the ThermalStandard.time_series_container field can describe other fields in the struct (available, activepower, reactivepower).

TimeSeriesDatas themselves can take the form of the following:

julia> print(join(tt(TimeSeriesData), ""))TimeSeriesData
 ├─ Forecast
 │   ├─ AbstractDeterministic
 │   │   ├─ Deterministic
 │   │   └─ DeterministicSingleTimeSeries
 │   ├─ Probabilistic
 │   └─ Scenarios
 └─ StaticTimeSeries
     └─ SingleTimeSeries

In each case, the time series contains fields for scaling_factor_multiplier and data to identify the details of th Component field that the time series describes, and the time series data. For example: we commonly want to use a time series to describe the maximum active power capability of a renewable generator. In this case, we can create a SingleTimeSeries with a TimeArray and an accessor function to the maximum active power field in the struct describing the generator. In this way, we can store a scaling factor time series that will get multiplied by the maximum active power rather than the magnitudes of the maximum active power time series.

julia> print_struct(Deterministic)mutable struct Deterministic
    name::String
    data::Union{DataStructures.SortedDict{Dates.DateTime, Vector{Vector{Tuple{Float64, Float64}}}}, DataStructures.SortedDict{Dates.DateTime, Vector{Float64}}, DataStructures.SortedDict{Dates.DateTime, Vector{Tuple{Float64, Float64}}}}
    resolution::Dates.Period
    scaling_factor_multiplier::Union{Nothing, Function}
    internal::InfrastructureSystems.InfrastructureSystemsInternal
end

Examples of how to create and add time series to system can be found in the Add Time Series Example

System

The System object collects all of the individual components into a single struct along with some metadata about the system itself (e.g. base_power)

julia> print_struct(System)mutable struct System
    data::InfrastructureSystems.SystemData
    frequency::Float64
    bus_numbers::Set{Int64}
    runchecks::Base.RefValue{Bool}
    units_settings::InfrastructureSystems.SystemUnitsSettings
    time_series_directory::Union{Nothing, String}
    metadata::PowerSystems.SystemMetadata
    internal::InfrastructureSystems.InfrastructureSystemsInternal
end

Example Code

PowerSystems contains a few basic data files (mostly for testing and demonstration). These can be found here:


julia> include(joinpath(BASE_DIR, "test", "data_5bus_pu.jl")); #.jl file containing 5-bus system data
julia> nodes_5 = nodes5() # function to create 5-bus buses5-element Vector{ACBus}: ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()) ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()) ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()) ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()) ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())
julia> thermal_generators5(nodes_5) # function to create thermal generators in 5-bus buses5-element Vector{ThermalStandard}: ThermalStandard(Alta, true, true, ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 0.4, 0.01, 0.5, (min = 0.0, max = 0.4), (min = -0.3, max = 0.3), nothing, ThreePartCost(VariableCost{Tuple{Float64, Float64}}((0.0, 1400.0)), 0.0, 4.0, 2.0), 100.0, nothing, false, PrimeMovers.ST = 20, ThermalFuels.COAL = 1, Service[], 10000.0, nothing, Dict{String, Any}()) ThermalStandard(Park City, true, true, ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 1.7, 0.2, 2.2125, (min = 0.0, max = 1.7), (min = -1.275, max = 1.275), (up = 2.0, down = 1.0), ThreePartCost(VariableCost{Tuple{Float64, Float64}}((0.0, 1500.0)), 0.0, 1.5, 0.75), 100.0, (up = 0.02, down = 0.02), false, PrimeMovers.ST = 20, ThermalFuels.COAL = 1, Service[], 10000.0, nothing, Dict{String, Any}()) ThermalStandard(Solitude, true, true, ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 5.2, 1.0, 5.2, (min = 0.0, max = 5.2), (min = -3.9, max = 3.9), (up = 3.0, down = 2.0), ThreePartCost(VariableCost{Tuple{Float64, Float64}}((0.0, 3000.0)), 0.0, 3.0, 1.5), 100.0, (up = 0.012, down = 0.012), false, PrimeMovers.ST = 20, ThermalFuels.COAL = 1, Service[], 10000.0, nothing, Dict{String, Any}()) ThermalStandard(Sundance, true, true, ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 2.0, 0.4, 2.5, (min = 0.0, max = 2.0), (min = -1.5, max = 1.5), (up = 2.0, down = 1.0), ThreePartCost(VariableCost{Tuple{Float64, Float64}}((0.0, 4000.0)), 0.0, 4.0, 2.0), 100.0, (up = 0.015, down = 0.015), false, PrimeMovers.ST = 20, ThermalFuels.COAL = 1, Service[], 10000.0, nothing, Dict{String, Any}()) ThermalStandard(Brighton, true, true, ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 6.0, 1.5, 0.75, (min = 0.0, max = 6.0), (min = -4.5, max = 4.5), (up = 5.0, down = 3.0), ThreePartCost(VariableCost{Tuple{Float64, Float64}}((0.0, 1000.0)), 0.0, 1.5, 0.75), 100.0, (up = 0.015, down = 0.015), false, PrimeMovers.ST = 20, ThermalFuels.COAL = 1, Service[], 10000.0, nothing, Dict{String, Any}())
julia> renewable_generators5(nodes_5) # function to create renewable generators in 5-bus buses3-element Vector{RenewableDispatch}: RenewableDispatch(WindBusA, true, ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 2.0, 1.0, 1.2, PrimeMovers.WT = 22, (min = 0.0, max = 0.0), 1.0, TwoPartCost(VariableCost{Float64}(22.0), 0.0), 100.0, Service[], nothing, Dict{String, Any}()) RenewableDispatch(WindBusB, true, ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 2.0, 1.0, 1.2, PrimeMovers.WT = 22, (min = 0.0, max = 0.0), 1.0, TwoPartCost(VariableCost{Float64}(22.0), 0.0), 100.0, Service[], nothing, Dict{String, Any}()) RenewableDispatch(WindBusC, true, ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 1.0, 0.0, 1.2, PrimeMovers.WT = 22, (min = -0.8, max = 0.8), 1.0, TwoPartCost(VariableCost{Float64}(22.0), 0.0), 100.0, Service[], nothing, Dict{String, Any}())
julia> loads5(nodes_5) # function to create the loads3-element Vector{PowerLoad}: PowerLoad(Bus2, true, ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 3.0, 0.9861, 100.0, 3.0, 0.9861, Service[], nothing, Dict{String, Any}()) PowerLoad(Bus3, true, ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 3.0, 0.9861, 100.0, 3.0, 0.9861, Service[], nothing, Dict{String, Any}()) PowerLoad(Bus4, true, ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 4.0, 1.3147, 100.0, 4.0, 1.3147, Service[], nothing, Dict{String, Any}())
julia> branches5(nodes_5) # function to create the branches6-element Vector{Line}: Line(1, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00281, 0.0281, (from = 0.00356, to = 0.00356), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}()) Line(2, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00304, 0.0304, (from = 0.00329, to = 0.00329), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}()) Line(3, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00064, 0.0064, (from = 0.01563, to = 0.01563), 18.812, (min = -0.7, max = 0.7), Service[], Dict{String, Any}()) Line(4, true, 0.0, 0.0, Arc(ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00108, 0.0108, (from = 0.00926, to = 0.00926), 11.148, (min = -0.7, max = 0.7), Service[], Dict{String, Any}()) Line(5, true, 0.0, 0.0, Arc(ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00297, 0.0297, (from = 0.00337, to = 0.00337), 40.53, (min = -0.7, max = 0.7), Service[], Dict{String, Any}()) Line(6, true, 0.0, 0.0, Arc(ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00297, 0.0297, (from = 0.00337, to = 0.00337), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())

Create a System

julia> sys = System(
           100.0,
           nodes_5,
           vcat(
             thermal_generators5(nodes_5),
             renewable_generators5(nodes_5)),
             loads5(nodes_5),
             branches5(nodes_5),
       )System
┌───────────────────┬─────────────┐
│ Property          │ Value       │
├───────────────────┼─────────────┤
│ Name              │             │
│ Description       │             │
│ System Units Base │ SYSTEM_BASE │
│ Base Power        │ 100.0       │
│ Base Frequency    │ 60.0        │
│ Num Components    │ 28          │
└───────────────────┴─────────────┘

Static Components
┌───────────────────┬───────┬────────────────────────┬───────────────┐
│ Type              │ Count │ Has Static Time Series │ Has Forecasts │
├───────────────────┼───────┼────────────────────────┼───────────────┤
│ ACBus             │ 5     │ false                  │ false         │
│ Arc               │ 6     │ false                  │ false         │
│ Line              │ 6     │ false                  │ false         │
│ PowerLoad         │ 3     │ false                  │ false         │
│ RenewableDispatch │ 3     │ false                  │ false         │
│ ThermalStandard   │ 5     │ false                  │ false         │
└───────────────────┴───────┴────────────────────────┴───────────────┘

Accessing System Data

PowerSystems provides functional interfaces to all data. The following examples outline the intended approach to accessing data expressed using PowerSystems.

PowerSystems enforces unique name fields between components of a particular concrete type. So, in order to retrieve a specific component, the user must specify the type of the component along with the name and system

Accessing components

julia> get_component(ACBus, sys, "nodeA")nodeA (ACBus):
   number: 1
   name: nodeA
   bustype: ACBusTypes.PV = 2
   angle: 0.0
   magnitude: 1.0
   voltage_limits: (min = 0.9, max = 1.05)
   base_voltage: 230.0
   area: nothing
   load_zone: nothing
   ext: Dict{String, Any}()
   InfrastructureSystems.SystemUnitsSettings:
      base_value: 100.0
      unit_system: UnitSystem.SYSTEM_BASE = 0
julia> get_component(Line, sys, "1")1 (Line): name: 1 available: true active_power_flow: 0.0 reactive_power_flow: 0.0 arc: nodeA -> nodeB (Arc) r: 0.00281 x: 0.0281 b: (from = 0.00356, to = 0.00356) rate: 2.0 angle_limits: (min = -0.7, max = 0.7) services: 0-element Vector{Service} ext: Dict{String, Any}() time_series_container: InfrastructureSystems.SystemUnitsSettings: base_value: 100.0 unit_system: UnitSystem.SYSTEM_BASE = 0

Similarly, you can access all the components of a particular type: *note: the return type of get_components is a FlattenIteratorWrapper, so call collect to get an Array

julia> get_components(ACBus, sys) |> collect5-element Vector{ACBus}:
 ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())
 ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())
 ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())
 ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())
 ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())

get_components also works on abstract types:

julia> get_components(Branch, sys) |> collect6-element Vector{Branch}:
 Line(4, true, 0.0, 0.0, Arc(ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00108, 0.0108, (from = 0.00926, to = 0.00926), 11.148, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())
 Line(1, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00281, 0.0281, (from = 0.00356, to = 0.00356), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())
 Line(5, true, 0.0, 0.0, Arc(ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00297, 0.0297, (from = 0.00337, to = 0.00337), 40.53, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())
 Line(2, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00304, 0.0304, (from = 0.00329, to = 0.00329), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())
 Line(6, true, 0.0, 0.0, Arc(ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00297, 0.0297, (from = 0.00337, to = 0.00337), 2.0, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())
 Line(3, true, 0.0, 0.0, Arc(ACBus(1, nodeA, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), ACBus(5, nodeE, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}())), 0.00064, 0.0064, (from = 0.01563, to = 0.01563), 18.812, (min = -0.7, max = 0.7), Service[], Dict{String, Any}())

The fields within a component can be accessed using the get_* functions: It's highly recommended that users avoid using the . to access fields since we make no guarantees on the stability field names and locations. We do however promise to keep the accessor functions stable.

julia> bus1 = get_component(ACBus, sys, "nodeA")nodeA (ACBus):
   number: 1
   name: nodeA
   bustype: ACBusTypes.PV = 2
   angle: 0.0
   magnitude: 1.0
   voltage_limits: (min = 0.9, max = 1.05)
   base_voltage: 230.0
   area: nothing
   load_zone: nothing
   ext: Dict{String, Any}()
   InfrastructureSystems.SystemUnitsSettings:
      base_value: 100.0
      unit_system: UnitSystem.SYSTEM_BASE = 0
julia> @show get_name(bus1);get_name(bus1) = "nodeA"
julia> @show get_magnitude(bus1);get_magnitude(bus1) = 1.0

Accessing TimeSeries

First we need to add some time series to the System

julia> loads = collect(get_components(PowerLoad, sys))3-element Vector{PowerLoad}:
 PowerLoad(Bus2, true, ACBus(2, nodeB, ACBusTypes.PQ = 1, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 3.0, 0.9861, 100.0, 3.0, 0.9861, Service[], nothing, Dict{String, Any}())
 PowerLoad(Bus3, true, ACBus(3, nodeC, ACBusTypes.PV = 2, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 3.0, 0.9861, 100.0, 3.0, 0.9861, Service[], nothing, Dict{String, Any}())
 PowerLoad(Bus4, true, ACBus(4, nodeD, ACBusTypes.REF = 3, 0.0, 1.0, (min = 0.9, max = 1.05), 230.0, nothing, nothing, Dict{String, Any}()), 4.0, 1.3147, 100.0, 4.0, 1.3147, Service[], nothing, Dict{String, Any}())
julia> for (l, ts) in zip(loads, load_timeseries_DA[2]) add_time_series!( sys, l, Deterministic( "activepower", Dict(TimeSeries.timestamp(load_timeseries_DA[2][1])[1] => ts), ), ) end

If we want to access a specific time series for a specific component, we need to specify:

  • time series type
  • component
  • initial_time
  • label

We can find the initial time of all the time series in the system:

julia> get_forecast_initial_times(sys)1-element Vector{Dates.DateTime}:
 2024-01-02T00:00:00

We can find the names of all time series attached to a component:

julia> ts_names = get_time_series_names(Deterministic, loads[1])1-element Vector{String}:
 "activepower"

We can access a specific time series for a specific component:

julia> ta = get_time_series_array(Deterministic, loads[1], ts_names[1])24×1 TimeSeries.TimeArray{Float64, 1, Dates.DateTime, SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true}} 2024-01-02T00:00:00 to 2024-01-02T23:00:00
│                     │ A      │
├─────────────────────┼────────┤
│ 2024-01-02T00:00:00 │ 0.8619 │
│ 2024-01-02T01:00:00 │ 0.7563 │
│ 2024-01-02T02:00:00 │ 0.7213 │
│ 2024-01-02T03:00:00 │ 0.7556 │
│ 2024-01-02T04:00:00 │ 0.742  │
│ 2024-01-02T05:00:00 │ 0.7371 │
│ 2024-01-02T06:00:00 │ 0.6978 │
│ 2024-01-02T07:00:00 │ 0.7316 │
│ ⋮                   │ ⋮      │
│ 2024-01-02T17:00:00 │ 0.9628 │
│ 2024-01-02T18:00:00 │ 1.0884 │
│ 2024-01-02T19:00:00 │ 1.0053 │
│ 2024-01-02T20:00:00 │ 1.0273 │
│ 2024-01-02T21:00:00 │ 0.9785 │
│ 2024-01-02T22:00:00 │ 0.9881 │
│ 2024-01-02T23:00:00 │ 0.8704 │

Or, we can just get the values of the time series:

julia> ts = get_time_series_values(Deterministic, loads[1], ts_names[1])24-element view(::Vector{Float64}, 1:24) with eltype Float64:
 0.8619091900311191
 0.7562615234872668
 0.7213328704450518
 0.7555911493370774
 0.7420403391756877
 0.7371278883554542
 0.6978020623521924
 0.7315918736631096
 0.8548315961829335
 0.8117383836194924
 ⋮
 0.8452107796521597
 0.8685974347470509
 0.9627865304180159
 1.0883621760908393
 1.0053077576959464
 1.0272819142080896
 0.9784521624551457
 0.9881302191756894
 0.870399605523601