Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for supplemental attributes #1039

Merged
merged 4 commits into from
Jan 15, 2024
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
28 changes: 28 additions & 0 deletions src/PowerSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export AggregationTopology
export Area
export LoadZone
export get_aggregation_topology_accessor
export SupplementalAttribute
export GeographicInfo

export Component
export Device
Expand Down Expand Up @@ -204,6 +206,11 @@ export PriorityCurrentLimiter
export Source
export PeriodicVariableSource

# Outages
export Outage
export ForcedOutage
export PlannedOutage

export Service
export AbstractReserve
export Reserve
Expand Down Expand Up @@ -241,6 +248,7 @@ export ForecastCache
export StaticTimeSeriesCache
export NormalizationFactor
export NormalizationTypes
export TimeSeriesCounts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to export this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We export get_time_series_counts which returns an instance of this struct. I don’t think a public function should return a private struct. We could argue whether that function should be exported.


export get_dynamic_components

Expand Down Expand Up @@ -282,6 +290,13 @@ export get_forecast_horizon
export get_forecast_initial_timestamp
export get_forecast_interval
export get_forecast_window_count
export add_supplemental_attribute!
export remove_supplemental_attribute!
export remove_supplemental_attributes!
export get_supplemental_attribute
export get_supplemental_attributes
export has_supplemental_attributes
export iterate_supplemental_attributes
export get_time_series
export get_time_series_array
export get_time_series_resolution
Expand Down Expand Up @@ -318,6 +333,8 @@ export CompressionTypes
export get_bus_numbers
export get_name
export set_name!
export get_component_uuids
export get_supplemental_attributes_container
export get_description
export set_description!
export get_base_power
Expand Down Expand Up @@ -420,22 +437,29 @@ import InfrastructureSystems:
Scenarios,
ForecastCache,
StaticTimeSeriesCache,
TimeSeriesCounts,
InfrastructureSystemsComponent,
InfrastructureSystemsType,
InfrastructureSystemsInternal,
SupplementalAttribute,
DeviceParameter,
FlattenIteratorWrapper,
LazyDictFromIterator,
DataFormatError,
InvalidRange,
InvalidValue,
GeographicInfo,
copy_time_series!,
get_count,
get_data,
get_horizon,
get_resolution,
get_window,
get_name,
get_component_uuids,
get_supplemental_attribute,
get_supplemental_attributes,
get_supplemental_attributes_container,
set_name!,
get_internal,
set_internal!,
Expand All @@ -451,6 +475,7 @@ import InfrastructureSystems:
get_percentiles, # Probabilistic Forecast Exports
get_next_time_series_array!,
get_next_time,
has_supplemental_attributes,
get_units_info,
set_units_info!,
to_json,
Expand Down Expand Up @@ -548,6 +573,9 @@ include("models/dynamic_branch.jl")
include("models/supplemental_constructors.jl")
include("models/supplemental_accessors.jl")

# Supplemental attributes
include("outages.jl")

