Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 52 additions & 27 deletions src/InfrastructureSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,66 +40,91 @@ using DocStringExtensions
# Do not add export statements.

"""
Base type for any struct in the Sienna packages.
All structs must implement a kwarg-only constructor to allow deserializing from a Dict.
Root abstract type for all structs defined in Sienna packages.

All concrete subtypes must implement a keyword-argument-only constructor so they can be
deserialized from a `Dict` via [`deserialize`](@ref) and [`serialize`](@ref).

See also: [`InfrastructureSystemsComponent`](@ref), [`DeviceParameter`](@ref),
[`SupplementalAttribute`](@ref)
"""
abstract type InfrastructureSystemsType end

"""
Base type for structs that are stored in a system.
Base type for structs that are stored in a system as top-level members.

Components are added with [`add_component!`](@ref) and retrieved with
[`get_component`](@ref) and [`get_components`](@ref). Each component carries an
[`InfrastructureSystemsInternal`](@ref) instance for identity and optional extension data.

Required interface functions for subtypes:

Note: InfrastructureSystems provides default implementations for these methods that
depend on the struct field names `name` and `internal`.
If subtypes have different field names, they must implement these methods.
- get_name()
- set_name_internal!()
- get_internal()
- [`get_name`](@ref)
- [`set_name_internal!`](@ref)
- [`get_internal`](@ref)

Warning: Subtypes should not implement the function
set_name!(::InfrastructureSystemsComponent, name).
InfrastructureSystems uses the component name in internal data structures, so it is not
safe to change the name of a component after it has been added to a system.
InfrastructureSystems provides set_name!(data::SystemData, component, name) for this
purpose.
Warning: Subtypes should not implement [`set_name!`](@ref) on the component type directly.
InfrastructureSystems uses the component name in internal data structures, so it is not
safe to change the name of a component after it has been added to a system.
Rename attached components through [`SystemData`](@ref) instead.

Optional interface functions:

Subtypes must implement this method. The default throws a `NotImplementedError`.
- get_available()
Subtypes must implement this method. The default throws a `NotImplementedError`.
- set_available!()
Required only if callers use [`get_available_components`](@ref) or
[`get_available_component`](@ref); otherwise the defaults throw `NotImplementedError`.
- [`get_available`](@ref)
- [`set_available!`](@ref)
Comment thread
kdayday marked this conversation as resolved.

Subtypes may contain time series and be associated with supplemental attributes.
Those behaviors can be modified with these methods:
- supports_supplemental_attributes()
- supports_time_series()
- [`supports_supplemental_attributes`](@ref)
- [`supports_time_series`](@ref)

See also: [`DeviceParameter`](@ref), [`SupplementalAttribute`](@ref),
[`ComponentContainer`](@ref)
"""
abstract type InfrastructureSystemsComponent <: InfrastructureSystemsType end

"""
Base type for auxillary structs. These should not be stored in a system.
Base type for auxiliary structs that describe the dynamic, economic, or financial
characteristics of an [`InfrastructureSystemsComponent`](@ref).

Unlike components, `DeviceParameter` subtypes are not added to a system with
[`add_component!`](@ref). They are stored as nested fields on components or on other
`DeviceParameter` subtypes. This decoupling lets the same physical component carry
different parameter sets depending on the modeling context.

Downstream packages define concrete subtypes for domain-specific data, such as
operational cost representations, dynamic machine sub-models, and inverter control schemes.

See also: [`InfrastructureSystemsType`](@ref), [`InfrastructureSystemsComponent`](@ref)
"""
abstract type DeviceParameter <: InfrastructureSystemsType end

