Correct optimize!, add stochastic test case

pull/25/head
Alinson S. Xavier 3 years ago
parent 20939dc4b7
commit 414128cc0b
Signed by: isoron
GPG Key ID: 0DA8E4B9E1109DCA

@ -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

Loading…
Cancel
Save