mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
Correct optimize!, add stochastic test case
This commit is contained in:
@@ -34,19 +34,21 @@ function _enforce_transmission(;
|
|||||||
if violation.outage_line === nothing
|
if violation.outage_line === nothing
|
||||||
limit = violation.monitored_line.normal_flow_limit[violation.time]
|
limit = violation.monitored_line.normal_flow_limit[violation.time]
|
||||||
@info @sprintf(
|
@info @sprintf(
|
||||||
" %8.3f MW overflow in %-5s time %3d (pre-contingency)",
|
" %8.3f MW overflow in %-5s time %3d (pre-contingency, scenario %s)",
|
||||||
violation.amount,
|
violation.amount,
|
||||||
violation.monitored_line.name,
|
violation.monitored_line.name,
|
||||||
violation.time,
|
violation.time,
|
||||||
|
sc.name,
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
limit = violation.monitored_line.emergency_flow_limit[violation.time]
|
limit = violation.monitored_line.emergency_flow_limit[violation.time]
|
||||||
@info @sprintf(
|
@info @sprintf(
|
||||||
" %8.3f MW overflow in %-5s time %3d (outage: line %s)",
|
" %8.3f MW overflow in %-5s time %3d (outage: line %s, scenario %s)",
|
||||||
violation.amount,
|
violation.amount,
|
||||||
violation.monitored_line.name,
|
violation.monitored_line.name,
|
||||||
violation.time,
|
violation.time,
|
||||||
violation.outage_line.name,
|
violation.outage_line.name,
|
||||||
|
sc.name,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,31 +15,25 @@ function _find_violations(
|
|||||||
overflow = model[:overflow]
|
overflow = model[:overflow]
|
||||||
length(sc.buses) > 1 || return []
|
length(sc.buses) > 1 || return []
|
||||||
violations = []
|
violations = []
|
||||||
@info "Verifying transmission limits..."
|
|
||||||
time_screening = @elapsed begin
|
non_slack_buses = [b for b in sc.buses if b.offset > 0]
|
||||||
non_slack_buses = [b for b in sc.buses if b.offset > 0]
|
net_injection_values = [
|
||||||
net_injection_values = [
|
value(net_injection[sc.name, b.name, t]) for b in non_slack_buses,
|
||||||
value(net_injection[sc.name, b.name, t]) for
|
t in 1:instance.time
|
||||||
b in non_slack_buses, t in 1:instance.time
|
]
|
||||||
]
|
overflow_values = [
|
||||||
overflow_values = [
|
value(overflow[sc.name, lm.name, t]) for lm in sc.lines,
|
||||||
value(overflow[sc.name, lm.name, t]) for lm in sc.lines,
|
t in 1:instance.time
|
||||||
t in 1:instance.time
|
]
|
||||||
]
|
violations = UnitCommitment._find_violations(
|
||||||
violations = UnitCommitment._find_violations(
|
instance = instance,
|
||||||
instance = instance,
|
sc = sc,
|
||||||
sc = sc,
|
net_injections = net_injection_values,
|
||||||
net_injections = net_injection_values,
|
overflow = overflow_values,
|
||||||
overflow = overflow_values,
|
isf = sc.isf,
|
||||||
isf = sc.isf,
|
lodf = sc.lodf,
|
||||||
lodf = sc.lodf,
|
max_per_line = max_per_line,
|
||||||
max_per_line = max_per_line,
|
max_per_period = max_per_period,
|
||||||
max_per_period = max_per_period,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
@info @sprintf(
|
|
||||||
"Verified transmission limits in %.2f seconds",
|
|
||||||
time_screening
|
|
||||||
)
|
)
|
||||||
return violations
|
return violations
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,46 +10,73 @@ function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
|
|||||||
JuMP.set_optimizer_attribute(model, "MIPGap", gap)
|
JuMP.set_optimizer_attribute(model, "MIPGap", gap)
|
||||||
@info @sprintf("MIP gap tolerance set to %f", gap)
|
@info @sprintf("MIP gap tolerance set to %f", gap)
|
||||||
end
|
end
|
||||||
|
initial_time = time()
|
||||||
|
large_gap = false
|
||||||
|
has_transmission = false
|
||||||
for sc in model[:instance].scenarios
|
for sc in model[:instance].scenarios
|
||||||
large_gap = false
|
if length(sc.isf) > 0
|
||||||
has_transmission = (length(sc.isf) > 0)
|
has_transmission = true
|
||||||
|
end
|
||||||
if has_transmission && method.two_phase_gap
|
if has_transmission && method.two_phase_gap
|
||||||
set_gap(1e-2)
|
set_gap(1e-2)
|
||||||
large_gap = true
|
large_gap = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
while true
|
||||||
|
time_elapsed = time() - initial_time
|
||||||
|
time_remaining = method.time_limit - time_elapsed
|
||||||
|
if time_remaining < 0
|
||||||
|
@info "Time limit exceeded"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
@info @sprintf(
|
||||||
|
"Setting MILP time limit to %.2f seconds",
|
||||||
|
time_remaining
|
||||||
|
)
|
||||||
|
JuMP.set_time_limit_sec(model, time_remaining)
|
||||||
|
@info "Solving MILP..."
|
||||||
JuMP.optimize!(model)
|
JuMP.optimize!(model)
|
||||||
while true
|
|
||||||
initial_time = time()
|
has_transmission || break
|
||||||
time_elapsed = time() - initial_time
|
|
||||||
time_remaining = method.time_limit - time_elapsed
|
@info "Verifying transmission limits..."
|
||||||
if time_remaining < 0
|
time_screening = @elapsed begin
|
||||||
@info "Time limit exceeded"
|
violations = []
|
||||||
break
|
for sc in model[:instance].scenarios
|
||||||
|
push!(
|
||||||
|
violations,
|
||||||
|
_find_violations(
|
||||||
|
model,
|
||||||
|
sc,
|
||||||
|
max_per_line = method.max_violations_per_line,
|
||||||
|
max_per_period = method.max_violations_per_period,
|
||||||
|
),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
@info @sprintf(
|
end
|
||||||
"Setting MILP time limit to %.2f seconds",
|
@info @sprintf(
|
||||||
time_remaining
|
"Verified transmission limits in %.2f seconds",
|
||||||
)
|
time_screening
|
||||||
JuMP.set_time_limit_sec(model, time_remaining)
|
)
|
||||||
@info "Solving MILP..."
|
|
||||||
JuMP.optimize!(model)
|
violations_found = false
|
||||||
has_transmission || break
|
for v in violations
|
||||||
violations = _find_violations(
|
if !isempty(v)
|
||||||
model,
|
violations_found = true
|
||||||
sc,
|
end
|
||||||
max_per_line = method.max_violations_per_line,
|
end
|
||||||
max_per_period = method.max_violations_per_period,
|
|
||||||
)
|
if violations_found
|
||||||
if isempty(violations)
|
for (i, v) in enumerate(violations)
|
||||||
@info "No violations found"
|
_enforce_transmission(model, v, model[:instance].scenarios[i])
|
||||||
if large_gap
|
end
|
||||||
large_gap = false
|
else
|
||||||
set_gap(method.gap_limit)
|
@info "No violations found"
|
||||||
else
|
if large_gap
|
||||||
break
|
large_gap = false
|
||||||
end
|
set_gap(method.gap_limit)
|
||||||
else
|
else
|
||||||
_enforce_transmission(model, violations, sc)
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,37 +4,59 @@
|
|||||||
|
|
||||||
using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON
|
using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON
|
||||||
|
|
||||||
@testset "usage" begin
|
function _set_flow_limits!(instance)
|
||||||
instance = UnitCommitment.read("$FIXTURES/case14.json.gz")
|
|
||||||
for sc in instance.scenarios
|
for sc in instance.scenarios
|
||||||
sc.power_balance_penalty = [100_000 for _ in 1:instance.time]
|
sc.power_balance_penalty = [100_000 for _ in 1:instance.time]
|
||||||
for line in sc.lines, t in 1:4
|
for line in sc.lines, t in 1:4
|
||||||
line.normal_flow_limit[t] = 10.0
|
line.normal_flow_limit[t] = 10.0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
|
end
|
||||||
model = UnitCommitment.build_model(
|
|
||||||
instance = instance,
|
@testset "usage" begin
|
||||||
optimizer = optimizer,
|
@testset "deterministic" begin
|
||||||
variable_names = true,
|
instance = UnitCommitment.read("$FIXTURES/case14.json.gz")
|
||||||
)
|
_set_flow_limits!(instance)
|
||||||
@test name(model[:is_on]["g1", 1]) == "is_on[g1,1]"
|
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
|
||||||
|
model = UnitCommitment.build_model(
|
||||||
# Optimize and retrieve solution
|
instance = instance,
|
||||||
UnitCommitment.optimize!(model)
|
optimizer = optimizer,
|
||||||
solution = UnitCommitment.solution(model)
|
variable_names = true,
|
||||||
|
)
|
||||||
# Write solution to a file
|
@test name(model[:is_on]["g1", 1]) == "is_on[g1,1]"
|
||||||
filename = tempname()
|
|
||||||
UnitCommitment.write(filename, solution)
|
# Optimize and retrieve solution
|
||||||
loaded = JSON.parsefile(filename)
|
UnitCommitment.optimize!(model)
|
||||||
@test length(loaded["Is on"]) == 6
|
solution = UnitCommitment.solution(model)
|
||||||
|
|
||||||
# Verify solution
|
# Write solution to a file
|
||||||
@test UnitCommitment.validate(instance, solution)
|
filename = tempname()
|
||||||
|
UnitCommitment.write(filename, solution)
|
||||||
# Reoptimize with fixed solution
|
loaded = JSON.parsefile(filename)
|
||||||
UnitCommitment.fix!(model, solution)
|
@test length(loaded["Is on"]) == 6
|
||||||
UnitCommitment.optimize!(model)
|
|
||||||
@test UnitCommitment.validate(instance, solution)
|
# Verify solution
|
||||||
|
@test UnitCommitment.validate(instance, solution)
|
||||||
|
|
||||||
|
# Reoptimize with fixed solution
|
||||||
|
UnitCommitment.fix!(model, solution)
|
||||||
|
UnitCommitment.optimize!(model)
|
||||||
|
@test UnitCommitment.validate(instance, solution)
|
||||||
|
end
|
||||||
|
|
||||||
|
@testset "stochastic" begin
|
||||||
|
instance = UnitCommitment.read([
|
||||||
|
"$FIXTURES/case14.json.gz",
|
||||||
|
"$FIXTURES/case14.json.gz",
|
||||||
|
])
|
||||||
|
_set_flow_limits!(instance)
|
||||||
|
@test length(instance.scenarios) == 2
|
||||||
|
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
|
||||||
|
model = UnitCommitment.build_model(
|
||||||
|
instance = instance,
|
||||||
|
optimizer = optimizer,
|
||||||
|
)
|
||||||
|
UnitCommitment.optimize!(model)
|
||||||
|
solution = UnitCommitment.solution(model)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user