Compare commits

...

3 Commits
v0.4.0 ... m2m

Author SHA1 Message Date
7897adbee1 enforce_transmission: Add constraint refs to model 2024-08-05 20:03:38 -05:00
bb880575ef optimize: Return stats with violations 2024-08-05 16:35:08 -05:00
Feng
d34378c660 Update decomposition.md
put application names in subtitle: production cost modeling for time decomposition; stochastic UC for scenario decomposition.
2024-07-14 14:35:02 -05:00
4 changed files with 47 additions and 33 deletions

View File

@@ -1,8 +1,8 @@
# Decomposition methods
## 1. Time decomposition
## 1. Time decomposition for production cost modeling
Solving unit commitment instances that have long time horizons (for example, year-long 8760-hour instances) requires a substantial amount of computational power. To address this issue, UC.jl offers a time decomposition method, which breaks the instance down into multiple overlapping subproblems, solves them sequentially, then reassembles the solution.
Solving unit commitment instances that have long time horizons (for example, year-long 8760-hour instances in production cost modeling) requires a substantial amount of computational power. To address this issue, UC.jl offers a time decomposition method, which breaks the instance down into multiple overlapping subproblems, solves them sequentially, then reassembles the solution.
When solving a unit commitment instance with a dense time slot structure, computational complexity can become a significant challenge. For instance, if the instance contains hourly data for an entire year (8760 hours), solving such a model can require a substantial amount of computational power. To address this issue, UC.jl provides a time_decomposition method within the `optimize!` function. This method decomposes the problem into multiple sub-problems, solving them sequentially.
@@ -57,7 +57,7 @@ solution = UnitCommitment.optimize!(
)
```
## 2. Scenario decomposition with Progressive Hedging
## 2. Scenario decomposition with Progressive Hedging for stochstic UC
By default, UC.jl uses the Extensive Form (EF) when solving stochastic instances. This approach involves constructing a single JuMP model that contains data and decision variables for all scenarios. Although EF has optimality guarantees and performs well with small test cases, it can become computationally intractable for large instances or substantial number of scenarios.

View File

@@ -26,59 +26,67 @@ function _enforce_transmission(;
isf::Matrix{Float64},
lodf::Matrix{Float64},
)::Nothing
instance = model[:instance]
limit::Float64 = 0.0
overflow = model[:overflow]
net_injection = model[:net_injection]
lm = violation.monitored_line
lc = violation.outage_line
t = violation.time
eq_flow_ub = _init(model, :eq_flow_ub)
eq_flow_lb = _init(model, :eq_flow_lb)
eq_flow_def = _init(model, :eq_flow_def)
eq_idx = (
sc.name,
lm.name,
lc === nothing ? "Base" : lc.name,
t,
)
if violation.outage_line === nothing
limit = violation.monitored_line.normal_flow_limit[violation.time]
if lc === nothing
limit = lm.normal_flow_limit[t]
@info @sprintf(
" %8.3f MW overflow in %-5s time %3d (pre-contingency, scenario %s)",
violation.amount,
violation.monitored_line.name,
violation.time,
lm.name,
t,
sc.name,
)
else
limit = violation.monitored_line.emergency_flow_limit[violation.time]
limit = lm.emergency_flow_limit[t]
@info @sprintf(
" %8.3f MW overflow in %-5s time %3d (outage: line %s, scenario %s)",
violation.amount,
violation.monitored_line.name,
violation.time,
violation.outage_line.name,
lm.name,
t,
lc.name,
sc.name,
)
end
fm = violation.monitored_line.name
t = violation.time
flow = @variable(model, base_name = "flow[$fm,$t]")
v = overflow[sc.name, lm.name, t]
flow = @variable(model, base_name = "flow[$eq_idx]")
eq_flow_ub[eq_idx] = @constraint(model, flow <= limit + v)
eq_flow_lb[eq_idx] = @constraint(model, -flow <= limit + v)
v = overflow[sc.name, violation.monitored_line.name, violation.time]
@constraint(model, flow <= limit + v)
@constraint(model, -flow <= limit + v)
if violation.outage_line === nothing
@constraint(
if lc === nothing
eq_flow_def[eq_idx] = @constraint(
model,
flow == sum(
net_injection[sc.name, b.name, violation.time] *
isf[violation.monitored_line.offset, b.offset] for
net_injection[sc.name, b.name, t] *
isf[lm.offset, b.offset] for
b in sc.buses if b.offset > 0
)
)
else
@constraint(
eq_flow_def[eq_idx] = @constraint(
model,
flow == sum(
net_injection[sc.name, b.name, violation.time] * (
isf[violation.monitored_line.offset, b.offset] + (
net_injection[sc.name, b.name, t] * (
isf[lm.offset, b.offset] + (
lodf[
violation.monitored_line.offset,
violation.outage_line.offset,
] * isf[violation.outage_line.offset, b.offset]
lm.offset,
lc.offset,
] * isf[lc.offset, b.offset]
)
) for b in sc.buses if b.offset > 0
)

View File

@@ -2,7 +2,9 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
using DataStructures
function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Dict
if !occursin("Gurobi", JuMP.solver_name(model))
method.two_phase_gap = false
end
@@ -22,6 +24,9 @@ function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
large_gap = true
end
end
stats = Dict(
"violations" => []
)
while true
time_elapsed = time() - initial_time
time_remaining = method.time_limit - time_elapsed
@@ -68,6 +73,7 @@ function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
if violations_found
for (i, v) in enumerate(violations)
append!(stats["violations"], v)
_enforce_transmission(model, v, model[:instance].scenarios[i])
end
else
@@ -80,5 +86,5 @@ function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
end
end
end
return
return stats
end

View File

@@ -3,12 +3,12 @@
# Released under the modified BSD license. See COPYING.md for more details.
"""
optimize!(model::JuMP.Model)::Nothing
optimize!(model::JuMP.Model)::Dict
Solve the given unit commitment model. Unlike `JuMP.optimize!`, this uses more
advanced methods to accelerate the solution process and to enforce transmission
and N-1 security constraints.
"""
function optimize!(model::JuMP.Model)::Nothing
function optimize!(model::JuMP.Model)::Dict
return UnitCommitment.optimize!(model, XavQiuWanThi2019.Method())
end