"""
Base type for structs that store supplemental attributes
Base type for structs that store supplemental attributes attached to components.

Unlike [`InfrastructureSystemsComponent`](@ref)s, supplemental attributes are not stored in
[`SystemData`](@ref) component containers. They are owned by
[`SupplementalAttributeManager`](@ref) and linked to components through
[`SupplementalAttributeAssociations`](@ref).

Required interface functions for subtypes:

- get_internal()
- [`get_internal`](@ref)

Optional interface functions:

- get_uuid()

Subtypes may contain time series. Which requires
- [`get_uuid`](@ref)
- [`supports_time_series`](@ref)

- `supports_time_series(::SupplementalAttribute)`

All subtypes must include an instance of ComponentUUIDs in order to track
All subtypes must include an instance of [`ComponentUUIDs`](@ref) in order to track
components attached to each attribute.

See also: [`SupplementalAttributeManager`](@ref), [`add_supplemental_attribute!`](@ref)
"""
abstract type SupplementalAttribute <: InfrastructureSystemsType end

Expand Down
40 changes: 34 additions & 6 deletions src/abstract_time_series.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""
Abstract type for time_series that are stored in a system.
Users never create them or get access to them.
Stores references to TimeSeriesData.
Metadata describing a time series attached to a [`TimeSeriesOwners`](@ref) instance.

Users do not construct metadata directly. It is created by [`add_time_series!`](@ref) and
used internally to locate [`TimeSeriesData`](@ref) in [`TimeSeriesStorage`](@ref).

See also: [`ForecastMetadata`](@ref), [`StaticTimeSeriesMetadata`](@ref)
"""
abstract type TimeSeriesMetadata <: InfrastructureSystemsType end

Expand All @@ -26,8 +29,22 @@ function make_features_string(; features...)
return JSON3.write(data)
end

"""
Metadata for forecast (multi-window) time series.

Concrete subtypes are generated from descriptors (for example,
[`DeterministicMetadata`](@ref), [`ScenariosMetadata`](@ref)).

See also: [`TimeSeriesMetadata`](@ref), [`Forecast`](@ref)
"""
abstract type ForecastMetadata <: TimeSeriesMetadata end

"""
Metadata for static (single-window) time series.

See also: [`TimeSeriesMetadata`](@ref), [`StaticTimeSeries`](@ref),
[`SingleTimeSeriesMetadata`](@ref)
"""
abstract type StaticTimeSeriesMetadata <: TimeSeriesMetadata end

get_interval(::StaticTimeSeriesMetadata) = nothing
Expand All @@ -41,9 +58,20 @@ function get_horizon_count(metadata::ForecastMetadata)
end

"""
Abstract type for time series stored in the system.
Components store references to these through TimeSeriesMetadata values so that data can
reside on storage media instead of memory.
Abstract type for time series arrays stored outside component structs.

Components and [`SupplementalAttribute`](@ref)s hold [`TimeSeriesMetadata`](@ref)
references so large arrays can live in [`TimeSeriesStorage`](@ref) instead of memory.

Required interface for subtypes:
- `Base.length`
- `check_time_series_data`
- `get_resolution`
- `make_time_array`
- `eltype_data`

See also: [`TimeSeriesManager`](@ref), [`get_time_series`](@ref), [`Forecast`](@ref),
[`StaticTimeSeries`](@ref)
"""
abstract type TimeSeriesData <: InfrastructureSystemsType end

Expand Down
13 changes: 7 additions & 6 deletions src/component_container.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""
A data structure that acts like a container of components. The `ComponentContainer`
interface consists of:
- `get_components`
- `get_component`
- `get_available_components`
- `get_available_component`
Abstract type for containers of [`InfrastructureSystemsComponent`](@ref)s.

The `ComponentContainer` interface consists of:
- [`get_components`](@ref)
- [`get_component`](@ref)
- [`get_available_components`](@ref)
- [`get_available_component`](@ref)

Notable subtypes include [`Components`](@ref), [`SystemData`](@ref), and
[`PowerSystems.System`](@extref).
Expand Down
6 changes: 6 additions & 0 deletions src/component_uuids.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# This is an abstraction of a Set in order to enable de-serialization of supplemental
# attributes.

"""
Set-like storage of component UUIDs attached to a [`SupplementalAttribute`](@ref).

