-
Notifications
You must be signed in to change notification settings - Fork 0
Anchor NetworkModel to a declared network source #152
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,27 @@ via [`set_reduced_branch_tracker!`](@ref). | |
| """ | ||
| abstract type AbstractBranchReductionTracker end | ||
|
|
||
| """ | ||
| Abstract anchor for the declaration of which network a `NetworkModel` is built on and | ||
| how it is reduced. Concrete sources (a reduction specification, a prebuilt matrix, a | ||
| prebuilt factorization core) live in the matrix-aware downstream package (POM), so | ||
| IOM carries no dependency on any matrix implementation. | ||
| """ | ||
| abstract type AbstractNetworkSource end | ||
|
|
||
| """ | ||
| Abstract anchor for the network artifacts a build derives from an | ||
| [`AbstractNetworkSource`](@ref): the reduction data plus whichever matrices the | ||
| network formulation needs. Concrete containers live in POM. | ||
| """ | ||
| abstract type AbstractNetworkData end | ||
|
|
||
| """ | ||
| Source used when a `NetworkModel` is constructed without an explicit one: build the | ||
| network from the system with no reductions applied. | ||
| """ | ||
| struct DefaultNetworkSource <: AbstractNetworkSource end | ||
|
|
||
| "Abstract supertype for network model formulations; neutral anchor for NetworkModel{T}." | ||
| abstract type AbstractNetworkModel <: IS.Optimization.AbstractInfrastructureModel end | ||
|
|
||
|
|
@@ -32,52 +53,44 @@ Establishes the NetworkModel for a given AC network formulation type. | |
| # Accepted keyword arguments | ||
| - `use_slacks::Bool` = false | ||
| Adds slack buses to the network modeling. | ||
| - `network_matrix::Union{AbstractInfrastructureNetworkMatrix, Nothing}` = nothing | ||
| Network matrix (e.g. PTDF/VirtualPTDF produced by PowerNetworkMatrices; optional). | ||
| - `contingency_matrix::Union{AbstractInfrastructureNetworkMatrix, Nothing}` = nothing | ||
| Contingency matrix (e.g. VirtualMODF) for security-constrained models (N-k contingencies). | ||
| If `nothing` and the template includes a security-constrained branch | ||
| formulation, the matrix is constructed from the system during | ||
| `instantiate_network_model!` (same pattern as PTDF). | ||
| - `reduce_radial_branches::Bool` = false | ||
| Enable radial branch reduction when building network matrices. | ||
| - `reduce_degree_two_branches::Bool` = false | ||
| Enable degree-two branch reduction when building network matrices. | ||
| - `subnetworks::Dict{Int, Set{Int}}` = Dict() | ||
| Optional mapping of reference bus → set of mapped buses. If not provided, | ||
| subnetworks are inferred from the network matrix or discovered from the system. | ||
| - `network_source::AbstractNetworkSource` = `DefaultNetworkSource()` | ||
| Declares which network the model is built on and how it is reduced. The default | ||
| builds it from the system with no reductions. Concrete sources (a reduction | ||
| specification, a prebuilt matrix, a prebuilt factorization core) live in the | ||
| matrix-aware downstream package. | ||
| - `reduction_exceptions::Vector{Int}` = `Int[]` | ||
| Bus numbers the reduction must not eliminate, on top of those the template | ||
| itself pins. | ||
| - `duals::Vector{DataType}` = Vector{DataType}() | ||
| Constraint types for which duals should be recorded. | ||
| - `evaluations::EvaluationContainer` | ||
| External evaluators (e.g. power-flow) keyed by concrete evaluator type. | ||
| Default is an empty container — no evaluator runs. | ||
|
|
||
| # Notes | ||
| - `modeled_branch_types` and `reduced_branch_tracker` are internal fields managed by the model. | ||
| - `network_data` holds every matrix and the reduction data derived from | ||
| `network_source` during `instantiate_network_model!`; it is `nothing` before then. | ||
| - `subnetworks`, `modeled_branch_types` and `reduced_branch_tracker` are internal | ||
| fields managed by the model. | ||
| - `subsystem` can be set after construction via `set_subsystem!(model, id)`. | ||
| - Network and contingency matrix inputs are validated against the requested reduction flags and | ||
| may raise a ConflictingInputsError if they are inconsistent with | ||
| `reduce_radial_branches` or `reduce_degree_two_branches`. | ||
|
|
||
| # Examples (concrete types like PTDFPowerModel, CopperPlatePowerModel are defined in PowerSimulations) | ||
| # ptdf = PowerNetworkMatrices.VirtualPTDF(system) | ||
| # ec = EvaluationContainer() | ||
| # add_evaluator!(ec, PFS.PowerFlowEvaluationModel, PFS.PowerFlowEvaluationModel()) | ||
| # nw = NetworkModel(PTDFPowerModel; network_matrix = ptdf, reduce_radial_branches = true, | ||
| # nw = NetworkModel(PTDFPowerModel; | ||
| # network_source = NetworkReductionSpec(RadialReduction()), | ||
| # evaluations = ec) | ||
| # | ||
| # nw2 = NetworkModel(CopperPlatePowerModel; subnetworks = Dict(1 => Set([1,2,3]))) | ||
| # nw2 = NetworkModel(CopperPlatePowerModel) | ||
| """ | ||
| mutable struct NetworkModel{T <: AbstractNetworkModel} | ||
| use_slacks::Bool | ||
| network_matrix::Union{Nothing, AbstractInfrastructureNetworkMatrix} | ||
| contingency_matrix::Union{Nothing, AbstractInfrastructureNetworkMatrix} | ||
| network_source::AbstractNetworkSource | ||
| reduction_exceptions::Vector{Int} | ||
| subnetworks::Dict{Int, Set{Int}} | ||
| bus_area_map::Dict{IS.InfrastructureSystemsComponent, Int} | ||
| duals::Vector{DataType} | ||
| network_reduction::Union{Nothing, AbstractInfrastructureNetworkReductionData} | ||
| reduce_radial_branches::Bool | ||
| reduce_degree_two_branches::Bool | ||
| network_data::Union{Nothing, AbstractNetworkData} | ||
| evaluations::EvaluationContainer | ||
| subsystem::Union{Nothing, String} | ||
| hvdc_network_model::Union{Nothing, AbstractHVDCNetworkModel} | ||
|
|
@@ -87,28 +100,23 @@ mutable struct NetworkModel{T <: AbstractNetworkModel} | |
| function NetworkModel( | ||
| ::Type{T}; | ||
| use_slacks = false, | ||
| network_matrix = nothing, | ||
| contingency_matrix = nothing, | ||
| reduce_radial_branches = false, | ||
| reduce_degree_two_branches = false, | ||
| subnetworks = Dict{Int, Set{Int}}(), | ||
| network_source = DefaultNetworkSource(), | ||
| reduction_exceptions = Int[], | ||
| duals = Vector{DataType}(), | ||
| evaluations = EvaluationContainer(), | ||
| hvdc_network_model = nothing, | ||
| ) where {T <: AbstractNetworkModel} | ||
| _check_network_formulation(T) | ||
| new{T}( | ||
| use_slacks, | ||
| network_matrix, | ||
| contingency_matrix, | ||
| subnetworks, | ||
| network_source, | ||
| reduction_exceptions, | ||
| Dict{Int, Set{Int}}(), | ||
| Dict{IS.InfrastructureSystemsComponent, Int}(), | ||
| duals, | ||
| # Populated by the network-matrix-aware instantiation code (POM); IOM | ||
| # holds it behind the IS abstraction so it carries no PNM dependency. | ||
| # holds it behind an abstract type so it carries no PNM dependency. | ||
| nothing, | ||
| reduce_radial_branches, | ||
| reduce_degree_two_branches, | ||
| evaluations, | ||
| nothing, | ||
| hvdc_network_model, | ||
|
|
@@ -119,11 +127,23 @@ mutable struct NetworkModel{T <: AbstractNetworkModel} | |
| end | ||
|
|
||
| get_use_slacks(m::NetworkModel) = m.use_slacks | ||
| get_network_matrix(m::NetworkModel) = m.network_matrix | ||
| get_contingency_matrix(m::NetworkModel) = m.contingency_matrix | ||
| get_reduce_radial_branches(m::NetworkModel) = m.reduce_radial_branches | ||
| get_network_reduction(m::NetworkModel) = m.network_reduction | ||
| get_network_source(m::NetworkModel) = m.network_source | ||
| get_reduction_exceptions(m::NetworkModel) = m.reduction_exceptions | ||
| get_network_data(m::NetworkModel) = m.network_data | ||
| get_duals(m::NetworkModel) = m.duals | ||
|
|
||
| """ | ||
| The network matrix derived during instantiation. Implemented in the matrix-aware | ||
| downstream package, which owns the concrete `AbstractNetworkData`. | ||
| """ | ||
| function get_network_matrix end | ||
|
|
||
| """The contingency matrix derived during instantiation. Implemented downstream.""" | ||
| function get_contingency_matrix end | ||
|
|
||
| """The network reduction derived during instantiation. Implemented downstream.""" | ||
| function get_network_reduction end | ||
|
|
||
|
Comment on lines
+135
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of defining these in IOM and implementing them downstream in POM? I'm guessing there is a reason but want to understand.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is because these are methods defined for network model. I think that NetworkModel still has pending work to see how it would generalize to infrastructure networks. |
||
| get_network_formulation(::NetworkModel{T}) where {T} = T | ||
| get_reduced_branch_tracker(m::NetworkModel) = m.reduced_branch_tracker | ||
| get_reference_buses(m::NetworkModel{T}) where {T <: AbstractNetworkModel} = | ||
|
|
@@ -143,6 +163,11 @@ function set_reduced_branch_tracker!(m::NetworkModel, val::AbstractBranchReducti | |
| return | ||
| end | ||
|
|
||
| function set_network_data!(m::NetworkModel, val::Union{Nothing, AbstractNetworkData}) | ||
| m.network_data = val | ||
| return | ||
| end | ||
|
|
||
| function add_dual!(model::NetworkModel, dual) | ||
| dual in model.duals && error("dual = $dual is already stored") | ||
| push!(model.duals, dual) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,41 @@ | ||
| """ | ||
| Unit tests for NetworkModel with the IS network-matrix abstractions. IOM holds | ||
| matrices, reduction data, and the branch-reduction tracker behind abstract types | ||
| with no PowerNetworkMatrices dependency; these mocks stand in for the | ||
| implementing package (POM/PNM). | ||
| Unit tests for NetworkModel's neutral network anchors. IOM holds the network source, | ||
| the derived network data, and the branch-reduction tracker behind abstract types with | ||
| no PowerNetworkMatrices dependency; these mocks stand in for the implementing package | ||
| (POM/PNM). | ||
| """ | ||
|
|
||
| struct MockNetworkMatrix <: IOM.AbstractInfrastructureNetworkMatrix{Float64} | ||
| data::Matrix{Float64} | ||
| end | ||
| Base.size(m::MockNetworkMatrix) = size(m.data) | ||
| Base.getindex(m::MockNetworkMatrix, i::Int, j::Int) = m.data[i, j] | ||
| struct MockNetworkSource <: IOM.AbstractNetworkSource end | ||
|
|
||
| struct MockReductionData <: IOM.AbstractInfrastructureNetworkReductionData end | ||
| struct MockNetworkData <: IOM.AbstractNetworkData end | ||
|
|
||
| struct MockReductionTracker <: IOM.AbstractBranchReductionTracker end | ||
|
|
||
| @testset "NetworkModel with abstract network matrices" begin | ||
| matrix = MockNetworkMatrix([1.0 0.0; 0.0 1.0]) | ||
| @testset "NetworkModel with abstract network source and data" begin | ||
| source = MockNetworkSource() | ||
| nw = IOM.NetworkModel( | ||
| TestPowerModel; | ||
| network_matrix = matrix, | ||
| contingency_matrix = matrix, | ||
| network_source = source, | ||
| reduction_exceptions = [3, 7], | ||
| ) | ||
| @test IOM.get_network_matrix(nw) === matrix | ||
| @test IOM.get_contingency_matrix(nw) === matrix | ||
| # Reduction data and tracker are populated by the matrix-aware downstream package. | ||
| @test IOM.get_network_reduction(nw) === nothing | ||
| @test IOM.get_network_source(nw) === source | ||
| @test IOM.get_reduction_exceptions(nw) == [3, 7] | ||
| # Network data and tracker are populated by the matrix-aware downstream package. | ||
| @test IOM.get_network_data(nw) === nothing | ||
| @test IOM.get_reduced_branch_tracker(nw) === nothing | ||
|
|
||
| nw.network_reduction = MockReductionData() | ||
| @test IOM.get_network_reduction(nw) isa MockReductionData | ||
| data = MockNetworkData() | ||
| IOM.set_network_data!(nw, data) | ||
| @test IOM.get_network_data(nw) === data | ||
|
|
||
| tracker = MockReductionTracker() | ||
| IOM.set_reduced_branch_tracker!(nw, tracker) | ||
| @test IOM.get_reduced_branch_tracker(nw) === tracker | ||
| end | ||
|
|
||
| @testset "NetworkModel defaults to the neutral source" begin | ||
| nw = IOM.NetworkModel(TestPowerModel) | ||
| @test IOM.get_network_source(nw) === IOM.DefaultNetworkSource() | ||
| @test isempty(IOM.get_reduction_exceptions(nw)) | ||
| @test isempty(IOM.get_subnetworks(nw)) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing the
hvdc_network_modelis domain specific and doesn't belong in IOMThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is TBD to be removed