Skip to content

Commit

Permalink
Fix TNEP solution building bug (#822)
Browse files Browse the repository at this point in the history
* fix tnep solution reporting, closes #820
* add pm specific sol_component_fixed, closes #821
  • Loading branch information
ccoffrin authored Apr 1, 2022
1 parent c9544b5 commit 8c7c710
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 35 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ PowerModels.jl Change Log
=========================

### Staged
- nothing
- Add specialized version of `sol_component_fixed` for PowerModels (#821)
- Fix `tnep` ne_branch solution values to be consistent with regular branches (#820)

### v0.19.5
- Add support for JuMP v1.0
Expand Down
6 changes: 6 additions & 0 deletions src/core/solution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ function sol_data_model!(pm::AbstractPowerModel, solution::Dict)
end


"PowerModels wrapper for the InfrastructureModels `sol_component_value` function."
function sol_component_fixed(aim::AbstractPowerModel, n::Int, comp_name::Symbol, field_name::Symbol, comp_ids, constant)
return _IM.sol_component_fixed(aim, pm_it_sym, n, comp_name, field_name, comp_ids, constant)
end


"PowerModels wrapper for the InfrastructureModels `sol_component_value` function."
function sol_component_value(aim::AbstractPowerModel, n::Int, comp_name::Symbol, field_name::Symbol, comp_ids, variables)
return _IM.sol_component_value(aim, pm_it_sym, n, comp_name, field_name, comp_ids, variables)
Expand Down
20 changes: 10 additions & 10 deletions src/form/apo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,40 @@

"apo models ignore reactive power flows"
function variable_gen_power_imaginary(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :gen, :qg, ids(pm, nw, :gen), NaN)
report && sol_component_fixed(pm, nw, :gen, :qg, ids(pm, nw, :gen), NaN)
end

"apo models ignore reactive power flows"
function variable_gen_power_imaginary_on_off(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :gen, :qg, ids(pm, nw, :gen), NaN)
report && sol_component_fixed(pm, nw, :gen, :qg, ids(pm, nw, :gen), NaN)
end

"apo models ignore reactive power flows"
function variable_storage_power_imaginary(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :storage, :qs, ids(pm, nw, :storage), NaN)
report && sol_component_fixed(pm, nw, :storage, :qs, ids(pm, nw, :storage), NaN)
end

"apo models ignore reactive power flows"
function variable_storage_power_imaginary_on_off(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :storage, :qs, ids(pm, nw, :storage), NaN)
report && sol_component_fixed(pm, nw, :storage, :qs, ids(pm, nw, :storage), NaN)
end

"apo models ignore reactive power flows"
function variable_branch_power_imaginary(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :branch, :qf, ids(pm, nw, :branch), NaN)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :branch, :qt, ids(pm, nw, :branch), NaN)
report && sol_component_fixed(pm, nw, :branch, :qf, ids(pm, nw, :branch), NaN)
report && sol_component_fixed(pm, nw, :branch, :qt, ids(pm, nw, :branch), NaN)
end

"apo models ignore reactive power flows"
function variable_ne_branch_power_imaginary(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :ne_branch, :q_ne_fr, ids(pm, nw, :ne_branch), NaN)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :ne_branch, :q_ne_to, ids(pm, nw, :ne_branch), NaN)
report && sol_component_fixed(pm, nw, :ne_branch, :qf, ids(pm, nw, :ne_branch), NaN)
report && sol_component_fixed(pm, nw, :ne_branch, :qt, ids(pm, nw, :ne_branch), NaN)
end

"apo models ignore reactive power flows"
function variable_dcline_power_imaginary(pm::AbstractActivePowerModel; nw::Int=nw_id_default, report::Bool=true, kwargs...)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :dcline, :qf, ids(pm, nw, :dcline), NaN)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :dcline, :qt, ids(pm, nw, :dcline), NaN)
report && sol_component_fixed(pm, nw, :dcline, :qf, ids(pm, nw, :dcline), NaN)
report && sol_component_fixed(pm, nw, :dcline, :qt, ids(pm, nw, :dcline), NaN)
end