Supplemental attribute subtypes include a `ComponentUUIDs` field so associations can be
tracked and serialized without storing full component references.
"""
struct ComponentUUIDs <: InfrastructureSystemsType
uuids::Set{Base.UUID}

Expand Down
22 changes: 17 additions & 5 deletions src/components.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const ComponentsByType = Dict{DataType, Dict{String, <:InfrastructureSystemsComponent}}

"A simple container for components and time series data."
"""
Concrete [`ComponentContainer`](@ref) backing regular and masked component storage in
[`SystemData`](@ref).

Components are indexed by concrete type and name. Name uniqueness is enforced per type
when adding with [`add_component!`](@ref).
"""
struct Components <: ComponentContainer
data::ComponentsByType
time_series_manager::TimeSeriesManager
Expand Down Expand Up @@ -55,12 +61,18 @@ function _add_component!(
end

"""
Add a component.
Add a component to a [`Components`](@ref) container.

Validates field ranges when validation descriptors are configured and rejects components
that already carry time series unless `allow_existing_time_series` is set.

# Throws

Throws ArgumentError if the component's name is already stored for its concrete type.
- `ArgumentError` if the component name is already stored for its concrete type, if the
type is not concrete, or if the component already has time series.
- `InvalidValue` if field validation fails.

Throws InvalidRange if any of the component's field values are outside of defined valid
range.
See also: [`add_component!`](@ref) on [`SystemData`](@ref)
"""
function add_component!(
components::Components,
Expand Down
8 changes: 8 additions & 0 deletions src/containers.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
"""
Parent abstract type for top-level containers stored in a [`SystemData`](@ref) instance.

Notable specializations include [`Components`](@ref), [`SystemData`](@ref), and
[`SupplementalAttributeManager`](@ref). Component storage uses the [`ComponentContainer`](@ref)
interface. Containers expose their members through package-specific query methods rather
than direct field access.
"""
Comment thread
kdayday marked this conversation as resolved.
abstract type InfrastructureSystemsContainer <: InfrastructureSystemsType end

get_display_string(x::InfrastructureSystemsContainer) = string(nameof(typeof(x)))
Expand Down
15 changes: 14 additions & 1 deletion src/internal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,26 @@ end
serialize(val::SystemUnitsSettings) = serialize_struct(val)
deserialize(T::Type{<:SystemUnitsSettings}, val::Dict) = deserialize_struct(T, val)

"""
References to system-level managers wired into attached components and attributes.

When a component or [`SupplementalAttribute`](@ref) is attached to a [`SystemData`](@ref)
instance, [`add_component!`](@ref) and [`add_supplemental_attribute!`](@ref) store a
`SharedSystemReferences` in its [`InfrastructureSystemsInternal`](@ref) so time series and
supplemental-attribute operations can reach the owning [`TimeSeriesManager`](@ref) and
[`SupplementalAttributeManager`](@ref) without passing the system explicitly.
"""
@kwdef struct SharedSystemReferences <: InfrastructureSystemsType
supplemental_attribute_manager::Any = nothing
time_series_manager::Any = nothing
end

"""
Internal storage common to InfrastructureSystems types.
Internal storage common to [`InfrastructureSystemsType`](@ref)s.

Every component and supplemental attribute carries a UUID, optional
[`SharedSystemReferences`](@ref) when attached to a system, optional unit metadata, and an
optional user extension dictionary accessed through [`get_ext`](@ref).
"""
mutable struct InfrastructureSystemsInternal <: InfrastructureSystemsType
uuid::Base.UUID
Expand Down
40 changes: 31 additions & 9 deletions src/serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ const CONSTRUCT_WITH_PARAMETERS_KEY = "construct_with_parameters"
const FUNCTION_KEY = "function"

"""
Serializes a InfrastructureSystemsType to a JSON file.
Write an [`InfrastructureSystemsType`](@ref) to a JSON file.

This is a convenience wrapper around [`serialize`](@ref) and JSON encoding. For
[`SystemData`](@ref), call [`prepare_for_serialization_to_file!`](@ref) first so time series
sidecar paths are recorded.

