System

The System is the main container of components and the time series data references. PowerSystems.jl uses a hybrid approach to data storage, where the component data and time series references are stored in volatile memory while the actual time series data is stored in an HDF5 file. This design loads into memory the portions of the data that are relevant at time of the query, and so avoids overwhelming the memory resources.

Accessing components stored in the system

PowerSystems.jl implements a wide variety of methods to search for components to aid in the development of models. The code block shows an example of retrieving components through the type hierarchy with the get_components function and exploiting the type hierarchy for modeling purposes.

The default implementation of the function get_components takes the desired device type (concrete or abstract) and the system and it also accepts filter functions for a more refined search. The container is optimized for iteration over abstract or concrete component types as described by the Type Structure. Given the potential size of the return, PowerSystems.jlreturns Julia iterators in order to avoid unnecessary memory allocations.

thermal_gens = get_components(ThermalStandard, system)
ThermalStandard Counts: 
ThermalStandard: 76

It is also possible to execute get_components with abstract types from the abstract tree. For instance, it is possible to retrieve all renewable generators

thermal_gens = get_components(RenewableGen, system)
RenewableGen Counts: 
RenewableDispatch: 30
RenewableFix: 31

The most common filtering requirement is by component name and for this case the method get_component returns a single component taking the device type, system and name as arguments.

my_thermal_gen = get_component(ThermalStandard, system, "323_CC_1")
323_CC_1 (ThermalStandard):
   name: 323_CC_1
   available: true
   status: true
   bus: COMTE (Bus)
   active_power: 3.55
   reactive_power: 0.3741
   rating: 3.853894134508627
   active_power_limits: (min = 1.7, max = 3.55)
   reactive_power_limits: (min = -0.25, max = 1.5)
   ramp_limits: (up = 0.0414, down = 0.0414)
   operation_cost: ThreePartCost
   base_power: 100.0
   time_limits: nothing
   prime_mover: PrimeMovers.CC = 4
   fuel: ThermalFuels.NATURAL_GAS = 7
   services: 0-element Vector{Service}
   time_at_status: 10000.0
   dynamic_injector: nothing
   ext: Dict{String, Any}()
   time_series_container: InfrastructureSystems.TimeSeriesContainer: 0
   InfrastructureSystems.SystemUnitsSettings:
      base_value: 100.0
      unit_system: UnitSystem.SYSTEM_BASE = 0

Accessing data stored in a component

Using the "dot" access to get a parameter value from a component is actively discouraged, use "getter" functions instead

Using code autogeneration, PowerSystems.jl implements accessor (or "getter") functions to enable the retrieval of parameters defined in the component struct fields. Julia syntax enables access to this data using the "dot" access (e.g. component.field), however this is actively discouraged for two reasons:

  1. We make no guarantees on the stability of component structure definitions. We will maintain version stability on the accessor methods.
  2. Per-unit conversions are made in the return of data from the accessor functions. (see the per-unit section for more details)

For example, the my_thermal_gen.active_power_limits parameter of a thermal generator should be accessed as follows:

get_active_power_limits(my_thermal_gen)
(min = 1.7, max = 3.55)

Per-unit conventions and data conversions

It is often useful to express power systems data in relative terms using per-unit conventions. PowerSystems.jl supports the automatic conversion of data between three different unit systems:

  1. Natural Units: The naturally defined units of each parameter (typically MW).
  2. System Base: Parameter values are divided by the system base_power
  3. Device Base: Parameter values are divided by the device base_mva

To see the unit system setting of a System:

get_units_base(system)
"SYSTEM_BASE"

To change the unit system setting of a System:

set_units_base_system!(system, "DEVICE_BASE")

The units of the parameter values stored in each struct are defined in src/descriptors/power_system_structs.json. Conversion between unit systems does not change the stored parameter values. Instead, unit system conversions are made when accessing parameters using the accessor functions (see above), thus making it imperative to utilize the accessor functions instead of the "dot" accessor methods to ensure the return of the correct values.

JSON Serialization

PowerSystems.jl provides functionality to serialize an entire system to a JSON file and then deserialize it back to a system. The main benefit is that deserializing is significantly faster than reconstructing the system from raw data files.

The function that serializes the system to_json requires the system and a file name

to_json(system, "system.json")

The serialization process stores 3 files

  1. System data file (*.json file)
  2. Validation data file (*.json file)
  3. Time Series data file (*.h5 file)

To deserialize:

system2 = System("system.json")

PowerSystems generates UUIDs for the System and all components in order to have a way to uniquely identify objects. During deserialization it restores the same UUIDs. If you will modify the System or components after deserialization then it is recommended that you set this flag to generate new UUIDs.

system2 = System("system.json", assign_new_uuids = true)

Reducing REPL printing

By default PowerSystems.jl outputs to the REPL all Logging values, this can be overwhelming in some cases. Use configure_logging to create a logger with your preferences (console and/or file, levels, etc.). For more detail refer to Logging.

Example: Set log output to only error messages

using PowerSystems
using Logging
configure_logging(console_level = Logging.Error)

Note: log messages are not automatically flushed to files. Call flush(logger) to make this happen.

Refer to this page for more logging configuration options. Note that it describes how to enable debug logging for some log messages but not others.

Viewing PowerSystems Data in JSON Format

PowerSystems data can be serialized and deserialized in JSON. This section shows how to explore the data outside of Julia using.

system = System("system.json")

It can be useful to view and filter the PowerSystems data in this format. There are many tools available to browse JSON data.

Here is an example GUI tool that is available online in a browser.

The command line utility jq offers even more features. The rest of this document provides example commands.

  • View the entire file pretty-printed
jq . system.json
  • View the PowerSystems component types
jq '.data.components | .[] | .__metadata__ | .type' system.json | sort | uniq
  • View specific components
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard")' system.json
  • Get the count of a component type
# There is almost certainly a better way.
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard")' system.json | grep -c ThermalStandard
  • View specific component by name
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard" and .name == "107_CC_1")' system.json
  • Filter on a field value
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard" and .active_power > 2.3)' system.json
  • View the time series metadata for a component.
jq '.data.components | .[] | select(.__metadata__.type == "RenewableDispatch") | .time_series_container' system.json