Skip to content

Commit

Permalink
Updates for PowerModels v0.20 (#22)
Browse files Browse the repository at this point in the history
* updates for powermodels v0.20

* REF: objective functions needed for PowerModels v0.20

---------

Co-authored-by: Juan Ospina <[email protected]>
  • Loading branch information
ccoffrin and juanjospina authored Jan 22, 2024
1 parent 08bdfa9 commit 54100f3
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## staged

- none.
- Added multiple functions to `objetive_helpers.jl` adapted from the implementation in PowerModels <= v0.19 due to their removal from >= v0.20.

## v0.8.0

Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Ipopt = "0.9, 1.0.2"
JSON = "~0.18, ~0.19, ~0.20, ~0.21"
JuMP = "~0.22, ~0.23, 1"
LinearAlgebra = "1.6"
PowerModels = "0.19.9"
PowerModels = "0.20"
PowerModelsDistribution = "0.15.1"
SCS = "~1.0, ~1.1"
julia = "1.6"
Expand Down
5 changes: 5 additions & 0 deletions src/PowerModelsITD.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ module PowerModelsITD
"BOUNDARY_NUMBER constant that determines the starting counter for the boundaries defined."
const BOUNDARY_NUMBER = 100001

### compat for PM v0.20
# enables support for v[1]
Base.getindex(v::JuMP.VariableRef, i::Int) = v

# Files to include in module
include("io/common.jl")
include("core/base.jl")
Expand All @@ -40,6 +44,7 @@ module PowerModelsITD
include("core/ref.jl")
include("core/helpers.jl")
include("core/variable.jl")
include("core/objective_helpers.jl")
include("core/objective.jl")
include("core/objective_dmld.jl")
include("core/objective_dmld_simple.jl")
Expand Down
10 changes: 5 additions & 5 deletions src/core/objective.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function objective_itd_min_fuel_cost(pmitd::AbstractPowerModelITD)
pmd_model = _get_powermodeldistribution_from_powermodelitd(pmitd)

# PM cost models
pm_cost_model = _PM.check_cost_models(pm_model)
pm_cost_model = _check_gen_cost_models(pm_model)

# PMD cost models
pmd_cost_model = _PMD.check_gen_cost_models(pmd_model)
Expand Down Expand Up @@ -43,8 +43,8 @@ Fuel cost minimization objective with piecewise linear terms.
function objective_itd_min_fuel_cost_pwl(pmitd::AbstractPowerModelITD, pm::_PM.AbstractPowerModel, pmd::_PMD.AbstractUnbalancedPowerModel)

# PM-section part
_PM.objective_variable_pg_cost(pm)
_PM.objective_variable_dc_cost(pm)
_objective_variable_pg_cost(pm)
_objective_variable_dc_cost(pm)

# PMD-section part
objective_mc_variable_pg_cost(pmd)
Expand Down Expand Up @@ -185,7 +185,7 @@ function _objective_itd_min_fuel_cost_polynomial_linquad(pmitd::AbstractPowerMod

for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n) )
pg = _PM.var(pm, n, :pg, i)

if length(gen["cost"]) == 1
pm_gen_cost[(n,i)] = gen["cost"][1]
Expand Down Expand Up @@ -387,7 +387,7 @@ function _objective_itd_min_fuel_cost_polynomial_nl(pmitd::AbstractPowerModelITD
pm_gen_cost = Dict()
for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n))
pg = _PM.var(pm, n, :pg, i)

cost_rev = reverse(gen["cost"])
if length(cost_rev) == 1
Expand Down
10 changes: 5 additions & 5 deletions src/core/objective_dmld.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function objective_itd_min_fuel_distribution_load_setpoint_delta(pmitd::Abstract
pmd_model = _get_powermodeldistribution_from_powermodelitd(pmitd)

# PM cost models
pm_cost_model = _PM.check_cost_models(pm_model)
pm_cost_model = _check_cost_models(pm_model)

# PMD cost models
pmd_cost_model = _PMD.check_gen_cost_models(pmd_model)
Expand Down Expand Up @@ -42,8 +42,8 @@ Fuel cost minimization objective with piecewise linear terms in transmission and
function objective_itd_min_fuel_pwl_distribution_load_setpoint_delta(pmitd::AbstractPowerModelITD, pm::_PM.AbstractPowerModel, pmd::_PMD.AbstractUnbalancedPowerModel)

# PM-section part
_PM.objective_variable_pg_cost(pm)
_PM.objective_variable_dc_cost(pm)
_objective_variable_pg_cost(pm)
_objective_variable_dc_cost(pm)

# PMD-section part
for (n, nw_ref) in _PMD.nws(pmd)
Expand Down Expand Up @@ -132,7 +132,7 @@ function _objective_itd_min_fuel_polynomial_linquad_distribution_load_setpoint_d

for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n) )
pg = _PM.var(pm, n, :pg, i)

