diff --git a/CHANGELOG.md b/CHANGELOG.md index 724f9a179..b033d6427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ PowerModels.jl Change Log - Added iterative flow limit cut OPF solvers (#619) - Improved connected components computation time (#504) - Removed `Inf` bounds from variables (#630) -- Removal of unused functions in `solution.jl`: `get_solution`, `add_generator_power_setpoint`, `add_storage_setpoint`, `add_branch_flow_setpoint`, `add_dcline_flow_setpoint` (breaking) (#637) +- Removal of unused functions in `solution.jl`: `get_solution`, `add_generator_power_setpoint`, `add_storage_setpoint`, `add_branch_flow_setpoint`, `add_dcline_flow_setpoint` (breaking) (#637) +- Fixed a solution reporting bug when the optimizer result count is zero ### v0.13.1 - Added DCMPPowerModel for replication of Matpower's DC model (#612) diff --git a/src/core/solution.jl b/src/core/solution.jl index b82a2b2aa..ce9a1899f 100644 --- a/src/core/solution.jl +++ b/src/core/solution.jl @@ -1,23 +1,46 @@ "" function build_solution(pm::AbstractPowerModel, solve_time; solution_builder=solution_opf!) - # TODO @assert that the model is solved - sol = _init_solution(pm) - data = Dict{String,Any}("name" => pm.data["name"]) + # TODO replace with JuMP.result_count(pm.model) after version v0.21 + # try-catch is needed until solvers reliably support ResultCount() + result_count = 1 + try + result_count = _MOI.get(pm.model, _MOI.ResultCount()) + catch + Memento.warn(_LOGGER, "the given optimizer does not provide the ResultCount() attribute, assuming the solver returned a solution which may be incorrect."); + end + + if result_count > 0 + if InfrastructureModels.ismultinetwork(pm.data) + sol["multinetwork"] = true + sol_nws = sol["nw"] = Dict{String,Any}() + + for (n,nw_data) in pm.data["nw"] + sol_nw = sol_nws[n] = Dict{String,Any}() + sol_nw["baseMVA"] = nw_data["baseMVA"] + if haskey(nw_data, "conductors") + sol_nw["conductors"] = nw_data["conductors"] + end + pm.cnw = parse(Int, n) + solution_builder(pm, sol_nw) + end + else + sol["baseMVA"] = pm.data["baseMVA"] + if haskey(pm.data, "conductors") + sol["conductors"] = pm.data["conductors"] + end + solution_builder(pm, sol) + end + else + Memento.warn(_LOGGER, "model has no results, solution cannot be built") + end + + data = Dict{String,Any}("name" => pm.data["name"]) if InfrastructureModels.ismultinetwork(pm.data) - sol["multinetwork"] = true - sol_nws = sol["nw"] = Dict{String,Any}() data_nws = data["nw"] = Dict{String,Any}() for (n,nw_data) in pm.data["nw"] - sol_nw = sol_nws[n] = Dict{String,Any}() - sol_nw["baseMVA"] = nw_data["baseMVA"] - if haskey(nw_data, "conductors") - sol_nw["conductors"] = nw_data["conductors"] - end - pm.cnw = parse(Int, n) - solution_builder(pm, sol_nw) data_nws[n] = Dict( "name" => get(nw_data, "name", "anonymous"), "bus_count" => length(nw_data["bus"]), @@ -25,11 +48,6 @@ function build_solution(pm::AbstractPowerModel, solve_time; solution_builder=sol ) end else - sol["baseMVA"] = pm.data["baseMVA"] - if haskey(pm.data, "conductors") - sol["conductors"] = pm.data["conductors"] - end - solution_builder(pm, sol) data["bus_count"] = length(pm.data["bus"]) data["branch_count"] = length(pm.data["branch"]) end diff --git a/test/output.jl b/test/output.jl index d383304ac..8b40d8556 100644 --- a/test/output.jl +++ b/test/output.jl @@ -20,6 +20,28 @@ @test length(result["solution"]["bus"]) == 24 @test length(result["solution"]["gen"]) == 33 end + + @testset "infeasible case" begin + # make sure code does not crash when ResultCount == 0 + # change objective to linear so the case can load into cbc + data = parse_file("../test/data/matpower/case24.m") + for (i,gen) in data["gen"] + if gen["ncost"] > 2 + gen["ncost"] = 2 + gen["cost"] = gen["cost"][length(gen["cost"])-1:end] + end + end + result = run_opf(data, DCPPowerModel, cbc_solver) + + @test haskey(result, "optimizer") + @test haskey(result, "termination_status") + @test haskey(result, "primal_status") + @test haskey(result, "dual_status") + @test haskey(result, "solve_time") + @test haskey(result, "solution") + @test !isnan(result["solve_time"]) + @test length(result["solution"]) == 1 + end end @testset "test branch flow output" begin