From 0ca4ed25f1a7a63b3f137724dbe4d09d544e1e2a Mon Sep 17 00:00:00 2001 From: Luke Kiernan Date: Fri, 4 Sep 2026 13:43:13 -0600 Subject: [PATCH] Bound event parameter attributes on SupplementalAttribute, not Component The event slot of `EventParametersAttributes` / `add_event_parameter_container!` describes the event itself, and real event types are supplemental attributes (`PSY.FixedForcedOutage <: PSY.Contingency <: IS.SupplementalAttribute`), which do not subtype `IS.InfrastructureSystemsComponent`. With the Component bound every downstream call was a MethodError, so the scaffolding had never been exercised; POM's events port is the first consumer. Also drop `affected_devices::Vector{T}`: it had no readers, and under the corrected bound its name no longer matched its type. The affected device set lives on the event model. Add `get_attribute_type` so the remaining type parameter is readable. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NjXEBDreXLvbXw3pLKtAVR --- src/common_models/add_param_container.jl | 6 +- .../add_param_container_shims.jl | 2 +- src/core/parameter_container.jl | 15 ++-- test/InfrastructureOptimizationModelsTests.jl | 2 +- test/mocks/mock_components.jl | 5 ++ test/test_event_parameter_container.jl | 70 +++++++++++++++++++ test/test_parameterized_range_constraints.jl | 2 +- 7 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 test/test_event_parameter_container.jl diff --git a/src/common_models/add_param_container.jl b/src/common_models/add_param_container.jl index d9132799..088b4d89 100644 --- a/src/common_models/add_param_container.jl +++ b/src/common_models/add_param_container.jl @@ -101,8 +101,8 @@ function add_variable_value_parameter_container!( end """ -Allocate an event parameter container (`EventParametersAttributes`). `V` is the component type -whose instances the event affects. +Allocate an event parameter container (`EventParametersAttributes`). `U` is the component type +the event affects; `V` is the supplemental-attribute type describing the event itself. """ function add_event_parameter_container!( container::OptimizationContainer, @@ -115,7 +115,7 @@ function add_event_parameter_container!( ) where { T <: EventParameter, U <: IS.InfrastructureSystemsComponent, - V <: IS.InfrastructureSystemsComponent, + V <: IS.SupplementalAttribute, } param_key = ParameterKey(T, U, meta) attributes = EventParametersAttributes(V, T) diff --git a/src/common_models/add_param_container_shims.jl b/src/common_models/add_param_container_shims.jl index bb3aae22..573b1fc8 100644 --- a/src/common_models/add_param_container_shims.jl +++ b/src/common_models/add_param_container_shims.jl @@ -86,6 +86,6 @@ add_param_container!( ) where { T <: EventParameter, U <: IS.InfrastructureSystemsComponent, - V <: IS.InfrastructureSystemsComponent, + V <: IS.SupplementalAttribute, } = add_event_parameter_container!( container, T, U, V, axs...; sparse = sparse, meta = meta) diff --git a/src/core/parameter_container.jl b/src/core/parameter_container.jl index 07de9837..9b23ce3a 100644 --- a/src/core/parameter_container.jl +++ b/src/core/parameter_container.jl @@ -81,25 +81,30 @@ get_variable_types(attr::CostFunctionAttributes) = attr.variable_types get_uses_compact_power(attr::CostFunctionAttributes) = attr.uses_compact_power struct EventParametersAttributes{ - T <: IS.InfrastructureSystemsComponent, + T <: IS.SupplementalAttribute, U <: ParameterType, } <: ParameterAttributes - affected_devices::Vector{T} end function EventParametersAttributes( ::Type{T}, ::Type{U}, -) where {T <: IS.InfrastructureSystemsComponent, U <: ParameterType} - return EventParametersAttributes{T, U}(T[]) +) where {T <: IS.SupplementalAttribute, U <: ParameterType} + return EventParametersAttributes{T, U}() end function get_param_type( ::EventParametersAttributes{T, U}, -) where {T <: IS.InfrastructureSystemsComponent, U <: ParameterType} +) where {T <: IS.SupplementalAttribute, U <: ParameterType} return U end +function get_attribute_type( + ::EventParametersAttributes{T, U}, +) where {T <: IS.SupplementalAttribute, U <: ParameterType} + return T +end + ################################################################################# # Parameter Container - holds parameter arrays and their attributes ################################################################################# diff --git a/test/InfrastructureOptimizationModelsTests.jl b/test/InfrastructureOptimizationModelsTests.jl index 3f6559e8..ad28b334 100644 --- a/test/InfrastructureOptimizationModelsTests.jl +++ b/test/InfrastructureOptimizationModelsTests.jl @@ -111,7 +111,7 @@ function run_tests() # optimization_problem_outputs_export.jl: low-complexity include(joinpath(TEST_DIR, "test_optimization_outputs.jl")) include(joinpath(TEST_DIR, "test_optimizer_stats.jl")) - # parameter_container.jl: low-complexity + include(joinpath(TEST_DIR, "test_event_parameter_container.jl")) # TODO outputs_by_time.jl # TODO service_model.jl include(joinpath(TEST_DIR, "test_settings.jl")) diff --git a/test/mocks/mock_components.jl b/test/mocks/mock_components.jl index d54f9310..57d7d672 100644 --- a/test/mocks/mock_components.jl +++ b/test/mocks/mock_components.jl @@ -146,6 +146,11 @@ get_from_bus(b::MockBranch) = b.from_bus get_to_bus(b::MockBranch) = b.to_bus get_rate(b::MockBranch) = b.rating +# Mock supplemental attribute type for use as the event type parameter of event +# parameter containers. Real event types (e.g. PSY.FixedForcedOutage) are supplemental +# attributes, not components. +struct MockOutageAttribute <: IS.SupplementalAttribute end + # Mock component type for use as type parameter in container keys # This replaces PSY.ThermalStandard etc. in tests that don't need real PSY types # Subtypes IS.InfrastructureSystemsComponent so it works with VariableKey, ConstraintKey, etc. diff --git a/test/test_event_parameter_container.jl b/test/test_event_parameter_container.jl new file mode 100644 index 00000000..e8dac035 --- /dev/null +++ b/test/test_event_parameter_container.jl @@ -0,0 +1,70 @@ +""" +Unit tests for the event parameter container (`EventParametersAttributes`). + +The type parameter describing the event is a *supplemental attribute*, not a component: +downstream event models key parameters off types such as `PSY.FixedForcedOutage`, which +subtype `IS.SupplementalAttribute`. Bounding that slot on `IS.InfrastructureSystemsComponent` +makes every real call a `MethodError`, so the bound is what these tests pin down. +""" + +struct EventContainerParameter <: IOM.EventParameter end + +function _make_event_parameter_container(time_steps) + mock_sys = MockSystem(100.0) + settings = IOM.Settings( + mock_sys; + horizon = Dates.Hour(length(time_steps)), + resolution = Dates.Hour(1), + time_series_cache_size = 0, + ) + container = IOM.OptimizationContainer(mock_sys, settings, nothing, MockDeterministic) + IOM.set_time_steps!(container, time_steps) + return container +end + +@testset "Event parameter container" begin + time_steps = 1:3 + names = ["A", "B"] + + @testset "Allocation with a supplemental-attribute event type" begin + container = _make_event_parameter_container(time_steps) + param_container = IOM.add_event_parameter_container!( + container, + EventContainerParameter, + MockThermalGen, + MockOutageAttribute, + names, + time_steps, + ) + param_array = IOM.get_parameter_array(param_container) + @test axes(param_array)[1] == names + @test axes(param_array)[2] == time_steps + @test size(IOM.get_multiplier_array(param_container)) == (2, 3) + + attributes = IOM.get_attributes(param_container) + @test attributes isa + IOM.EventParametersAttributes{MockOutageAttribute, EventContainerParameter} + @test IOM.get_param_type(attributes) === EventContainerParameter + @test IOM.get_attribute_type(attributes) === MockOutageAttribute + + @test IOM.has_container_key( + container, + EventContainerParameter, + MockThermalGen, + ) + end + + @testset "The add_param_container! shim routes to the event overload" begin + container = _make_event_parameter_container(time_steps) + param_container = IOM.add_param_container!( + container, + EventContainerParameter, + MockThermalGen, + MockOutageAttribute, + names, + time_steps, + ) + @test IOM.get_attributes(param_container) isa + IOM.EventParametersAttributes{MockOutageAttribute, EventContainerParameter} + end +end diff --git a/test/test_parameterized_range_constraints.jl b/test/test_parameterized_range_constraints.jl index 92d9cf0a..0be0522f 100644 --- a/test/test_parameterized_range_constraints.jl +++ b/test/test_parameterized_range_constraints.jl @@ -183,7 +183,7 @@ end container, TestEventParameter, MockThermalGen, - MockThermalGen, + MockOutageAttribute, names, time_steps, )