Skip to content

Commit

Permalink
Merge pull request #1197 from NREL-Sienna/gks/td/component_selector_port
Browse files Browse the repository at this point in the history
Add `ComponentSelector` feature: PSY portion (take two)
  • Loading branch information
jd-lara authored Jan 19, 2025
2 parents 5bfab88 + 4e70698 commit 21160e7
Show file tree
Hide file tree
Showing 10 changed files with 758 additions and 44 deletions.
4 changes: 2 additions & 2 deletions docs/src/api/public.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ Filter = t -> nameof(t) in names(PowerSystems)

```@autodocs
Modules = [PowerSystems]
Pages = ["base.jl"]
Pages = ["get_components_interface.jl", "base.jl", "component_selector.jl"]
Public = true
Private = false
Filter = t -> t ∈ [System]
```

```@autodocs
Modules = [PowerSystems]
Pages = ["base.jl"]
Pages = ["get_components_interface.jl", "base.jl", "component_selector.jl"]
Public = true
Private = false
Filter = t -> t ∉ [System]
Expand Down
33 changes: 32 additions & 1 deletion src/PowerSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ export get_components
export show_components
export get_subcomponents
export get_components_by_name
export get_available_component
export get_available_components
export get_existing_device_types
export get_existing_component_types
Expand Down Expand Up @@ -492,6 +493,17 @@ export generate_struct_file
export generate_struct_files
export UnitSystem # internal.jl

# ComponentSelector
export ComponentSelector
export SingularComponentSelector
export PluralComponentSelector
export DynamicallyGroupedComponentSelector
export subtype_to_string
export component_to_qualified_string
export make_selector
export rebuild_selector
export get_groups
export get_available_groups
#################################################################################
# Imports

Expand Down Expand Up @@ -609,7 +621,21 @@ import InfrastructureSystems:
get_raw_data_type,
supports_time_series,
supports_supplemental_attributes,
fast_deepcopy_system
fast_deepcopy_system,
ComponentSelector,
SingularComponentSelector,
PluralComponentSelector,
DynamicallyGroupedComponentSelector,
NameComponentSelector,
ListComponentSelector,
TypeComponentSelector,
FilterComponentSelector,
RegroupedComponentSelector,
component_to_qualified_string,
subtype_to_string,
COMPONENT_NAME_DELIMITER,
make_selector,
rebuild_selector
import InfrastructureSystems:
ValueCurve,
InputOutputCurve,
Expand Down Expand Up @@ -654,6 +680,9 @@ provide a constructor that allows existing values to be deserialized.
"""
abstract type Component <: IS.InfrastructureSystemsComponent end

"Get whether this component is available for simulation or not."
get_available(::Component) = true

""" Supertype for "devices" (bus, line, etc.) """
abstract type Device <: Component end

Expand Down Expand Up @@ -724,7 +753,9 @@ include("outages.jl")
# Definitions of PowerSystem
include("base.jl")
include("subsystems.jl")
include("component_selector.jl")
include("data_format_conversions.jl")
include("get_components_interface.jl")

#Data Checks
include("utils/IO/system_checks.jl")
Expand Down
53 changes: 15 additions & 38 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ sys = System(100.0; compression = CompressionSettings(
sys = System(100.0; time_series_in_memory = true)
```
"""
struct System <: IS.InfrastructureSystemsType
struct System <: IS.ComponentContainer
data::IS.SystemData
frequency::Float64 # [Hz]
bus_numbers::Set{Int}
Expand Down Expand Up @@ -1128,7 +1128,11 @@ See [`get_components_by_name`](@ref) for abstract types with non-unique names ac
Throws ArgumentError if T is not a concrete type and there is more than one component with
requested name
"""
function get_component(::Type{T}, sys::System, name::AbstractString) where {T <: Component}
function IS.get_component(
::Type{T},
sys::System,
name::AbstractString,
) where {T <: Component}
return IS.get_component(T, sys.data, name)
end

