Skip to content
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

FEATURE: Robust partition evaluation #17

Merged
merged 9 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- none

## v3.6.0

- Added capability to evaluate the optimality of a given partition against a set of load scenarios to judge robustness

## v3.5.1

- Fixed bug in `constraint_mc_power_balance_shed_block` (`LPUBFDiagPowerModel` version) where `pd_zblock_zdemand` was used instead of `qd_zblock_zdemand`
Expand Down
5 changes: 3 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PowerModelsONM"
uuid = "25264005-a304-4053-a338-565045d392ac"
authors = ["David M Fobes <[email protected]>"]
version = "3.5.1"
version = "3.6.0"

[deps]
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
Expand Down Expand Up @@ -60,7 +60,8 @@ Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
Juniper = "2ddba703-00a4-53a7-87a5-e8b9971dde84"
PowerModelsDistribution = "d7431456-977f-11e9-2de3-97ff7677985e"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "HiGHS", "Ipopt", "JSON", "Juniper", "PowerModelsDistribution"]
test = ["Test", "HiGHS", "Ipopt", "JSON", "Juniper", "PowerModelsDistribution", "Random"]
1 change: 1 addition & 0 deletions src/PowerModelsONM.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ module PowerModelsONM
include("prob/mld_block.jl")
include("prob/partitions.jl")
include("prob/mld_block_robust.jl")
include("prob/robust_evaluation.jl")
include("prob/stability.jl")
include("prob/switch.jl")

Expand Down
63 changes: 63 additions & 0 deletions src/prob/robust_evaluation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
evaluate_partition_optimality(
data,
load_scenarios,
model_type,
solver;
save_partial_results,
partial_result_folder,
time_elapsed,
kwargs...
)

Function to evaluate the optimality of a specific partition by considering a collection of load scenarios.

`data` has the partition configuration applied.
"""
function evaluate_partition_optimality(
data::Dict{String,<:Any},
load_scenarios,
model_type::Type,
solver;
save_partial_results::Bool=false,
partial_result_folder::String=".",
time_elapsed::Union{Missing,Real} = missing,
kwargs...)

_results = Dict{String,Any}()

for ls in keys(load_scenarios)
single_load_scenario = Dict{String,Dict{String,Any}}()
single_load_scenario["1"] = load_scenarios[ls]

eng = deepcopy(data)

if !ismissing(time_elapsed)
eng["time_elapsed"] = time_elapsed
end

@debug "starting load scenario evaluation $(ls)/$(length(load_scenarios))"

result = solve_robust_block_mld(eng, model_type, solver, single_load_scenario; kwargs...)

if save_partial_results
open("$(partial_result_folder)/result_$(ls).json", "w") do io
JSON.print(io, result)
end
end

_results[ls] = result
end

return _results
end


"""
retrieve_load_scenario_optimality(results::Dict)

Returns a Dict of objectives for the different load scenarios considered in the robust partition evaluation.
"""
function retrieve_load_scenario_optimality(results::Dict{String,<:Any})::Dict{String,Real}
return Dict{String,Real}("$i" => results["$i"]["1"]["objective"] for i in 1:length(results))
end
47 changes: 47 additions & 0 deletions test/robust_eval.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function randomize_partition_config(
case,
num_closed_switches)

if num_closed_switches > length(keys(case["switch"]))
error("Number of closed switches exceeds the total number of switches")
end

part_config = Dict{String,Any}()

switch_keys = collect(keys(case["switch"]))
shuffled_keys = Random.shuffle(switch_keys)
closed_switches = shuffled_keys[1:num_closed_switches]

# Set the status of the selected switches to "CLOSED" and the rest to "OPEN"
for key in switch_keys
if key in closed_switches
part_config[key] = PMD.SwitchState(1)
else
part_config[key] = PMD.SwitchState(0)
end
end

case["fixed_partition_config"] = part_config

return case
end


@testset "robust partition evaluation" begin
case = parse_file("../test/data/ieee13_feeder.dss")
settings = parse_settings("../test/data/ieee13_settings.json")
PMD.apply_voltage_bounds!(case)
case = randomize_partition_config(case, 2)

num_load_scenarios = 20
uncertainty_val = 0.2
ls = generate_load_scenarios(case, num_load_scenarios, uncertainty_val)

solver = optimizer_with_attributes(HiGHS.Optimizer, "primal_feasibility_tolerance" => 1e-6, "dual_feasibility_tolerance" => 1e-6, "small_matrix_value" => 1e-12, "allow_unbounded_or_infeasible" => true, "output_flag" => false)

results_eval_optimality = evaluate_partition_optimality(case, ls, PMD.LPUBFDiagPowerModel, solver)

optimality = retrieve_load_scenario_optimality(results_eval_optimality)

@test isapprox(optimality["1"], 5, atol=1e0)
end
5 changes: 5 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import Juniper
import Ipopt
import HiGHS

import Random
Random.seed!(21)

minlp_solver = optimizer_with_attributes(
Juniper.Optimizer,
"nl_solver" => optimizer_with_attributes(Ipopt.Optimizer, "tol"=>1e-6, "print_level"=>0),
Expand Down Expand Up @@ -60,6 +63,8 @@ silence!()
# problems
@info "Running tests in mld.jl"
include("mld.jl")
@info "Running tests in robust_eval.jl"
include("robust_eval.jl")
@info "Running tests in nlp.jl"
include("nlp.jl")
@info "Running tests in opf.jl"
Expand Down
Loading