# Definitions of PowerSystem
include("base.jl")
include("data_format_conversions.jl")
Expand Down
154 changes: 136 additions & 18 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ function System(file_path::AbstractString; assign_new_uuids = false, kwargs...)
)
runchecks && check(sys)
if assign_new_uuids
IS.assign_new_uuid!(sys)
IS.assign_new_uuid_internal!(sys)
for component in get_components(Component, sys)
IS.assign_new_uuid!(component)
assign_new_uuid!(sys, component)
end
for component in
IS.get_masked_components(InfrastructureSystemsComponent, sys.data)
IS.assign_new_uuid!(component)
assign_new_uuid!(sys, component)
end
# Note: this does not change UUIDs for time series data because they are
# shared with components.
Expand Down Expand Up @@ -914,11 +914,24 @@ function get_components(
return IS.get_components(T, sys.data, filter_func)
end

# These are helper functions for debugging problems.
# Searches components linearly, and so is slow compared to the other get_component functions
"""
Return a vector of components that are attached to the supplemental attribute.
"""
function get_components(sys::System, attribute::SupplementalAttribute)
return IS.get_components(sys.data, attribute)
end

"""
Get the component by UUID.
"""
get_component(sys::System, uuid::Base.UUID) = IS.get_component(sys.data, uuid)
get_component(sys::System, uuid::String) = IS.get_component(sys.data, Base.UUID(uuid))

"""
Change the UUID of a component.
"""
assign_new_uuid!(sys::System, x::Component) = IS.assign_new_uuid!(sys.data, x)

function _get_components_by_name(abstract_types, data::IS.SystemData, name::AbstractString)
_components = []
for subtype in abstract_types
Expand Down Expand Up @@ -1258,6 +1271,104 @@ function transform_single_time_series!(sys::System, horizon::Int, interval::Date
return
end

"""
Add a supplemental attribute to the component. The attribute may already be attached to a
different component.
"""
function add_supplemental_attribute!(
sys::System,
component::Component,
attribute::IS.SupplementalAttribute,
)
return IS.add_supplemental_attribute!(sys.data, component, attribute)
end

"""
Remove the supplemental attribute from the component. The attribute will be removed from the
system if it is not attached to any other component.
"""
function remove_supplemental_attribute!(
sys::System,
component::Component,
attribute::IS.SupplementalAttribute,
)
return IS.remove_supplemental_attribute!(sys.data, component, attribute)
end

"""
Remove the supplemental attribute from the system and all attached components.
"""
function remove_supplemental_attribute!(sys::System, attribute::IS.SupplementalAttribute)
return IS.remove_supplemental_attribute!(sys.data, attribute)
end

"""
Remove all supplemental attributes with the given type from the system.
"""
function remove_supplemental_attributes!(
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.remove_supplemental_attributes!(T, sys.data)
end

"""
Returns an iterator of supplemental attributes. T can be concrete or abstract.
Call collect on the result if an array is desired.

# Examples
```julia
iter = get_supplemental_attributes(ForcedOutage, sys)
iter = get_supplemental_attributes(Outage, sys)
iter = get_supplemental_attributes(x -> x.forced_outage_rate >= 0.5, ForcedOutage, sys)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a better value to put in this example?

outages = get_supplemental_attributes(ForcedOutage, sys) do outage
x.forced_outage_rate >= 0.5
end
outages = collect(get_supplemental_attributes(ForcedOutage, sys))
```

See also: [`iterate_supplemental_attributes`](@ref)
"""
function get_supplemental_attributes(
filter_func::Function,
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.get_supplemental_attributes(filter_func, T, sys.data)
end

function get_supplemental_attributes(
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.get_supplemental_attributes(T, sys.data)
end

"""
Return the supplemental attribute with the given uuid.

Throws ArgumentError if the attribute is not stored.
"""
function get_supplemental_attribute(sys::System, uuid::Base.UUID)
return IS.get_supplemental_attribute(sys.data, uuid)
end

"""
Iterates over all supplemental_attributes.

# Examples
```julia
for supplemental_attribute in iterate_supplemental_attributes(sys)
@show supplemental_attribute
end
```

See also: [`get_supplemental_attributes`](@ref)
"""
function iterate_supplemental_attributes(sys::System)
return IS.iterate_supplemental_attributes(sys.data)
end

"""
Sanitize component values.
"""
Expand Down Expand Up @@ -1507,19 +1618,22 @@ function deserialize_components!(sys::System, raw)
end

# Run in order based on type composition.
# Bus and AGC instances can have areas and LoadZones.
# Most components have buses.
# Static injection devices can contain dynamic injection devices.
# StaticInjectionSubsystem instances have StaticInjection subcomponents.
# RegulationDevice instances have one StaticInjection subcomponent.
deserialize_and_add!(; include_types = [Area, LoadZone])
deserialize_and_add!(; include_types = [AGC])
deserialize_and_add!(; include_types = [Bus])
deserialize_and_add!(;
include_types = [Arc, Service],
skip_types = [StaticReserveGroup],
)
deserialize_and_add!(; include_types = [Branch], skip_types = [DynamicBranch])
deserialize_and_add!(; include_types = [Branch])
deserialize_and_add!(; include_types = [DynamicBranch])
# Static injection devices can contain dynamic injection devices.
deserialize_and_add!(; include_types = [StaticReserveGroup, DynamicInjection])
# StaticInjectionSubsystem instances have StaticInjection subcomponents.
deserialize_and_add!(; skip_types = [StaticInjectionSubsystem])
deserialize_and_add!(; skip_types = [StaticInjectionSubsystem, RegulationDevice])
deserialize_and_add!()

for subsystem in get_components(StaticInjectionSubsystem, sys)
Expand All @@ -1529,6 +1643,10 @@ function deserialize_components!(sys::System, raw)
IS.mask_component!(sys.data, subcomponent)
end
end

for component in get_components(RegulationDevice, sys)
IS.mask_component!(sys.data, component.device)
end
end

"""
Expand Down Expand Up @@ -1731,9 +1849,7 @@ function handle_component_addition!(sys::System, component::RegulationDevice; kw
copy_time_series!(component, component.device)
if !isnothing(get_component(typeof(component.device), sys, get_name(component.device)))
# This will not be true during deserialization, and so won't run then.
remove_component!(sys, component.device)
# The line above removed the component setting so needs to be added back
set_units_setting!(component.device, component.internal.units_info)
IS.mask_component!(sys.data, component.device; remove_time_series = true)
end
return
end
Expand Down Expand Up @@ -1942,7 +2058,7 @@ function convert_component!(
InfrastructureSystems.TimeSeriesContainer(),
deepcopy(line.internal),
)
IS.assign_new_uuid!(line)
assign_new_uuid!(sys, line)
add_component!(sys, new_line)
copy_time_series!(new_line, line)
remove_component!(sys, line)
Expand All @@ -1951,7 +2067,7 @@ end

"""
Converts a MonitoredLine component to a Line component and replaces the original in the
system
system.
"""
function convert_component!(
sys::System,
Expand Down Expand Up @@ -1984,7 +2100,7 @@ function convert_component!(
InfrastructureSystems.TimeSeriesContainer(),
deepcopy(line.internal),
)
IS.assign_new_uuid!(line)
assign_new_uuid!(sys, line)
add_component!(sys, new_line)
copy_time_series!(new_line, line)
remove_component!(sys, line)
Expand All @@ -1993,7 +2109,7 @@ end

"""
Converts a PowerLoad component to a StandardLoad component and replaces the original in the
system. Does not set any fields in StandardLoad that lack a PowerLoad equivalent
system. Does not set any fields in StandardLoad that lack a PowerLoad equivalent.
"""
function convert_component!(
sys::System,
Expand All @@ -2015,7 +2131,7 @@ function convert_component!(
services = Device[],
time_series_container = InfrastructureSystems.TimeSeriesContainer(),
)
IS.assign_new_uuid!(new_load)
assign_new_uuid!(sys, old_load)
add_component!(sys, new_load)
copy_time_series!(new_load, old_load)
for service in get_services(old_load)
Expand Down Expand Up @@ -2048,7 +2164,9 @@ function _validate_or_skip!(sys, component, skip_validation)
end

"""
Return a tuple of counts of components with time series and total time series and forecasts.
Return an instance of TimeSeriesCounts.

See also: [`TimeSeriesCounts`](@ref)
"""
get_time_series_counts(sys::System) = IS.get_time_series_counts(sys.data)

Expand Down
21 changes: 21 additions & 0 deletions src/descriptors/power_system_structs.json
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,13 @@
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "supplemental_attributes_container",
"comment": "container for supplemental attributes",
"null_value": "InfrastructureSystems.SupplementalAttributesContainer()",
"data_type": "InfrastructureSystems.SupplementalAttributesContainer",
"default": "InfrastructureSystems.SupplementalAttributesContainer()"
},
{
"name": "internal",
"comment": "power system internal reference, do not modify",
Expand Down Expand Up @@ -510,6 +517,13 @@
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "supplemental_attributes_container",
"comment": "container for supplemental attributes",
"null_value": "InfrastructureSystems.SupplementalAttributesContainer()",
"data_type": "InfrastructureSystems.SupplementalAttributesContainer",
"default": "InfrastructureSystems.SupplementalAttributesContainer()"
},
{
"name": "internal",
"comment": "power system internal reference, do not modify",
Expand Down Expand Up @@ -3913,6 +3927,13 @@
"data_type": "InfrastructureSystems.TimeSeriesContainer",
"default": "InfrastructureSystems.TimeSeriesContainer()"
},
{
"name": "supplemental_attributes_container",
"comment": "container for supplemental attributes",
"null_value": "InfrastructureSystems.SupplementalAttributesContainer()",
"data_type": "InfrastructureSystems.SupplementalAttributesContainer",
"default": "InfrastructureSystems.SupplementalAttributesContainer()"
},
{
"name": "internal",
"comment": "power system internal reference, do not modify",
Expand Down
Loading
Loading