Expand All @@ -1153,36 +1157,15 @@ See also: [`iterate_components`](@ref), [`get_components` with a filter](@ref ge
) where {T <: Component}),
[`get_available_components`](@ref), [`get_buses`](@ref)
"""
function get_components(
function IS.get_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}
return IS.get_components(T, sys.data; subsystem_name = subsystem_name)
end

"""
Return an iterator of components of a given `Type` from a [`System`](@ref), using an
additional filter
`T` can be a concrete or abstract [`Component`](@ref) type from the [Type Tree](@ref).
Call collect on the result if an array is desired.
# Examples
```julia
iter_coal = get_components(x -> get_fuel(x) == ThermalFuels.COAL, Generator, sys)
pv_gens =
collect(get_components(x -> get_prime_mover_type(x) == PrimeMovers.PVe, Generator, sys))
```
See also: [`get_components`](@ref get_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}), [`get_available_components`](@ref),
[`get_buses`](@ref)
"""
function get_components(
function IS.get_components(
filter_func::Function,
::Type{T},
sys::System;
Expand All @@ -1194,15 +1177,15 @@ end
"""
Return a vector of components that are attached to the supplemental attribute.
"""
function get_components(sys::System, attribute::SupplementalAttribute)
function IS.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))
IS.get_component(sys::System, uuid::Base.UUID) = IS.get_component(sys.data, uuid)
IS.get_component(sys::System, uuid::String) = IS.get_component(sys.data, Base.UUID(uuid))

"""
Change the UUID of a component.
Expand Down Expand Up @@ -1237,16 +1220,10 @@ function get_components_by_name(
return IS.get_components_by_name(T, sys.data, name)
end

"""
Returns iterator of available components in a [`System`](@ref).
`T` can be a concrete or abstract [`Component`](@ref) type from the [Type Tree](@ref)
and must have the method `get_available` implemented.
Call collect on the result if an array is desired.
"""
function get_available_components(::Type{T}, sys::System) where {T <: Component}
return get_components(get_available, T, sys)
end
# PSY availability is a pure function of the component and the system is not needed; here we
# implement the required IS.ComponentContainer interface
IS.get_available(::System, component::Component) =
get_available(component)

"""
Return true if the component is attached to the system.
Expand Down
82 changes: 82 additions & 0 deletions src/component_selector.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Most of the `ComponentSelector` functionality in PowerSystems.jl is implemented by
# wrapping the InfrastructureSystems.jl versions (that wrapping occurs in
# `get_components_interface.jl`). An exception is `TopologyComponentSelector`, which is
# wholly implemented in PSY rather than in IS because it depends on
# `PSY.AggregationTopology`.

"""
`PluralComponentSelector` represented by an `AggregationTopology` and a type of `Component`.
"""
@kwdef struct TopologyComponentSelector <: DynamicallyGroupedComponentSelector
component_type::Type{<:Component}
topology_type::Type{<:AggregationTopology}
topology_name::AbstractString
groupby::Union{Symbol, Function}
name::String

TopologyComponentSelector(
component_type::Type{<:InfrastructureSystemsComponent},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString,
groupby::Union{Symbol, Function},
name::String,
) =
new(
component_type,
topology_type,
topology_name,
IS.validate_groupby(groupby),
name,
)
end

# Construction
TopologyComponentSelector(
component_type::Type{<:InfrastructureSystemsComponent},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString,
groupby::Union{Symbol, Function},
name::Nothing = nothing,
) =
TopologyComponentSelector(
component_type,
topology_type,
topology_name,
groupby,
component_to_qualified_string(topology_type, topology_name) *
COMPONENT_NAME_DELIMITER * subtype_to_string(component_type),
)

"""
Make a `ComponentSelector` from an `AggregationTopology` and a type of component. Optionally
provide a name and/or grouping behavior for the `ComponentSelector`.
"""
make_selector(
component_type::Type{<:Component},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString;
groupby::Union{Symbol, Function} = IS.DEFAULT_GROUPBY,
name::Union{String, Nothing} = nothing,
) = TopologyComponentSelector(
component_type,
topology_type,
topology_name,
groupby,
name,
)

# Contents
function IS.get_components(
scope_limiter::Union{Function, Nothing},
selector::TopologyComponentSelector,
sys::System,
)
agg_topology = get_component(selector.topology_type, sys, selector.topology_name)
isnothing(agg_topology) && return IS._make_empty_iterator(selector.component_type)

combo_filter = IS.optional_and_fns(
scope_limiter,
Base.Fix2(is_component_in_aggregation_topology, agg_topology),
)
return IS.get_components(combo_filter, selector.component_type, sys)
end
Loading

0 comments on commit 21160e7

Please sign in to comment.