if length(gen["cost"]) == 1
pm_gen_cost[(n,i)] = gen["cost"][1]
Expand Down Expand Up @@ -207,7 +207,7 @@ function _objective_itd_min_fuel_polynomial_nl_distribution_load_setpoint_delta(
pm_gen_cost = Dict()
for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n))
pg = _PM.var(pm, n, :pg, i)

cost_rev = reverse(gen["cost"])
if length(cost_rev) == 1
Expand Down
10 changes: 5 additions & 5 deletions src/core/objective_dmld_simple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function objective_itd_min_fuel_distribution_load_setpoint_delta_simple(pmitd::A
pmd_model = _get_powermodeldistribution_from_powermodelitd(pmitd)

# PM cost models
pm_cost_model = _PM.check_cost_models(pm_model)
pm_cost_model = _check_cost_models(pm_model)

# PMD cost models
pmd_cost_model = _PMD.check_gen_cost_models(pmd_model)
Expand Down Expand Up @@ -42,8 +42,8 @@ Fuel cost minimization objective with piecewise linear terms in transmission and
function objective_itd_min_fuel_pwl_distribution_load_setpoint_delta_simple(pmitd::AbstractPowerModelITD, pm::_PM.AbstractPowerModel, pmd::_PMD.AbstractUnbalancedPowerModel)

# PM-section part
_PM.objective_variable_pg_cost(pm)
_PM.objective_variable_dc_cost(pm)
_objective_variable_pg_cost(pm)
_objective_variable_dc_cost(pm)

# ITD (Combined objective)
return JuMP.@objective(pmitd.model, Min,
Expand Down Expand Up @@ -102,7 +102,7 @@ function _objective_itd_min_fuel_polynomial_linquad_distribution_load_setpoint_d

for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n) )
pg = _PM.var(pm, n, :pg, i)

if length(gen["cost"]) == 1
pm_gen_cost[(n,i)] = gen["cost"][1]
Expand Down Expand Up @@ -145,7 +145,7 @@ function _objective_itd_min_fuel_polynomial_nl_distribution_load_setpoint_delta_
pm_gen_cost = Dict()
for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
pg = sum( _PM.var(pm, n, :pg, i)[c] for c in _PM.conductor_ids(pm, n))
pg = _PM.var(pm, n, :pg, i)

cost_rev = reverse(gen["cost"])
if length(cost_rev) == 1
Expand Down
234 changes: 234 additions & 0 deletions src/core/objective_helpers.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
"""
function _check_cost_models(
pm::_PM.AbstractPowerModel
)
Checks that all cost models are of the same type.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _check_cost_models(pm::_PM.AbstractPowerModel)
gen_model = _check_gen_cost_models(pm)
dcline_model = _check_dcline_cost_models(pm)

if dcline_model == nothing
return gen_model
end

if gen_model == nothing
return dcline_model
end

if gen_model != dcline_model
@error "generator and dcline cost models are inconsistent, the generator model is $(gen_model) however dcline model $(dcline_model)"
end

return gen_model
end


"""
function _check_gen_cost_models(
pm::_PM.AbstractPowerModel
)
Checks that all generator cost models are of the same type.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _check_gen_cost_models(pm::_PM.AbstractPowerModel)
model = nothing

for (n, nw_ref) in _PM.nws(pm)
for (i,gen) in nw_ref[:gen]
if haskey(gen, "cost")
if model == nothing
model = gen["model"]
else
if gen["model"] != model
@error "cost models are inconsistent, the typical model is $(model) however model $(gen["model"]) is given on generator $(i)"
end
end
else
@error "no cost given for generator $(i)"
end
end
end

return model
end


"""
function _check_dcline_cost_models(
pm::_PM.AbstractPowerModel
)
Checks that all dcline cost models are of the same type.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _check_dcline_cost_models(pm::_PM.AbstractPowerModel)
model = nothing

for (n, nw_ref) in _PM.nws(pm)
for (i,dcline) in nw_ref[:dcline]
if haskey(dcline, "model")
if model == nothing
model = dcline["model"]
else
if dcline["model"] != model
@error "cost models are inconsistent, the typical model is $(model) however model $(dcline["model"]) is given on dcline $(i)"
end
end
else
@error "no cost given for dcline $(i)"
end
end
end

return model
end


"""
function _objective_variable_pg_cost(
pm::_PM.AbstractPowerModel,
report::Bool=true
)
Adds pg_cost variables and constraints.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _objective_variable_pg_cost(pm::_PM.AbstractPowerModel, report::Bool=true)
for (n, nw_ref) in _PM.nws(pm)
pg_cost = _PM.var(pm, n)[:pg_cost] = Dict{Int,Any}()

for (i,gen) in _PM.ref(pm, n, :gen)
pg_var = _PM.var(pm, n, :pg, i)
pmin = JuMP.lower_bound(pg_var)
pmax = JuMP.upper_bound(pg_var)

points = _PM.calc_pwl_points(gen["ncost"], gen["cost"], pmin, pmax)

