diff --git a/CHANGELOG.md b/CHANGELOG.md index 858c2af54..6c9348a87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## staged +- Fixed bug in `apply_voltage_bounds!` for multinetwork data - Added compat for JuMP v1 - Fixed bug in `_map_eng2math` where global keys were not being propagated in multinetwork - Fixed bug/typo in `_create_storage` where `kwhstored` was derived from `:stored` instead of `Symbol("%stored")` diff --git a/src/data_model/transformations.jl b/src/data_model/transformations.jl index ef5c9a497..9907bbe0f 100644 --- a/src/data_model/transformations.jl +++ b/src/data_model/transformations.jl @@ -166,7 +166,7 @@ end add voltage bounds to all buses based on per-unit upper (`vm_ub`) and lower (`vm_lb`), scaled by the bus's voltage based """ function _apply_voltage_bounds!(data_eng::Dict{String,<:Any}; vm_lb::Union{Real,Missing}=0.9, vm_ub::Union{Real,Missing}=1.1, exclude::Vector{String}=!isempty(get(data_eng, "voltage_source", Dict())) ? String[x.second["bus"] for x in data_eng["voltage_source"]] : String[]) - (bus_vbases, edge_vbases) = calc_voltage_bases(data_eng, data_eng["settings"]["vbases_default"]) + (bus_vbases, _) = calc_eng_voltage_bases(data_eng, data_eng["settings"]["vbases_default"]) for (id, bus) in filter(x->!(x.first in exclude), get(data_eng, "bus", Dict{String,Any}())) vbase = bus_vbases[id] if !ismissing(vm_lb) && !ismissing(vbase) diff --git a/src/data_model/units.jl b/src/data_model/units.jl index e50c4666c..b790d0fb4 100644 --- a/src/data_model/units.jl +++ b/src/data_model/units.jl @@ -107,12 +107,37 @@ end """ discover_voltage_zones(data_model::Dict{String,<:Any})::Dict{Int,Set{Any}} -finds voltage zones by walking through the network and analyzing the transformers +finds voltage zones by walking through the network and analyzing the transformers, attempting to decern the type of `data_model` """ function discover_voltage_zones(data_model::Dict{String,<:Any})::Dict{Int,Set{Any}} @assert iseng(data_model) || ismath(data_model) "unsupported data model" - edge_elements = ismath(data_model) ? _math_edge_elements : _eng_edge_elements + return ismath(data_model) ? discover_math_voltage_zones(data_model) : discover_eng_voltage_zones(data_model) +end + + +""" + discover_math_voltage_zones(data_model::Dict{String,<:Any})::Dict{Int,Set{Any}} + +finds voltage zones by walking through the network and analyzing the transformers for a MATHEMATICAL `data_model` +""" +discover_math_voltage_zones(data_model::Dict{String,Any})::Dict{Int,Set{Any}} = _discover_voltage_zones(data_model, _math_edge_elements) + + +""" + discover_voltage_zones(data_model::Dict{String,<:Any})::Dict{Int,Set{Any}} + +finds voltage zones by walking through the network and analyzing the transformers for a ENGINEERING `data_model` +""" +discover_eng_voltage_zones(data_model::Dict{String,Any})::Dict{Int,Set{Any}} = _discover_voltage_zones(data_model, _eng_edge_elements) + + +""" + discover_voltage_zones(data_model::Dict{String,<:Any}, edge_elements::Vector{String})::Dict{Int,Set{Any}} + +finds voltage zones by walking through the network and analyzing the transformers +""" +function _discover_voltage_zones(data_model::Dict{String,<:Any}, edge_elements::Vector{String})::Dict{Int,Set{Any}} unused_components = Set("$comp_type.$id" for comp_type in edge_elements[edge_elements .!= "transformer"] for id in keys(get(data_model, comp_type, Dict()))) bus_connectors = Dict([(id,Set()) for id in keys(get(data_model, "bus", Dict()))]) for comp_type in edge_elements[edge_elements .!= "transformer"] @@ -147,15 +172,40 @@ function discover_voltage_zones(data_model::Dict{String,<:Any})::Dict{Int,Set{An return zones end +""" + calc_math_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} + +Calculates voltage bases for each voltage zone for buses and branches for a MATHEMATICAL `data_model` +""" +calc_math_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} = _calc_voltage_bases(data_model, vbase_sources, _math_edge_elements) + + +""" + calc_eng_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} + +Calculates voltage bases for each voltage zone for buses and branches for a ENGINEERING `data_model` +""" +calc_eng_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} = _calc_voltage_bases(data_model, vbase_sources, _eng_edge_elements) + """ calc_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} -Calculates voltage bases for each voltage zone for buses and branches +Calculates voltage bases for each voltage zone for buses and branches, attempting to automatically decern the `data_model` type """ function calc_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real})::Tuple{Dict,Dict} + return ismath(data_model) ? calc_math_voltage_bases(data_model, vbase_sources) : calc_eng_voltage_bases(data_model, vbase_sources) +end + + +""" + _calc_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real}, edge_elements::Vector{String})::Tuple{Dict,Dict} + +Calculates voltage bases for each voltage zone for buses and branches given a list of `edge_elements` +""" +function _calc_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{String,<:Real}, edge_elements::Vector{String})::Tuple{Dict,Dict} # find zones of buses connected by lines - zones = discover_voltage_zones(data_model) + zones = _discover_voltage_zones(data_model, edge_elements) bus_to_zone = Dict([(bus,zone) for (zone, buses) in zones for bus in buses]) # assign specified vbase to corresponding zones @@ -214,10 +264,9 @@ function calc_voltage_bases(data_model::Dict{String,<:Any}, vbase_sources::Dict{ end end - edge_elements = ismath(data_model) ? _math_edge_elements : _eng_edge_elements - bus_vbase = Dict([(bus,zone_vbase[zone]) for (bus,zone) in bus_to_zone]) edge_vbase = Dict([("$edge_type.$id", bus_vbase["$(obj["f_bus"])"]) for edge_type in edge_elements[edge_elements .!= "transformer"] if haskey(data_model, edge_type) for (id,obj) in data_model[edge_type]]) + return (bus_vbase, edge_vbase) end diff --git a/test/multinetwork.jl b/test/multinetwork.jl index 1ea19e47b..9b6935605 100644 --- a/test/multinetwork.jl +++ b/test/multinetwork.jl @@ -7,4 +7,16 @@ @test result_mn["termination_status"] == LOCALLY_SOLVED end + + @testset "apply_voltage_bounds! to multinetworks" begin + mn_eng = make_multinetwork(case3_balanced) + + apply_voltage_bounds!(mn_eng) + for (n,nw) in mn_eng["nw"] + vbases, _ = calc_eng_voltage_bases(mn_eng["nw"]["1"], mn_eng["nw"]["1"]["settings"]["vbases_default"]) + + @test all(all(isapprox.(bus["vm_ub"][filter(x->x∉bus["grounded"],bus["terminals"])]/vbases[id], 1.1; atol=1e-6)) for (id,bus) in filter(x->x.first!="sourcebus",nw["bus"])) + @test all(all(isapprox.(bus["vm_lb"][filter(x->x∉bus["grounded"],bus["terminals"])]/vbases[id], 0.9; atol=1e-6)) for (id,bus) in filter(x->x.first!="sourcebus",nw["bus"])) + end + end end