See also: [`from_json`](@ref), [`serialize`](@ref)
"""
function to_json(
obj::T,
Expand All @@ -27,7 +33,9 @@ function to_json(
end

"""
Serializes a InfrastructureSystemsType to a JSON string.
Return a JSON string for an [`InfrastructureSystemsType`](@ref).

See also: [`serialize`](@ref), [`from_json`](@ref)
"""
Comment thread
kdayday marked this conversation as resolved.
function to_json(obj::T; pretty = false, indent = 2) where {T <: InfrastructureSystemsType}
try
Expand Down Expand Up @@ -61,7 +69,9 @@ function to_json(
end

"""
Deserializes a InfrastructureSystemsType from a JSON filename.
Read an [`InfrastructureSystemsType`](@ref) from a JSON file.

See also: [`deserialize`](@ref), [`to_json`](@ref)
"""
Comment thread
kdayday marked this conversation as resolved.
function from_json(::Type{T}, filename::String) where {T <: InfrastructureSystemsType}
return open(filename) do io
Expand All @@ -70,16 +80,23 @@ function from_json(::Type{T}, filename::String) where {T <: InfrastructureSystem
end

"""
Deserializes a InfrastructureSystemsType from String or IO.
Read an [`InfrastructureSystemsType`](@ref) from a JSON string or IO stream.

See also: [`deserialize`](@ref)
"""
Comment thread
kdayday marked this conversation as resolved.
function from_json(io::Union{IO, String}, ::Type{T}) where {T <: InfrastructureSystemsType}
return deserialize(T, JSON3.read(io, Dict))
end

"""
Serialize the Julia value into standard types that can be converted to non-Julia formats,
such as JSON. In cases where val is an instance of a struct, return a Dict. In cases where
val is a scalar value, return that value.
Convert an [`InfrastructureSystemsType`](@ref) into JSON-compatible `Dict`s and scalars.

Generic structs are encoded as `Dict`s with [`add_serialization_metadata!`](@ref) type
information so [`deserialize`](@ref) can reconstruct them. For [`SystemData`](@ref),
[`serialize(::SystemData)`](@ref) additionally writes time series sidecar files when
[`prepare_for_serialization_to_file!`](@ref) has been called.

See also: [`to_dict`](@ref), [`to_json`](@ref)
"""
function serialize(val::T) where {T <: InfrastructureSystemsType}
@debug "serialize InfrastructureSystemsType" _group = LOG_GROUP_SERIALIZATION val T
Expand Down Expand Up @@ -156,8 +173,13 @@ serialize(val::Base.RefValue{T}) where {T} = serialize(val[])
serialize(val::T) where {T} = deepcopy(val)

"""
Deserialize an object from standard types stored in non-Julia formats, such as JSON, into
Julia types.
Reconstruct an [`InfrastructureSystemsType`](@ref) from serialized `Dict` data.

For [`SystemData`](@ref), downstream packages must deserialize individual components
separately after the container is loaded because component types are defined outside
InfrastructureSystems.

See also: [`serialize`](@ref), [`from_json`](@ref)
"""
function deserialize(::Type{T}, data::Dict) where {T <: InfrastructureSystemsType}
@debug "deserialize InfrastructureSystemsType" _group = LOG_GROUP_SERIALIZATION T data
Expand Down
11 changes: 11 additions & 0 deletions src/supplemental_attribute_associations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ mutable struct SupplementalAttributeAssociations
# If you add any fields, ensure they are managed in deepcopy_internal below.
end

"""
SQLite-backed store linking [`SupplementalAttribute`](@ref)s to
[`InfrastructureSystemsComponent`](@ref)s.

Owned by [`SupplementalAttributeManager`](@ref). Associations are serialized into the
system JSON file rather than a separate sidecar database.

See also: [`add_supplemental_attribute!`](@ref), [`list_associated_component_uuids`](@ref)
"""
SupplementalAttributeAssociations

"""
Construct a new SupplementalAttributeAssociations with an in-memory database.
"""
Expand Down
Loading
Loading