"do nothing, apo models do not have reactive variables"
Expand Down
4 changes: 2 additions & 2 deletions src/form/dcp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ end

""
function variable_bus_voltage_magnitude(pm::AbstractDCPModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
report && _IM.sol_component_fixed(pm, pm_it_sym, nw, :bus, :vm, ids(pm, nw, :bus), 1.0)
report && sol_component_fixed(pm, nw, :bus, :vm, ids(pm, nw, :bus), 1.0)
end

""
Expand Down Expand Up @@ -280,7 +280,7 @@ function variable_ne_branch_power_real(pm::AbstractAPLossLessModels; nw::Int=nw_
p_ne_expr = merge(p_ne_expr, Dict(((l,j,i), -1.0*var(pm, nw, :p_ne, (l,i,j))) for (l,i,j) in ref(pm, nw, :ne_arcs_from)))
var(pm, nw)[:p_ne] = p_ne_expr

report && sol_component_value_edge(pm, nw, :ne_branch, :p_ne_fr, :p_ne_to, ref(pm, nw, :ne_arcs_from), ref(pm, nw, :ne_arcs_to), p_ne_expr)
report && sol_component_value_edge(pm, nw, :ne_branch, :pf, :pt, ref(pm, nw, :ne_arcs_from), ref(pm, nw, :ne_arcs_to), p_ne_expr)
end

""
Expand Down
4 changes: 2 additions & 2 deletions src/form/lpac.jl
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ function variable_ne_branch_cosine(pm::AbstractLPACCModel; nw::Int=nw_id_default
start = comp_start_value(ref(pm, nw, :ne_branch, l), "cs_start", 1.0)
)

report && sol_component_value(pm, nw, :ne_branch, :cs_ne, ids(pm, nw, :ne_branch), cs_ne)
report && sol_component_value(pm, nw, :ne_branch, :cs, ids(pm, nw, :ne_branch), cs_ne)
end

""
Expand All @@ -237,7 +237,7 @@ function variable_ne_branch_voltage_product_angle(pm::AbstractLPACCModel; nw::In
start = comp_start_value(ref(pm, nw, :ne_buspairs, bi_bp[b]), "td_start")
)

report && sol_component_value(pm, nw, :ne_branch, :td_ne, ids(pm, nw, :ne_branch), td_ne)
report && sol_component_value(pm, nw, :ne_branch, :td, ids(pm, nw, :ne_branch), td_ne)
end

""
Expand Down
7 changes: 6 additions & 1 deletion src/form/wr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,12 @@ function variable_bus_voltage_on_off(pm::AbstractQCWRModel; kwargs...)
variable_buspair_voltage_product_magnitude_on_off(pm; kwargs...)
variable_branch_cosine_on_off(pm; kwargs...)
variable_branch_sine_on_off(pm; kwargs...)
variable_branch_current_magnitude_sqr_on_off(pm; kwargs...) # includes 0, but needs new indexs
variable_branch_current_magnitude_sqr_on_off(pm; kwargs...) # includes 0, but needs new indexes
end

""
function variable_ne_branch_voltage(pm::AbstractQCWRModel; kwargs...)
Memento.error(_LOGGER, "variable_ne_branch_voltage is not yet supported for QC formulations, open an issue if you would like this feature.")
end

""
Expand Down
2 changes: 1 addition & 1 deletion test/multinetwork.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ TESTLOG = Memento.getlogger(PowerModels)
result = PowerModels.run_mn_opf(mn_data, SparseSDPWRMPowerModel, sdp_solver)

# hits iteration limit in SCS v0.9, sense ALMOST_OPTIMAL
@test result["termination_status"] == ALMOST_OPTIMAL
@test result["termination_status"] == OPTIMAL || result["termination_status"] == ALMOST_OPTIMAL
# tolerance relaxed for cross platform compat.
@test isapprox(result["objective"], 33321.9; atol = 1e2)
@test isapprox(
Expand Down
4 changes: 3 additions & 1 deletion test/opf-var.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ end

@test result["termination_status"] == OPTIMAL
@test isapprox(result["objective"], 5728.62; atol = 1e0)
#@test isapprox(result["objective"], 5747.63; atol = 1e0)
end
@testset "5-bus case" begin
data = build_current_data("../test/data/matpower/case5.m")
Expand All @@ -142,8 +143,9 @@ end
data = build_current_data("../test/data/matpower/case14.m")
result = PowerModels._solve_opf_cl(data, SDPWRMPowerModel, sdp_solver)

@test result["termination_status"] == OPTIMAL
@test result["termination_status"] == OPTIMAL || result["termination_status"] == ALMOST_OPTIMAL
@test isapprox(result["objective"], 7505.33; atol = 1e0)
#@test isapprox(result["objective"], 7637.95; atol = 1e0)
end
end

Expand Down
11 changes: 10 additions & 1 deletion test/opf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ end

@test result["termination_status"] == OPTIMAL
@test isapprox(result["objective"], 5736.94; atol = 2e0)
#@test isapprox(result["objective"], 5747.37; atol = 2e0)
end
@testset "5-bus transformer swap case" begin
result = run_opf("../test/data/matpower/case5.m", SOCWRConicPowerModel, sdp_solver)
Expand Down Expand Up @@ -621,26 +622,30 @@ end

@test result["termination_status"] == OPTIMAL
@test isapprox(result["objective"], 3551.71; atol = 40)
#@test isapprox(result["objective"], 3602.11; atol = 40)
end
@testset "5-bus with pwl costs" begin
result = run_opf("../test/data/matpower/case5_pwlc.m", SOCWRConicPowerModel, sdp_solver)

@test result["termination_status"] == OPTIMAL
@test isapprox(result["objective"], 42889; atol = 1e0)
#@test isapprox(result["objective"], 42906; atol = 1e0)
end
@testset "6-bus case" begin
result = run_opf("../test/data/matpower/case6.m", SOCWRConicPowerModel, sdp_solver)

@test result["termination_status"] == OPTIMAL
#@test isapprox(result["objective"], 11472.2; atol = 3e0)
@test isapprox(result["objective"], 11451.5; atol = 3e0)
#@test isapprox(result["objective"], 11473.4; atol = 3e0)
end
@testset "24-bus rts case" begin
result = run_opf("../test/data/matpower/case24.m", SOCWRConicPowerModel, sdp_solver)

@test result["termination_status"] == OPTIMAL
#@test isapprox(result["objective"], 70693.9; atol = 1e0)
@test isapprox(result["objective"], 70670.0; atol = 1e0)
#@test isapprox(result["objective"], 70683.5; atol = 1e0)
end
@testset "14-bus variable bounds" begin
pm = instantiate_model("../test/data/matpower/case14.m", SOCWRConicPowerModel, PowerModels.build_opf)
Expand Down Expand Up @@ -902,6 +907,7 @@ end

@test result["termination_status"] == OPTIMAL
@test isapprox(result["objective"], 5818.00; atol = 1e1)
#@test isapprox(result["objective"], 5852.51; atol = 1e1)
end
@testset "5-bus asymmetric case" begin
result = run_opf("../test/data/matpower/case5_asym.m", SDPWRMPowerModel, sdp_solver)
Expand All @@ -927,6 +933,7 @@ end
@test result["termination_status"] == OPTIMAL
#@test isapprox(result["objective"], 6827.34; atol = 1e0)
@test isapprox(result["objective"], 6735.17; atol = 1e0)
#@test isapprox(result["objective"], 6827.71; atol = 1e0)
end
# too slow for unit tests
# @testset "14-bus case" begin
Expand All @@ -941,6 +948,7 @@ end
@test result["termination_status"] == OPTIMAL
#@test isapprox(result["objective"], 11580.8; atol = 1e1)
@test isapprox(result["objective"], 11507.7; atol = 1e1)
#@test isapprox(result["objective"], 11580.5; atol = 1e1)
end
@testset "14-bus variable bounds" begin
pm = instantiate_model("../test/data/matpower/case14.m", SDPWRMPowerModel, PowerModels.build_opf)
Expand All @@ -956,6 +964,7 @@ end
@test result["termination_status"] == OPTIMAL
#@test isapprox(result["objective"], 5851.23; atol = 1e1)
@test isapprox(result["objective"], 5818.00; atol = 1e1)
#@test isapprox(result["objective"], 5852.51; atol = 1e1)
end
@testset "5-bus with asymmetric line charge" begin
result = run_opf("../test/data/pti/case5_alc.raw", SparseSDPWRMPowerModel, sdp_solver)
Expand Down
46 changes: 30 additions & 16 deletions test/tnep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ function check_tnep_status(sol)
end
end

# test that ne_branch solution information is a superset of regular branches
function check_ne_branch_keys(sol)
branch = collect(sol["branch"])[1].second
ne_brnach = collect(sol["ne_branch"])[1].second
@test all(haskey(ne_brnach, k) for k in keys(branch))
end


@testset "test ac tnep" begin
@testset "3-bus case" begin
Expand All @@ -14,6 +21,7 @@ end
result = run_tnep(data, ACPPowerModel, minlp_solver)

check_tnep_status(result["solution"])
check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 2; atol = 1e-2)
Expand All @@ -37,6 +45,7 @@ end
result = run_tnep(data, SOCWRPowerModel, minlp_solver)

check_tnep_status(result["solution"])
check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 2; atol = 1e-2)
Expand All @@ -53,27 +62,29 @@ end
end


@testset "test qc tnep" begin
@testset "3-bus case" begin
data = PowerModels.parse_file("../test/data/matpower/case3_tnep.m")
calc_thermal_limits!(data)
result = run_tnep(data, QCRMPowerModel, minlp_solver)
# requires a correct implementation of `variable_ne_branch_voltage`
# @testset "test qc tnep" begin
# @testset "3-bus case" begin
# data = PowerModels.parse_file("../test/data/matpower/case3_tnep.m")
# calc_thermal_limits!(data)
# result = run_tnep(data, QCRMPowerModel, minlp_solver)

check_tnep_status(result["solution"])
# check_tnep_status(result["solution"])
# check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 2; atol = 1e-2)
end
# @test result["termination_status"] == LOCALLY_SOLVED
# @test isapprox(result["objective"], 2; atol = 1e-2)
# end

@testset "5-bus rts case" begin
result = run_tnep("../test/data/matpower/case5_tnep.m", QCRMPowerModel, minlp_solver)
# @testset "5-bus rts case" begin
# result = run_tnep("../test/data/matpower/case5_tnep.m", QCRMPowerModel, minlp_solver)

check_tnep_status(result["solution"])
# check_tnep_status(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 1; atol = 1e-2)
end
end
# @test result["termination_status"] == LOCALLY_SOLVED
# @test isapprox(result["objective"], 1; atol = 1e-2)
# end
# end


@testset "test dc tnep" begin
Expand All @@ -83,6 +94,7 @@ end
result = run_tnep(data, DCPPowerModel, minlp_solver)

check_tnep_status(result["solution"])
check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 2; atol = 1e-2)
Expand Down Expand Up @@ -129,6 +141,7 @@ end
result = run_tnep("../test/data/matpower/case5_tnep.m", DCPLLPowerModel, minlp_solver)

check_tnep_status(result["solution"])
check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 1; atol = 1e-2)
Expand All @@ -142,6 +155,7 @@ end
result = run_tnep(data, LPACCPowerModel, minlp_solver)

check_tnep_status(result["solution"])
check_ne_branch_keys(result["solution"])

@test result["termination_status"] == LOCALLY_SOLVED
@test isapprox(result["objective"], 2; atol = 1e-2)
Expand Down

0 comments on commit 8c7c710

Please sign in to comment.