pg_cost_lambda = JuMP.@variable(pm.model,
[i in 1:length(points)], base_name="$(n)_pg_cost_lambda",
lower_bound = 0.0,
upper_bound = 1.0
)
JuMP.@constraint(pm.model, sum(pg_cost_lambda) == 1.0)

pg_expr = 0.0
pg_cost_expr = 0.0
for (i,point) in enumerate(points)
pg_expr += point.mw*pg_cost_lambda[i]
pg_cost_expr += point.cost*pg_cost_lambda[i]
end
JuMP.@constraint(pm.model, pg_expr == pg_var)
pg_cost[i] = pg_cost_expr
end

report && _PM.sol_component_value(pm, n, :gen, :pg_cost, _PM.ids(pm, n, :gen), pg_cost)
end
end


"""
function _objective_variable_dc_cost(
pm::_PM.AbstractPowerModel,
report::Bool=true
)
Adds p_dc_cost variables and constraints.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _objective_variable_dc_cost(pm::_PM.AbstractPowerModel, report::Bool=true)
for (n, nw_ref) in _PM.nws(pm)
p_dc_cost = _PM.var(pm, n)[:p_dc_cost] = Dict{Int,Any}()

for (i,dcline) in _PM.ref(pm, n, :dcline)
arc = (i, dcline["f_bus"], dcline["t_bus"])
p_dc_var = _PM.var(pm, n, :p_dc)[arc]
pmin = JuMP.lower_bound(p_dc_var)
pmax = JuMP.upper_bound(p_dc_var)

# note pmin/pmax may be different from dcline["pminf"]/dcline["pmaxf"] in the on/off case
points = _PM.calc_pwl_points(dcline["ncost"], dcline["cost"], pmin, pmax)

dc_p_cost_lambda = JuMP.@variable(pm.model,
[i in 1:length(points)], base_name="$(n)_dc_p_cost_lambda",
lower_bound = 0.0,
upper_bound = 1.0
)
JuMP.@constraint(pm.model, sum(dc_p_cost_lambda) == 1.0)

dc_p_expr = 0.0
dc_p_cost_expr = 0.0
for (i,point) in enumerate(points)
dc_p_expr += point.mw*dc_p_cost_lambda[i]
dc_p_cost_expr += point.cost*dc_p_cost_lambda[i]
end

JuMP.@constraint(pm.model, dc_p_expr == p_dc_var)
p_dc_cost[i] = dc_p_cost_expr
end

report && _PM.sol_component_value(pm, n, :dcline, :p_dc_cost, _PM.ids(pm, n, :dcline), p_dc_cost)
end
end


"""
function _objective_variable_pg_cost(
pm::_PM.AbstractIVRModel,
report::Bool=true
)
Adds pg_cost variables and constraints for IVR Model.
Adapted from the implementation in PowerModels <= v0.19.
"""
function _objective_variable_pg_cost(pm::_PM.AbstractIVRModel; report::Bool=true)
for (n, nw_ref) in _PM.nws(pm)
gen_lines = _PM.calc_cost_pwl_lines(nw_ref[:gen])

#to avoid function calls inside of @NLconstraint
pg_cost = _PM.var(pm, n)[:pg_cost] = JuMP.@variable(pm.model,
[i in _PM.ids(pm, n, :gen)], base_name="$(n)_pg_cost",
)
report && _PM.sol_component_value(pm, n, :gen, :pg_cost, _PM.ids(pm, n, :gen), pg_cost)

for (i, gen) in nw_ref[:gen]
pg = _PM.var(pm, n, :pg, i)
for line in gen_lines[i]
JuMP.@NLconstraint(pm.model, pg_cost[i] >= line.slope*pg + line.intercept)
end
end
end
end


"""
function _objective_variable_dc_cost(
pm::_PM.AbstractIVRModel,
report::Bool=true
)
Adds p_dc_cost variables and constraints for IVR Model.
Added for compat with PowerModels <= v0.19 implementation.
"""
function _objective_variable_dc_cost(pm::_PM.AbstractIVRModel, report::Bool=true)
for (n, nw_ref) in _PM.nws(pm)
dcline_lines = _PM.calc_cost_pwl_lines(nw_ref[:dcline])

#to avoid function calls inside of @NLconstraint
p_dc_cost = _PM.var(pm, n)[:p_dc_cost] = JuMP.@variable(pm.model,
[i in _PM.ids(pm, n, :dcline)], base_name="$(n)_p_dc_cost",
)
report && _PM.sol_component_value(pm, n, :dcline, :p_dc_cost, _PM.ids(pm, n, :dcline), p_dc_cost)

for (i, dcline) in nw_ref[:dcline]
arc = (i, dcline["f_bus"], dcline["t_bus"])
p_dc_var = _PM.var(pm, n, :p_dc)[arc]
for line in dcline_lines[i]
JuMP.@NLconstraint(pm.model, p_dc_cost[i] >= line.slope*p_dc_var + line.intercept)
end
end
end
end
Loading

0 comments on commit 54100f3

Please sign in to comment.