mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
Compare commits
3 Commits
7a28a0ca36
...
m2m
| Author | SHA1 | Date | |
|---|---|---|---|
| 7897adbee1 | |||
| bb880575ef | |||
|
|
d34378c660 |
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user