From 53a74b6bb3ff7a5a956b766bc538ae7b421a0d73 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Tue, 27 Jun 2017 19:17:35 +0200 Subject: [PATCH 01/23] Write out DC line data to dict --- src/io/matpower.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 277f9aee1..3004e6b62 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -224,7 +224,7 @@ function add_line_delimiter(mp_line::AbstractString, start_char, end_char) mp_line = "$(mp_line);" end - if contains(mp_line, string(end_char)) + if contains(mp_line, string(end_char)) prefix = strip(split(mp_line, end_char)[1]) if length(prefix) > 0 && ! contains(prefix, ";") mp_line = replace(mp_line, end_char, ";$(end_char)") @@ -525,6 +525,7 @@ function parse_matpower_data(data_string::String) push!(dclines, dcline_data) end + case["dcline"] = dclines else name = parsed_matrix["name"] @@ -543,7 +544,7 @@ function parse_matpower_data(data_string::String) for parsed_cell in parsed_cells #println(parsed_cell) - if parsed_cell["name"] == "bus_name" + if parsed_cell["name"] == "bus_name" if length(parsed_cell["data"]) != length(case["bus"]) error("incorrect Matpower file, the number of bus names ($(length(parsed_cell["data"]))) is inconsistent with the number of buses ($(length(case["bus"]))).\n") end @@ -578,7 +579,7 @@ function build_typed_dict(data, column_names) columns = length(data[1]) typed_columns = [type_array([ data[r][c] for r in 1:rows ]) for c in 1:columns] - + typed_data = Dict{String,Any}[] for r in 1:rows data_dict = Dict{String,Any}() From 33140e700cf90a8891b2eb468559314bb3dbe26b Mon Sep 17 00:00:00 2001 From: hakanergun Date: Wed, 19 Jul 2017 11:08:26 +0200 Subject: [PATCH 02/23] Bug fix DCLine data input from Matpower --- src/io/matpower.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 3004e6b62..7a869cc8a 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -515,12 +515,12 @@ function parse_matpower_data(data_string::String) "loss1" => parse(Float64, dcline_row[17]), ) if length(dcline_row) > 17 - branch_data["mu_pmin"] = parse(Float64, dcline_row[18]) - branch_data["mu_pmax"] = parse(Float64, dcline_row[19]) - branch_data["mu_qminf"] = parse(Float64, dcline_row[20]) - branch_data["mu_qmaxf"] = parse(Float64, dcline_row[21]) - branch_data["mu_qmint"] = parse(Float64, dcline_row[22]) - branch_data["mu_qmaxt"] = parse(Float64, dcline_row[23]) + dcline_data["mu_pmin"] = parse(Float64, dcline_row[18]) + dcline_data["mu_pmax"] = parse(Float64, dcline_row[19]) + dcline_data["mu_qminf"] = parse(Float64, dcline_row[20]) + dcline_data["mu_qmaxf"] = parse(Float64, dcline_row[21]) + dcline_data["mu_qmint"] = parse(Float64, dcline_row[22]) + dcline_data["mu_qmaxt"] = parse(Float64, dcline_row[23]) end push!(dclines, dcline_data) From 20e6681785ca2caf17d3cb0fb8df53dac19d7142 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Wed, 19 Jul 2017 12:00:41 +0200 Subject: [PATCH 03/23] Adding file for AC DC Power flow model - New file acdcp.jl (as same file as acp.jl) - Defining ACDCPPowerModel, instead of ACPPowerModel - Include command in Powermodels.jl --- src/PowerModels.jl | 1 + src/form/acdcp.jl | 422 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 423 insertions(+) create mode 100644 src/form/acdcp.jl diff --git a/src/PowerModels.jl b/src/PowerModels.jl index 6c132a403..1a188f2e3 100644 --- a/src/PowerModels.jl +++ b/src/PowerModels.jl @@ -21,6 +21,7 @@ include("core/objective.jl") include("core/solution.jl") include("form/acp.jl") +include("form/acdcp.jl") include("form/dcp.jl") include("form/wr.jl") include("form/wrm.jl") diff --git a/src/form/acdcp.jl b/src/form/acdcp.jl new file mode 100644 index 000000000..287d7a39b --- /dev/null +++ b/src/form/acdcp.jl @@ -0,0 +1,422 @@ +export + ACDCPPowerModel, StandardACPForm, + APIACDCPPowerModel, APIACPForm + +"" +@compat abstract type AbstractACPForm <: AbstractPowerFormulation end + +"" +@compat abstract type StandardACPForm <: AbstractACPForm end + +"" +const ACDCPPowerModel = GenericPowerModel{StandardACPForm} + +"default AC constructor" +ACDCPPowerModel(data::Dict{String,Any}; kwargs...) = + GenericPowerModel(data, StandardACPForm; kwargs...) + +"" +function variable_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) + variable_phase_angle(pm; kwargs...) + variable_voltage_magnitude(pm; kwargs...) +end + +"" +variable_voltage_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) = nothing + +"do nothing, this model does not have complex voltage constraints" +constraint_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = Set() + +"do nothing, this model does not have complex voltage constraints" +constraint_voltage_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = nothing + +"`t[ref_bus] == 0`" +constraint_theta_ref{T <: AbstractACPForm}(pm::GenericPowerModel{T}, ref_bus) = + Set([@constraint(pm.model, getindex(pm.model, :t)[ref_bus] == 0)]) + +"`vm - epsilon <= v[i] <= vm + epsilon`" +function constraint_voltage_magnitude_setpoint{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, vm, epsilon) + v = getindex(pm.model, :v)[i] + + if epsilon == 0.0 + c = @constraint(pm.model, v == vm) + return Set([c]) + else + c1 = @constraint(pm.model, v <= vm + epsilon) + c2 = @constraint(pm.model, v >= vm - epsilon) + return Set([c1, c2]) + end +end + +""" +``` +sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 +sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 +``` +""" +function constraint_kcl_shunt{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) + v = getindex(pm.model, :v)[i] + p = getindex(pm.model, :p) + q = getindex(pm.model, :q) + pg = getindex(pm.model, :pg) + qg = getindex(pm.model, :qg) + + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) + return Set([c1, c2]) +end + +""" +``` +sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 +sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 +``` +""" +function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) + v = getindex(pm.model, :v)[i] + p = getindex(pm.model, :p) + q = getindex(pm.model, :q) + p_ne = getindex(pm.model, :p_ne) + q_ne = getindex(pm.model, :q_ne) + pg = getindex(pm.model, :pg) + qg = getindex(pm.model, :qg) + + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) + return Set([c1, c2]) +end + +""" +Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) + +``` +p[f_idx] == g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])) +q[f_idx] == -(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])) +``` +""" +function constraint_ohms_yt_from{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) + p_fr = getindex(pm.model, :p)[f_idx] + q_fr = getindex(pm.model, :q)[f_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + + c1 = @NLconstraint(pm.model, p_fr == g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to)) ) + c2 = @NLconstraint(pm.model, q_fr == -(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to)) ) + return Set([c1, c2]) +end + +""" +Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) + +``` +p[t_idx] == g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])) +q[t_idx] == -(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])) +``` +""" +function constraint_ohms_yt_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) + p_to = getindex(pm.model, :p)[t_idx] + q_to = getindex(pm.model, :q)[t_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + + c1 = @NLconstraint(pm.model, p_to == g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr)) ) + c2 = @NLconstraint(pm.model, q_to == -(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr)) ) + return Set([c1, c2]) +end + +""" +Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) + +``` +p[f_idx] == g*(v[f_bus]/tr)^2 + -g*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -b*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as) +q[f_idx] == -(b+c/2)*(v[f_bus]/tr)^2 + b*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -g*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as) +``` +""" +function constraint_ohms_y_from{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, as) + p_fr = getindex(pm.model, :p)[f_idx] + q_fr = getindex(pm.model, :q)[f_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + + c1 = @NLconstraint(pm.model, p_fr == g*(v_fr/tr)^2 + -g*v_fr/tr*v_to*cos(t_fr-t_to-as) + -b*v_fr/tr*v_to*sin(t_fr-t_to-as) ) + c2 = @NLconstraint(pm.model, q_fr == -(b+c/2)*(v_fr/tr)^2 + b*v_fr/tr*v_to*cos(t_fr-t_to-as) + -g*v_fr/tr*v_to*sin(t_fr-t_to-as) ) + return Set([c1, c2]) +end + +""" +Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) + +``` +p[t_idx] == g*v[t_bus]^2 + -g*v[t_bus]*v[f_bus]/tr*cos(t[t_bus]-t[f_bus]+as) + -b*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as) +q_to == -(b+c/2)*v[t_bus]^2 + b*v[t_bus]*v[f_bus]/tr*cos(t[f_bus]-t[t_bus]+as) + -g*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as) +``` +""" +function constraint_ohms_y_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, as) + p_to = getindex(pm.model, :p)[t_idx] + q_to = getindex(pm.model, :q)[t_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + + c1 = @NLconstraint(pm.model, p_to == g*v_to^2 + -g*v_to*v_fr/tr*cos(t_to-t_fr+as) + -b*v_to*v_fr/tr*sin(t_to-t_fr+as) ) + c2 = @NLconstraint(pm.model, q_to == -(b+c/2)*v_to^2 + b*v_to*v_fr/tr*cos(t_fr-t_to+as) + -g*v_to*v_fr/tr*sin(t_to-t_fr+as) ) + return Set([c1, c2]) +end + +""" +``` +t[f_bus] - t[t_bus] <= angmax +t[f_bus] - t[t_bus] >= angmin +``` +""" +function constraint_phase_angle_difference{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + + c1 = @constraint(pm.model, t_fr - t_to <= angmax) + c2 = @constraint(pm.model, t_fr - t_to >= angmin) + return Set([c1, c2]) +end + +"" +function variable_voltage_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) + variable_phase_angle(pm; kwargs...) + variable_voltage_magnitude(pm; kwargs...) +end + +"do nothing, this model does not have complex voltage constraints" +constraint_voltage_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = Set() + +""" +``` +p[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) +q[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) +``` +""" +function constraint_ohms_yt_from_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) + p_fr = getindex(pm.model, :p)[f_idx] + q_fr = getindex(pm.model, :q)[f_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_z)[i] + + c1 = @NLconstraint(pm.model, p_fr == z*(g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) + c2 = @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) + return Set([c1, c2]) +end + +""" +``` +p[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) +q[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) +``` +""" +function constraint_ohms_yt_to_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) + p_to = getindex(pm.model, :p)[t_idx] + q_to = getindex(pm.model, :q)[t_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_z)[i] + + c1 = @NLconstraint(pm.model, p_to == z*(g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) + c2 = @NLconstraint(pm.model, q_to == z*(-(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) + return Set([c1, c2]) +end + +""" +``` +p_ne[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) +q_ne[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) +``` +""" +function constraint_ohms_yt_from_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) + p_fr = getindex(pm.model, :p_ne)[f_idx] + q_fr = getindex(pm.model, :q_ne)[f_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_ne)[i] + + c1 = @NLconstraint(pm.model, p_fr == z*(g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) + c2 = @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) + return Set([c1, c2]) +end + +""" +``` +p_ne[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) +q_ne[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) +``` +""" +function constraint_ohms_yt_to_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) + p_to = getindex(pm.model, :p_ne)[t_idx] + q_to = getindex(pm.model, :q_ne)[t_idx] + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_ne)[i] + + c1 = @NLconstraint(pm.model, p_to == z*(g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) + c2 = @NLconstraint(pm.model, q_to == z*(-(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) + return Set([c1, c2]) +end + +"`angmin <= line_z[i]*(t[f_bus] - t[t_bus]) <= angmax`" +function constraint_phase_angle_difference_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, angmin, angmax, t_min, t_max) + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_z)[i] + + c1 = @constraint(pm.model, z*(t_fr - t_to) <= angmax) + c2 = @constraint(pm.model, z*(t_fr - t_to) >= angmin) + return Set([c1, c2]) +end + +"`angmin <= line_ne[i]*(t[f_bus] - t[t_bus]) <= angmax`" +function constraint_phase_angle_difference_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, angmin, angmax, t_min, t_max) + t_fr = getindex(pm.model, :t)[f_bus] + t_to = getindex(pm.model, :t)[t_bus] + z = getindex(pm.model, :line_ne)[i] + + c1 = @constraint(pm.model, z*(t_fr - t_to) <= angmax) + c2 = @constraint(pm.model, z*(t_fr - t_to) >= angmin) + return Set([c1, c2]) +end + +""" +``` +p[f_idx] + p[t_idx] >= 0 +q[f_idx] + q[t_idx] >= -c/2*(v[f_bus]^2/tr^2 + v[t_bus]^2) +``` +""" +function constraint_loss_lb{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, c, tr) + v_fr = getindex(pm.model, :v)[f_bus] + v_to = getindex(pm.model, :v)[t_bus] + p_fr = getindex(pm.model, :p)[f_idx] + q_fr = getindex(pm.model, :q)[f_idx] + p_to = getindex(pm.model, :p)[t_idx] + q_to = getindex(pm.model, :q)[t_idx] + + c1 = @constraint(m, p_fr + p_to >= 0) + c2 = @constraint(m, q_fr + q_to >= -c/2*(v_fr^2/tr^2 + v_to^2)) + return Set([c1, c2]) +end + +"" +@compat abstract type APIACPForm <: AbstractACPForm end + +"" +const APIACDCPPowerModel = GenericPowerModel{APIACPForm} + +"default AC constructor" +APIACDCPPowerModel(data::Dict{String,Any}; kwargs...) = + GenericPowerModel(data, APIACPForm; kwargs...) + +"variable: load_factor >= 1.0" +variable_load_factor(pm::GenericPowerModel) = + @variable(pm.model, load_factor >= 1.0, start = 1.0) + +"objective: Max. load_factor" +objective_max_loading(pm::GenericPowerModel) = + @objective(pm.model, Max, getindex(pm.model, :load_factor)) + +"" +function objective_max_loading_voltage_norm(pm::GenericPowerModel) + # Seems to create too much reactive power and makes even small models hard to converge + load_factor = getindex(pm.model, :load_factor) + + scale = length(pm.ref[:bus]) + v = getindex(pm.model, :v) + + return @objective(pm.model, Max, 10*scale*load_factor - sum(((bus["vmin"] + bus["vmax"])/2 - v[i])^2 for (i,bus) in pm.ref[:bus] )) +end + +"" +function objective_max_loading_gen_output(pm::GenericPowerModel) + # Works but adds unnecessary runtime + load_factor = getindex(pm.model, :load_factor) + + scale = length(pm.ref[:gen]) + pg = getindex(pm.model, :pg) + qg = getindex(pm.model, :qg) + + return @NLobjective(pm.model, Max, 100*scale*load_factor - sum( (pg[i]^2 - (2*qg[i])^2)^2 for (i,gen) in pm.ref[:gen] )) +end + +"" +function bounds_tighten_voltage(pm::APIACDCPPowerModel; epsilon = 0.001) + for (i,bus) in pm.ref[:bus] + v = getindex(pm.model, :v)[i] + setupperbound(v, bus["vmax"]*(1.0-epsilon)) + setlowerbound(v, bus["vmin"]*(1.0+epsilon)) + end +end + +"" +function upperbound_negative_active_generation(pm::APIACDCPPowerModel) + for (i,gen) in pm.ref[:gen] + if gen["pmax"] <= 0 + pg = getindex(pm.model, :pg)[i] + setupperbound(pg, gen["pmax"]) + end + end +end + +"" +function constraint_kcl_shunt_scaled(pm::APIACDCPPowerModel, bus) + i = bus["index"] + bus_arcs = pm.ref[:bus_arcs][i] + bus_gens = pm.ref[:bus_gens][i] + + load_factor = getindex(pm.model, :load_factor) + v = getindex(pm.model, :v) + p = getindex(pm.model, :p) + q = getindex(pm.model, :q) + pg = getindex(pm.model, :pg) + qg = getindex(pm.model, :qg) + + if bus["pd"] > 0 && bus["qd"] > 0 + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - bus["pd"]*load_factor - bus["gs"]*v[i]^2) + else + # super fallback impl + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - bus["pd"] - bus["gs"]*v[i]^2) + end + + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - bus["qd"] + bus["bs"]*v[i]^2) + + return Set([c1, c2]) +end + +"" +function get_solution(pm::APIACDCPPowerModel) + # super fallback + sol = init_solution(pm) + add_bus_voltage_setpoint(sol, pm) + add_generator_power_setpoint(sol, pm) + add_branch_flow_setpoint(sol, pm) + + # extension + add_bus_demand_setpoint(sol, pm) + + return sol +end + +"" +function add_bus_demand_setpoint(sol, pm::APIACDCPPowerModel) + mva_base = pm.data["baseMVA"] + add_setpoint(sol, pm, "bus", "bus_i", "pd", :load_factor; default_value = (item) -> item["pd"], scale = (x,item) -> item["pd"] > 0 && item["qd"] > 0 ? x*item["pd"] : item["pd"], extract_var = (var,idx,item) -> var) + add_setpoint(sol, pm, "bus", "bus_i", "qd", :load_factor; default_value = (item) -> item["qd"], scale = (x,item) -> item["qd"], extract_var = (var,idx,item) -> var) +end From a13a1cae47237d89dafde49f26d5e1abc0a5c960 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Thu, 20 Jul 2017 10:17:08 +0200 Subject: [PATCH 04/23] Add DC arcs and buspairs to base.jl --- src/core/base.jl | 63 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/core/base.jl b/src/core/base.jl index 83981706b..ee40f6ba5 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -15,7 +15,7 @@ export ``` type GenericPowerModel{T<:AbstractPowerFormulation} model::JuMP.Model - data::Dict{String,Any} + data::Dict{String,Any} setting::Dict{String,Any} solution::Dict{String,Any} ref::Dict{Symbol,Any} # reference data @@ -181,6 +181,14 @@ function build_ref(data::Dict{String,Any}) ref[:arcs_to] = [(i,branch["t_bus"],branch["f_bus"]) for (i,branch) in ref[:branch]] ref[:arcs] = [ref[:arcs_from]; ref[:arcs_to]] +#############################DC LINES############## + if haskey(ref, :dcline) + ref[:arcs_from_dc] = [(i,dcline["f_bus"],dcline["t_bus"]) for (i,dcline) in ref[:dcline]] + ref[:arcs_to_dc] = [(i,dcline["t_bus"],dcline["f_bus"]) for (i,dcline) in ref[:dcline]] + ref[:arcs_dc] = [ref[:arcs_from]; ref[:arcs_to]] + end +################################################### + bus_gens = Dict([(i, []) for (i,bus) in ref[:bus]]) for (i,gen) in ref[:gen] push!(bus_gens[gen["gen_bus"]], i) @@ -193,6 +201,16 @@ function build_ref(data::Dict{String,Any}) end ref[:bus_arcs] = bus_arcs +######################### DC LINES ################################### + if haskey(ref, :dcline) + bus_arcs_dc = Dict([(i, []) for (i,bus) in ref[:bus]]) + for (l,i,j) in ref[:arcs_dc] + push!(bus_arcs_dc[i], (l,i,j)) + end + ref[:bus_arcs_dc] = bus_arcs_dc + end +################################################################# + ref_bus = Union{} for (k,v) in ref[:bus] if v["bus_type"] == 3 @@ -203,6 +221,11 @@ function build_ref(data::Dict{String,Any}) ref[:ref_bus] = ref_bus ref[:buspairs] = buspair_parameters(ref[:arcs_from], ref[:branch], ref[:bus]) + ############################ DC LINES########################################## + if haskey(ref, :dcline) + ref[:buspairs_dc] = buspair_parameters_dc(ref[:arcs_from_dc], ref[:dcline], ref[:bus]) + end + ############################################################################### if haskey(ref, :ne_branch) ref[:ne_branch] = filter((i, branch) -> branch["br_status"] == 1 && branch["f_bus"] in keys(ref[:bus]) && branch["t_bus"] in keys(ref[:bus]), ref[:ne_branch]) @@ -254,3 +277,41 @@ function buspair_parameters(arcs_from, branches, buses) return buspairs end + +"compute bus pair level structures for DC" +function buspair_parameters_dc(arcs_from_dc, dclines, buses) + buspair_indexes = collect(Set([(i,j) for (l,i,j) in arcs_from_dc])) + + bp_angmin = Dict([(bp, -Inf) for bp in buspair_indexes]) + bp_angmax = Dict([(bp, Inf) for bp in buspair_indexes]) + bp_line = Dict([(bp, Inf) for bp in buspair_indexes]) + + for (l,dcline) in dclines + i = dcline["f_bus"] + j = dcline["t_bus"] + + bp_line[(i,j)] = min(bp_line[(i,j)], l) + end + + buspairs_dc = Dict([((i,j), Dict( + "line"=>bp_line[(i,j)], + "pmin"=>dclines[bp_line[(i,j)]]["pmin"], + "pmax"=>dclines[bp_line[(i,j)]]["pmax"], + "qminf"=>dclines[bp_line[(i,j)]]["qminf"], + "qmaxf"=>dclines[bp_line[(i,j)]]["qmaxf"], + "qmint"=>dclines[bp_line[(i,j)]]["qmint"], + "qmaxt"=>dclines[bp_line[(i,j)]]["qmaxt"], + "pf"=>dclines[bp_line[(i,j)]]["pf"], + "pt"=>dclines[bp_line[(i,j)]]["pt"], + "qf"=>dclines[bp_line[(i,j)]]["qf"], + "qt"=>dclines[bp_line[(i,j)]]["qt"], + "vf"=>dclines[bp_line[(i,j)]]["vf"], + "vt"=>dclines[bp_line[(i,j)]]["vt"], + "v_from_min"=>buses[i]["vmin"], + "v_from_max"=>buses[i]["vmax"], + "v_to_min"=>buses[j]["vmin"], + "v_to_max"=>buses[j]["vmax"] + )) for (i,j) in buspair_indexes]) + + return buspairs_dc +end From 733fb66a0b13ccd30b8075c705706403b816eafe Mon Sep 17 00:00:00 2001 From: hakanergun Date: Thu, 20 Jul 2017 11:21:37 +0200 Subject: [PATCH 05/23] Consitent pmin, pmax fromulation For the to and From side of the DC Lines --- src/core/base.jl | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/core/base.jl b/src/core/base.jl index ee40f6ba5..984b30b36 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -285,18 +285,38 @@ function buspair_parameters_dc(arcs_from_dc, dclines, buses) bp_angmin = Dict([(bp, -Inf) for bp in buspair_indexes]) bp_angmax = Dict([(bp, Inf) for bp in buspair_indexes]) bp_line = Dict([(bp, Inf) for bp in buspair_indexes]) + pmint = Dict([(bp, Inf) for bp in buspair_indexes]) + pminf = Dict([(bp, Inf) for bp in buspair_indexes]) + pmaxt = Dict([(bp, Inf) for bp in buspair_indexes]) + pmaxf = Dict([(bp, Inf) for bp in buspair_indexes]) for (l,dcline) in dclines i = dcline["f_bus"] j = dcline["t_bus"] bp_line[(i,j)] = min(bp_line[(i,j)], l) + if dcline["pmin"] > 0 + pminf[(i,j)]=>dclines[bp_line[(i,j)]]["pmin"] + pmint[(i,j)]=>-min(abs(pminf[(i,j)]),abs(dcline["pmax"])) + else + pmint[(i,j)]=>dclines[bp_line[(i,j)]]["pmin"] + pminf[(i,j)]=>-min(abs(pmint[(i,j)]),abs(dcline["pmax"])) + end + if dcline["pmax"] > 0 + pmaxf[(i,j)]=>dclines[bp_line[(i,j)]]["pmax"] + pmaxt[(i,j)]=>max(abs(pmaxf[(i,j)]),abs(dcline["pmin"])) + else + pmaxt[(i,j)]=>dclines[bp_line[(i,j)]]["pmax"] + pmaxf[(i,j)]=>max(abs(pmaxt[(i,j)]),abs(dcline["pmin"])) + end end buspairs_dc = Dict([((i,j), Dict( "line"=>bp_line[(i,j)], - "pmin"=>dclines[bp_line[(i,j)]]["pmin"], - "pmax"=>dclines[bp_line[(i,j)]]["pmax"], + "pmint"=>pmint[(i,j)], + "pmaxt"=>pmaxt[(i,j)], + "pminf"=>pminf[(i,j)], + "pmaxf"=>pmaxf[(i,j)], "qminf"=>dclines[bp_line[(i,j)]]["qminf"], "qmaxf"=>dclines[bp_line[(i,j)]]["qmaxf"], "qmint"=>dclines[bp_line[(i,j)]]["qmint"], From 8b83583bb505b26008784e28b3c8410f4009266b Mon Sep 17 00:00:00 2001 From: hakanergun Date: Thu, 20 Jul 2017 16:54:56 +0200 Subject: [PATCH 06/23] First draft of Matpower compatible DC line extension Needs to be validated!!!! --- src/core/base.jl | 24 +++------- src/core/constraint.jl | 16 ++++++- src/core/constraint_template.jl | 80 +++++++++++++++++++++++++++------ src/core/solution.jl | 4 ++ src/core/variable.jl | 36 ++++++++++++++- src/form/acdcp.jl | 40 ++++++++++++++++- src/io/matpower.jl | 20 ++++++++- src/prob/opf.jl | 8 +++- src/prob/pf.jl | 3 +- 9 files changed, 192 insertions(+), 39 deletions(-) diff --git a/src/core/base.jl b/src/core/base.jl index 984b30b36..c1fa72724 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -185,7 +185,7 @@ function build_ref(data::Dict{String,Any}) if haskey(ref, :dcline) ref[:arcs_from_dc] = [(i,dcline["f_bus"],dcline["t_bus"]) for (i,dcline) in ref[:dcline]] ref[:arcs_to_dc] = [(i,dcline["t_bus"],dcline["f_bus"]) for (i,dcline) in ref[:dcline]] - ref[:arcs_dc] = [ref[:arcs_from]; ref[:arcs_to]] + ref[:arcs_dc] = [ref[:arcs_from_dc]; ref[:arcs_to_dc]] end ################################################### @@ -295,28 +295,14 @@ function buspair_parameters_dc(arcs_from_dc, dclines, buses) j = dcline["t_bus"] bp_line[(i,j)] = min(bp_line[(i,j)], l) - if dcline["pmin"] > 0 - pminf[(i,j)]=>dclines[bp_line[(i,j)]]["pmin"] - pmint[(i,j)]=>-min(abs(pminf[(i,j)]),abs(dcline["pmax"])) - else - pmint[(i,j)]=>dclines[bp_line[(i,j)]]["pmin"] - pminf[(i,j)]=>-min(abs(pmint[(i,j)]),abs(dcline["pmax"])) - end - if dcline["pmax"] > 0 - pmaxf[(i,j)]=>dclines[bp_line[(i,j)]]["pmax"] - pmaxt[(i,j)]=>max(abs(pmaxf[(i,j)]),abs(dcline["pmin"])) - else - pmaxt[(i,j)]=>dclines[bp_line[(i,j)]]["pmax"] - pmaxf[(i,j)]=>max(abs(pmaxt[(i,j)]),abs(dcline["pmin"])) - end end buspairs_dc = Dict([((i,j), Dict( "line"=>bp_line[(i,j)], - "pmint"=>pmint[(i,j)], - "pmaxt"=>pmaxt[(i,j)], - "pminf"=>pminf[(i,j)], - "pmaxf"=>pmaxf[(i,j)], + "pminf"=>dclines[bp_line[(i,j)]]["pminf"], + "pmaxf"=>dclines[bp_line[(i,j)]]["pmaxf"], + "pmint"=>dclines[bp_line[(i,j)]]["pmint"], + "pmaxt"=>dclines[bp_line[(i,j)]]["pmaxt"], "qminf"=>dclines[bp_line[(i,j)]]["qminf"], "qmaxf"=>dclines[bp_line[(i,j)]]["qmaxf"], "qmint"=>dclines[bp_line[(i,j)]]["qmint"], diff --git a/src/core/constraint.jl b/src/core/constraint.jl index 7c1887260..8e3bc39d3 100644 --- a/src/core/constraint.jl +++ b/src/core/constraint.jl @@ -1,6 +1,6 @@ ############################################################################### # This file defines commonly used constraints for power flow models -# These constraints generally assume that the model contains p and q values +# These constraints generally assume that the model contains p and q values # for branches line flows and bus flow conservation ############################################################################### @@ -21,6 +21,20 @@ function constraint_thermal_limit_to(pm::GenericPowerModel, t_idx, rate_a) return Set([c]) end +function constraint_thermal_limit_dc(pm::GenericPowerModel, f_idx, t_idx, f_bus, t_bus, br_status, pmaxf, pmaxt, pminf, pmint, qmaxf, qmaxt, qminf, qmint) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + q_fr = getindex(pm.model, :q_dc)[f_idx] + q_to = getindex(pm.model, :q_dc)[t_idx] + + c1 = @constraint(pm.model, br_status * pminf <= p_fr <= br_status * pmaxf) + c2 = @constraint(pm.model, br_status * pmint <= p_to <= br_status * pmaxt) + c3 = @constraint(pm.model, br_status * qminf <= q_fr <= br_status * qmaxf) + c4 = @constraint(pm.model, br_status * qmint <= q_to <= br_status * qmaxt) + + return Set([c1,c2,c3,c4]) +end + "`norm([p[f_idx]; q[f_idx]]) <= rate_a`" function constraint_thermal_limit_from{T <: AbstractConicPowerFormulation}(pm::GenericPowerModel{T}, f_idx, rate_a) p_fr = getindex(pm.model, :p)[f_idx] diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 596f389e9..9679d6bda 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -1,9 +1,9 @@ # # Constraint Template Definitions -# Constraint templates help simplify data wrangling across multiple Power +# Constraint templates help simplify data wrangling across multiple Power # Flow formulations by providing an abstraction layer between the network data -# and network constraint definitions. The constraint template's job is to -# extract the required parameters from a given network data structure and +# and network constraint definitions. The constraint template's job is to +# extract the required parameters from a given network data structure and # pass the data as named arguments to the Power Flow formulations. # # Constraint templates should always be defined over "GenericPowerModel" @@ -56,7 +56,7 @@ function constraint_kcl_shunt_ne(pm::GenericPowerModel, bus) return constraint_kcl_shunt_ne(pm, i, bus_arcs, bus_arcs_ne, bus_gens, bus["pd"], bus["qd"], bus["gs"], bus["bs"]) end -### Branch - Ohm's Law Constraints ### +### Branch - Ohm's Law Constraints ### "" function constraint_ohms_yt_from(pm::GenericPowerModel, branch) @@ -74,6 +74,38 @@ function constraint_ohms_yt_from(pm::GenericPowerModel, branch) return constraint_ohms_yt_from(pm, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) end +### Branch - Loss Constraints DC LINES### + +"" +function constraint_ohms_yt_dc(pm::GenericPowerModel, dcline) + i = dcline["index"] + f_bus = dcline["f_bus"] + t_bus = dcline["t_bus"] + f_idx = (i, f_bus, t_bus) + t_idx = (i, t_bus, f_bus) + br_status = dcline["br_status"] + loss0 = dcline["loss0"] + loss1 = dcline["loss1"] + + return constraint_ohms_yt_dc(pm, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) +end + + +### Branch - Voltage Constraints DC LINES### + +"" +function constraint_voltage_dc(pm::GenericPowerModel, dcline) + i = dcline["index"] + f_bus = dcline["f_bus"] + t_bus = dcline["t_bus"] + br_status = dcline["br_status"] + vt = dcline["vf"] + vf = dcline["vt"] + + return constraint_voltage_dc(pm, f_bus, t_bus, br_status, vf, vt) +end + + "" function constraint_ohms_yt_to(pm::GenericPowerModel, branch) i = branch["index"] @@ -122,7 +154,7 @@ function constraint_ohms_y_to(pm::GenericPowerModel, branch) return constraint_ohms_y_to(pm, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, as) end -### Branch - On/Off Ohm's Law Constraints ### +### Branch - On/Off Ohm's Law Constraints ### "" function constraint_ohms_yt_from_on_off(pm::GenericPowerModel, branch) @@ -135,7 +167,7 @@ function constraint_ohms_yt_from_on_off(pm::GenericPowerModel, branch) g, b = calc_branch_y(branch) tr, ti = calc_branch_t(branch) c = branch["br_b"] - tm = branch["tap"]^2 + tm = branch["tap"]^2 t_min = pm.ref[:off_angmin] t_max = pm.ref[:off_angmax] @@ -154,7 +186,7 @@ function constraint_ohms_yt_to_on_off(pm::GenericPowerModel, branch) g, b = calc_branch_y(branch) tr, ti = calc_branch_t(branch) c = branch["br_b"] - tm = branch["tap"]^2 + tm = branch["tap"]^2 t_min = pm.ref[:off_angmin] t_max = pm.ref[:off_angmax] @@ -192,7 +224,7 @@ function constraint_ohms_yt_to_ne(pm::GenericPowerModel, branch) g, b = calc_branch_y(branch) tr, ti = calc_branch_t(branch) c = branch["br_b"] - tm = branch["tap"]^2 + tm = branch["tap"]^2 t_min = pm.ref[:off_angmin] t_max = pm.ref[:off_angmax] @@ -200,7 +232,7 @@ function constraint_ohms_yt_to_ne(pm::GenericPowerModel, branch) return constraint_ohms_yt_to_ne(pm, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) end -### Branch - Current ### +### Branch - Current ### "" function constraint_power_magnitude_sqr(pm::GenericPowerModel, branch) @@ -226,12 +258,12 @@ function constraint_power_magnitude_link(pm::GenericPowerModel, branch) g, b = calc_branch_y(branch) tr, ti = calc_branch_t(branch) c = branch["br_b"] - tm = branch["tap"]^2 + tm = branch["tap"]^2 return constraint_power_magnitude_link(pm, f_bus, t_bus, f_idx, g, b, c, tr, ti, tm) end -### Branch - Thermal Limit Constraints ### +### Branch - Thermal Limit Constraints ### "" function constraint_thermal_limit_from(pm::GenericPowerModel, branch; scale = 1.0) @@ -243,6 +275,28 @@ function constraint_thermal_limit_from(pm::GenericPowerModel, branch; scale = 1. return constraint_thermal_limit_from(pm, f_idx, branch["rate_a"]*scale) end +### Branch - Thermal Limit Constraints DC LINES### + +"" +function constraint_thermal_limit_dc(pm::GenericPowerModel, dcline; scale = 1.0) + i = dcline["index"] + f_bus = dcline["f_bus"] + t_bus = dcline["t_bus"] + br_status = dcline["br_status"] + pmaxf = dcline["pmaxf"] + pmaxt = dcline["pmaxt"] + pminf = dcline["pminf"] + pmint = dcline["pmint"] + qmaxf = dcline["qmaxf"] + qmaxt = dcline["qmaxt"] + qminf = dcline["qminf"] + qmint = dcline["qmint"] + f_idx = (i, f_bus, t_bus) + t_idx = (i, t_bus, f_bus) + + return constraint_thermal_limit_dc(pm, f_idx, t_idx, f_bus, t_bus, br_status, pmaxf*scale, pmaxt*scale, pminf*scale, pmint*scale, qmaxf*scale, qmaxt*scale, qminf*scale, qmint*scale) +end + "" function constraint_thermal_limit_to(pm::GenericPowerModel, branch; scale = 1.0) i = branch["index"] @@ -293,7 +347,7 @@ function constraint_thermal_limit_to_ne(pm::GenericPowerModel, branch) return constraint_thermal_limit_to_ne(pm, i, t_idx, branch["rate_a"]) end -### Branch - Phase Angle Difference Constraints ### +### Branch - Phase Angle Difference Constraints ### "" function constraint_phase_angle_difference(pm::GenericPowerModel, branch) @@ -333,7 +387,7 @@ function constraint_phase_angle_difference_ne(pm::GenericPowerModel, branch) return constraint_phase_angle_difference_ne(pm, i, f_bus, t_bus, branch["angmin"], branch["angmax"], t_min, t_max) end -### Branch - Loss Constraints ### +### Branch - Loss Constraints ### "" function constraint_loss_lb(pm::GenericPowerModel, branch) diff --git a/src/core/solution.jl b/src/core/solution.jl index 397eb7731..5272b3745 100644 --- a/src/core/solution.jl +++ b/src/core/solution.jl @@ -98,6 +98,10 @@ function add_branch_status_setpoint(sol, pm::GenericPowerModel) add_setpoint(sol, pm, "branch", "index", "br_status", :line_z; default_value = (item) -> 1) end +function add_branch_status_setpoint_dc(sol, pm::GenericPowerModel) + add_setpoint(sol, pm, "dcline", "index", "br_status", :line_z; default_value = (item) -> 1) +end + "" function add_branch_ne_setpoint(sol, pm::GenericPowerModel) add_setpoint(sol, pm, "ne_branch", "index", "built", :line_ne; default_value = (item) -> 1) diff --git a/src/core/variable.jl b/src/core/variable.jl index 6e1c62ec2..113025522 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -86,6 +86,7 @@ function variable_line_flow(pm::GenericPowerModel; kwargs...) variable_reactive_line_flow(pm; kwargs...) end + "variable: `p[l,i,j]` for `(l,i,j)` in `arcs`" function variable_active_line_flow(pm::GenericPowerModel; bounded = true) if bounded @@ -106,6 +107,40 @@ function variable_reactive_line_flow(pm::GenericPowerModel; bounded = true) return q end +############## DC Lines ############################################ +function variable_line_flow_dc(pm::GenericPowerModel; kwargs...) + variable_active_line_flow_dc(pm; kwargs...) + variable_reactive_line_flow_dc(pm; kwargs...) +end + +"variable: `p_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" +function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) + if bounded + @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]]) + else + #@variable(pm.model, p[(l,i,j) in pm.ref[:arcs]], start = getstart(pm.ref[:branch], l, "p_start")) + @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]]) + end + @show pm.ref[:arcs_dc] + @show p_dc + return p_dc +end + +"variable: `q_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" +function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) + if bounded + @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]]) + #@constraint(pm.model, pm.ref[:buspairs_dc][i,j]["qmint"] <= q_dc[(l,i,j) in pm.ref[:arcs_to_dc]] <= pm.ref[:buspairs_dc][i,j]["qmaxt"]) + #@constraint(pm.model, pm.ref[:buspairs_dc][i,j]["qminf"] <= q_dc[(l,i,j) in pm.ref[:arcs_from_dc]] <= pm.ref[:buspairs_dc][i,j]["qmaxf"]) + else + #@variable(pm.model, p[(l,i,j) in pm.ref[:arcs]], start = getstart(pm.ref[:branch], l, "p_start")) + @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]]) + end + return q_dc +end + +################################################################## + "generates variables for both `active` and `reactive` `line_flow_ne`" function variable_line_flow_ne(pm::GenericPowerModel; kwargs...) variable_active_line_flow_ne(pm; kwargs...) @@ -136,4 +171,3 @@ function variable_line_ne(pm::GenericPowerModel) @variable(pm.model, 0 <= line_ne[l in keys(branches)] <= 1, Int, start = getstart(branches, l, "line_tnep_start", 1.0)) return line_ne end - diff --git a/src/form/acdcp.jl b/src/form/acdcp.jl index 287d7a39b..8efeb793d 100644 --- a/src/form/acdcp.jl +++ b/src/form/acdcp.jl @@ -80,9 +80,11 @@ function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, q_ne = getindex(pm.model, :q_ne) pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) return Set([c1, c2]) end @@ -107,6 +109,40 @@ function constraint_ohms_yt_from{T <: AbstractACPForm}(pm::GenericPowerModel{T}, return Set([c1, c2]) end +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +p_fr + p_to == loss0 + loss1 * p_fr +``` +""" +function constraint_ohms_yt_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, p_fr + p_to == loss0 + loss1 .* p_fr) + return Set([c1]) +end + +""" +Creates Voltage constraints for DC Lines (AC bus seen as PV node) + +``` +if br_status = 1: v_f == vf +if br_status = 1: v_t == vt +``` +""" +function constraint_voltage_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, br_status, vf, vt) + v_f = getindex(pm.model, :v)[f_bus] + v_t = getindex(pm.model, :v)[t_bus] + + c1 = @constraint(pm.model, br_status * v_f == br_status * vf) + c2 = @constraint(pm.model, br_status * v_t == br_status * vt) + + return Set([c1,c2]) +end + + """ Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 7a869cc8a..8ce2a11b4 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -494,6 +494,21 @@ function parse_matpower_data(data_string::String) dclines = [] for (i, dcline_row) in enumerate(parsed_matrix["data"]) + if parse(Float64, dcline_row[10]) > 0 + pminf = parse(Float64, dcline_row[10]) + pmint = -min(abs(parse(Float64, dcline_row[10])),abs(parse(Float64, dcline_row[11]))) + else + pmint = parse(Float64, dcline_row[10]) + pminf = -min(abs(parse(Float64, dcline_row[10])),abs(parse(Float64, dcline_row[11]))) + end + if parse(Float64, dcline_row[11]) > 0 + pmaxf = parse(Float64, dcline_row[11]) + pmaxt = max(abs(parse(Float64, dcline_row[11])),abs(parse(Float64, dcline_row[10]))) + else + pmaxt = parse(Float64, dcline_row[11]) + pmaxf = max(abs(parse(Float64, dcline_row[11])),abs(parse(Float64, dcline_row[10]))) + end + dcline_data = Dict{String,Any}( "index" => i, "f_bus" => parse(Int, dcline_row[1]), @@ -505,7 +520,10 @@ function parse_matpower_data(data_string::String) "qt" => parse(Float64, dcline_row[7]), "vf" => parse(Float64, dcline_row[8]), "vt" => parse(Float64, dcline_row[9]), - "pmin" => parse(Float64, dcline_row[10]), + "pmint" => pmint, + "pminf" => pminf, + "pmaxt" => pmaxt, + "pmaxf" => pmaxf, "pmax" => parse(Float64, dcline_row[11]), "qminf" => parse(Float64, dcline_row[12]), "qmaxf" => parse(Float64, dcline_row[13]), diff --git a/src/prob/opf.jl b/src/prob/opf.jl index 7b57a0a9b..392d2795d 100644 --- a/src/prob/opf.jl +++ b/src/prob/opf.jl @@ -12,7 +12,7 @@ end "" function run_opf(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_opf; kwargs...) + return run_generic_model(file, model_constructor, solver, post_opf; kwargs...) end "" @@ -20,6 +20,7 @@ function post_opf(pm::GenericPowerModel) variable_voltage(pm) variable_generation(pm) variable_line_flow(pm) + variable_line_flow_dc(pm) objective_min_fuel_cost(pm) @@ -39,4 +40,9 @@ function post_opf(pm::GenericPowerModel) constraint_thermal_limit_from(pm, branch) constraint_thermal_limit_to(pm, branch) end + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + constraint_thermal_limit_dc(pm, dcline) + constraint_voltage_dc(pm, dcline) + end end diff --git a/src/prob/pf.jl b/src/prob/pf.jl index 9b3136369..4139d9c07 100644 --- a/src/prob/pf.jl +++ b/src/prob/pf.jl @@ -12,7 +12,7 @@ end "" function run_pf(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_pf; kwargs...) + return run_generic_model(file, model_constructor, solver, post_pf; kwargs...) end "" @@ -20,6 +20,7 @@ function post_pf(pm::GenericPowerModel) variable_voltage(pm, bounded = false) variable_generation(pm, bounded = false) variable_line_flow(pm, bounded = false) + variable_line_flow_dc(pm, bounded = false) constraint_theta_ref(pm) constraint_voltage_magnitude_setpoint(pm, pm.ref[:bus][pm.ref[:ref_bus]]) From 804e3e91ae2e14454bf82a20e5bb24daf73cd4d0 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Mon, 24 Jul 2017 16:46:27 +0200 Subject: [PATCH 07/23] Validating DC Line implementation - Matpower OPF compoatible, in AC and DC OPF - WR & WRM formulations updated and tested (no validation possible) - DC Line output included --- src/core/constraint.jl | 14 - src/core/constraint_template.jl | 41 +-- src/core/data.jl | 17 ++ src/core/solution.jl | 14 + src/core/variable.jl | 45 +++- src/form/acdcp.jl | 458 -------------------------------- src/form/acp.jl | 35 ++- src/form/dcp.jl | 22 +- src/form/wr.jl | 41 ++- src/form/wrm.jl | 25 +- src/io/matpower.jl | 1 - src/prob/opf.jl | 2 - test/data/case3_dc.m | 85 ++++++ test/data/case5_dc.m | 65 +++++ 14 files changed, 312 insertions(+), 553 deletions(-) delete mode 100644 src/form/acdcp.jl create mode 100644 test/data/case3_dc.m create mode 100644 test/data/case5_dc.m diff --git a/src/core/constraint.jl b/src/core/constraint.jl index 8e3bc39d3..74a955cea 100644 --- a/src/core/constraint.jl +++ b/src/core/constraint.jl @@ -21,20 +21,6 @@ function constraint_thermal_limit_to(pm::GenericPowerModel, t_idx, rate_a) return Set([c]) end -function constraint_thermal_limit_dc(pm::GenericPowerModel, f_idx, t_idx, f_bus, t_bus, br_status, pmaxf, pmaxt, pminf, pmint, qmaxf, qmaxt, qminf, qmint) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - q_fr = getindex(pm.model, :q_dc)[f_idx] - q_to = getindex(pm.model, :q_dc)[t_idx] - - c1 = @constraint(pm.model, br_status * pminf <= p_fr <= br_status * pmaxf) - c2 = @constraint(pm.model, br_status * pmint <= p_to <= br_status * pmaxt) - c3 = @constraint(pm.model, br_status * qminf <= q_fr <= br_status * qmaxf) - c4 = @constraint(pm.model, br_status * qmint <= q_to <= br_status * qmaxt) - - return Set([c1,c2,c3,c4]) -end - "`norm([p[f_idx]; q[f_idx]]) <= rate_a`" function constraint_thermal_limit_from{T <: AbstractConicPowerFormulation}(pm::GenericPowerModel{T}, f_idx, rate_a) p_fr = getindex(pm.model, :p)[f_idx] diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 31fdd3b6e..649753c34 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -48,9 +48,10 @@ end function constraint_kcl_shunt(pm::GenericPowerModel, bus) i = bus["index"] bus_arcs = pm.ref[:bus_arcs][i] + bus_arcs_dc = pm.ref[:bus_arcs_dc][i] bus_gens = pm.ref[:bus_gens][i] - return constraint_kcl_shunt(pm, i, bus_arcs, bus_gens, bus["pd"], bus["qd"], bus["gs"], bus["bs"]) + return constraint_kcl_shunt(pm, i, bus_arcs, bus_arcs_dc, bus_gens, bus["pd"], bus["qd"], bus["gs"], bus["bs"]) end "" @@ -97,22 +98,6 @@ function constraint_ohms_yt_dc(pm::GenericPowerModel, dcline) return constraint_ohms_yt_dc(pm, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) end - -### Branch - Voltage Constraints DC LINES### - -"" -function constraint_voltage_dc(pm::GenericPowerModel, dcline) - i = dcline["index"] - f_bus = dcline["f_bus"] - t_bus = dcline["t_bus"] - br_status = dcline["br_status"] - vt = dcline["vf"] - vf = dcline["vt"] - - return constraint_voltage_dc(pm, f_bus, t_bus, br_status, vf, vt) -end - - "" function constraint_ohms_yt_to(pm::GenericPowerModel, branch) i = branch["index"] @@ -307,28 +292,6 @@ function constraint_thermal_limit_from(pm::GenericPowerModel, branch; scale = 1. return constraint_thermal_limit_from(pm, f_idx, branch["rate_a"]*scale) end -### Branch - Thermal Limit Constraints DC LINES### - -"" -function constraint_thermal_limit_dc(pm::GenericPowerModel, dcline; scale = 1.0) - i = dcline["index"] - f_bus = dcline["f_bus"] - t_bus = dcline["t_bus"] - br_status = dcline["br_status"] - pmaxf = dcline["pmaxf"] - pmaxt = dcline["pmaxt"] - pminf = dcline["pminf"] - pmint = dcline["pmint"] - qmaxf = dcline["qmaxf"] - qmaxt = dcline["qmaxt"] - qminf = dcline["qminf"] - qmint = dcline["qmint"] - f_idx = (i, f_bus, t_bus) - t_idx = (i, t_bus, f_bus) - - return constraint_thermal_limit_dc(pm, f_idx, t_idx, f_bus, t_bus, br_status, pmaxf*scale, pmaxt*scale, pminf*scale, pmint*scale, qmaxf*scale, qmaxt*scale, qminf*scale, qmint*scale) -end - "" function constraint_thermal_limit_to(pm::GenericPowerModel, branch; scale = 1.0) i = branch["index"] diff --git a/src/core/data.jl b/src/core/data.jl index 5a16e87cd..2240e46db 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -136,6 +136,11 @@ function make_per_unit(data::Dict{String,Any}) if haskey(data, "branch") append!(branches, values(data["branch"])) end + dclines =[] + if haskey(data, "dcline") + append!(dclines, values(data["dcline"])) + end + if haskey(data, "ne_branch") append!(branches, values(data["ne_branch"])) end @@ -150,6 +155,18 @@ function make_per_unit(data::Dict{String,Any}) apply_func(branch, "angmin", deg2rad) end + for dcline in dclines + apply_func(dcline, "loss0", rescale) + apply_func(dcline, "pmaxt", rescale) + apply_func(dcline, "pmint", rescale) + apply_func(dcline, "pmaxf", rescale) + apply_func(dcline, "pminf", rescale) + apply_func(dcline, "qmaxt", rescale) + apply_func(dcline, "qmint", rescale) + apply_func(dcline, "qmaxf", rescale) + apply_func(dcline, "qminf", rescale) + end + if haskey(data, "gen") for (i, gen) in data["gen"] apply_func(gen, "pg", rescale) diff --git a/src/core/solution.jl b/src/core/solution.jl index 5272b3745..4ce1bd968 100644 --- a/src/core/solution.jl +++ b/src/core/solution.jl @@ -44,6 +44,7 @@ function get_solution(pm::GenericPowerModel) add_bus_voltage_setpoint(sol, pm) add_generator_power_setpoint(sol, pm) add_branch_flow_setpoint(sol, pm) + add_branch_flow_setpoint_dc(sol, pm) return sol end @@ -80,6 +81,19 @@ function add_branch_flow_setpoint(sol, pm::GenericPowerModel) end end +"" +function add_branch_flow_setpoint_dc(sol, pm::GenericPowerModel) + # check the line flows were requested + if haskey(pm.setting, "output") && haskey(pm.setting["output"], "line_flows") && pm.setting["output"]["line_flows"] == true + mva_base = pm.data["baseMVA"] + + add_setpoint(sol, pm, "dcline", "index", "p_from", :p_dc; scale = (x,item) -> x*mva_base, extract_var = (var,idx,item) -> var[(idx, item["f_bus"], item["t_bus"])]) + add_setpoint(sol, pm, "dcline", "index", "q_from", :q_dc; scale = (x,item) -> x*mva_base, extract_var = (var,idx,item) -> var[(idx, item["f_bus"], item["t_bus"])]) + add_setpoint(sol, pm, "dcline", "index", "p_to", :p_dc; scale = (x,item) -> x*mva_base, extract_var = (var,idx,item) -> var[(idx, item["t_bus"], item["f_bus"])]) + add_setpoint(sol, pm, "dcline", "index", "q_to", :q_dc; scale = (x,item) -> x*mva_base, extract_var = (var,idx,item) -> var[(idx, item["t_bus"], item["f_bus"])]) + end +end + "" function add_branch_flow_setpoint_ne(sol, pm::GenericPowerModel) # check the line flows were requested diff --git a/src/core/variable.jl b/src/core/variable.jl index 5bb414904..aeccf0230 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -137,25 +137,50 @@ end "variable: `p_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) if bounded - @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]]) + pmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + pref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + pmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + loss0 = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) + for (l,i,j) in pm.ref[:arcs_from_dc] + pmin[(l,i,j)] = pm.ref[:dcline][l]["pminf"] + pmax[(l,i,j)] = pm.ref[:dcline][l]["pmaxf"] + pmin[(l,j,i)] = pm.ref[:dcline][l]["pmint"] + pmax[(l,j,i)] = pm.ref[:dcline][l]["pmaxt"] + pref[(l,i,j)] = pm.ref[:dcline][l]["pf"] + pref[(l,j,i)] = pm.ref[:dcline][l]["pt"] + loss0[(l,i,j)] = 0 + loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] + br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] + br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] + end + @variable(pm.model, br_status[(l,i,j)] * (pmin[(l,i,j)] + (loss0[(l,i,j)])) <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * (pmax[(l,i,j)] + (loss0[(l,i,j)])), start = pref[(l,i,j)]) else - #@variable(pm.model, p[(l,i,j) in pm.ref[:arcs]], start = getstart(pm.ref[:branch], l, "p_start")) - @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]]) + @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]], start = 0) end - @show pm.ref[:arcs_dc] - @show p_dc return p_dc end "variable: `q_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) if bounded - @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]]) - #@constraint(pm.model, pm.ref[:buspairs_dc][i,j]["qmint"] <= q_dc[(l,i,j) in pm.ref[:arcs_to_dc]] <= pm.ref[:buspairs_dc][i,j]["qmaxt"]) - #@constraint(pm.model, pm.ref[:buspairs_dc][i,j]["qminf"] <= q_dc[(l,i,j) in pm.ref[:arcs_from_dc]] <= pm.ref[:buspairs_dc][i,j]["qmaxf"]) + qmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + qref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + qmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) + for (l,i,j) in pm.ref[:arcs_from_dc] + qmin[(l,i,j)] = pm.ref[:dcline][l]["qminf"] + qmax[(l,i,j)] = pm.ref[:dcline][l]["qmaxf"] + qmin[(l,j,i)] = pm.ref[:dcline][l]["qmint"] + qmax[(l,j,i)] = pm.ref[:dcline][l]["qmaxt"] + qref[(l,i,j)] = pm.ref[:dcline][l]["qf"] + qref[(l,j,i)] = pm.ref[:dcline][l]["qt"] + br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] + br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] + end + @variable(pm.model, br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) else - #@variable(pm.model, p[(l,i,j) in pm.ref[:arcs]], start = getstart(pm.ref[:branch], l, "p_start")) - @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]]) + @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]], start = 0) end return q_dc end diff --git a/src/form/acdcp.jl b/src/form/acdcp.jl deleted file mode 100644 index 8efeb793d..000000000 --- a/src/form/acdcp.jl +++ /dev/null @@ -1,458 +0,0 @@ -export - ACDCPPowerModel, StandardACPForm, - APIACDCPPowerModel, APIACPForm - -"" -@compat abstract type AbstractACPForm <: AbstractPowerFormulation end - -"" -@compat abstract type StandardACPForm <: AbstractACPForm end - -"" -const ACDCPPowerModel = GenericPowerModel{StandardACPForm} - -"default AC constructor" -ACDCPPowerModel(data::Dict{String,Any}; kwargs...) = - GenericPowerModel(data, StandardACPForm; kwargs...) - -"" -function variable_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) - variable_phase_angle(pm; kwargs...) - variable_voltage_magnitude(pm; kwargs...) -end - -"" -variable_voltage_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) = nothing - -"do nothing, this model does not have complex voltage constraints" -constraint_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = Set() - -"do nothing, this model does not have complex voltage constraints" -constraint_voltage_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = nothing - -"`t[ref_bus] == 0`" -constraint_theta_ref{T <: AbstractACPForm}(pm::GenericPowerModel{T}, ref_bus) = - Set([@constraint(pm.model, getindex(pm.model, :t)[ref_bus] == 0)]) - -"`vm - epsilon <= v[i] <= vm + epsilon`" -function constraint_voltage_magnitude_setpoint{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, vm, epsilon) - v = getindex(pm.model, :v)[i] - - if epsilon == 0.0 - c = @constraint(pm.model, v == vm) - return Set([c]) - else - c1 = @constraint(pm.model, v <= vm + epsilon) - c2 = @constraint(pm.model, v >= vm - epsilon) - return Set([c1, c2]) - end -end - -""" -``` -sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 -sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 -``` -""" -function constraint_kcl_shunt{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) - v = getindex(pm.model, :v)[i] - p = getindex(pm.model, :p) - q = getindex(pm.model, :q) - pg = getindex(pm.model, :pg) - qg = getindex(pm.model, :qg) - - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) - return Set([c1, c2]) -end - -""" -``` -sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 -sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 -``` -""" -function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) - v = getindex(pm.model, :v)[i] - p = getindex(pm.model, :p) - q = getindex(pm.model, :q) - p_ne = getindex(pm.model, :p_ne) - q_ne = getindex(pm.model, :q_ne) - pg = getindex(pm.model, :pg) - qg = getindex(pm.model, :qg) - p_dc = getindex(pm.model, :p_dc) - q_dc = getindex(pm.model, :q_dc) - - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) - return Set([c1, c2]) -end - -""" -Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) - -``` -p[f_idx] == g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])) -q[f_idx] == -(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus])) -``` -""" -function constraint_ohms_yt_from{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) - p_fr = getindex(pm.model, :p)[f_idx] - q_fr = getindex(pm.model, :q)[f_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - - c1 = @NLconstraint(pm.model, p_fr == g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to)) ) - c2 = @NLconstraint(pm.model, q_fr == -(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to)) ) - return Set([c1, c2]) -end - -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -p_fr + p_to == loss0 + loss1 * p_fr -``` -""" -function constraint_ohms_yt_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, p_fr + p_to == loss0 + loss1 .* p_fr) - return Set([c1]) -end - -""" -Creates Voltage constraints for DC Lines (AC bus seen as PV node) - -``` -if br_status = 1: v_f == vf -if br_status = 1: v_t == vt -``` -""" -function constraint_voltage_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, br_status, vf, vt) - v_f = getindex(pm.model, :v)[f_bus] - v_t = getindex(pm.model, :v)[t_bus] - - c1 = @constraint(pm.model, br_status * v_f == br_status * vf) - c2 = @constraint(pm.model, br_status * v_t == br_status * vt) - - return Set([c1,c2]) -end - - -""" -Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) - -``` -p[t_idx] == g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])) -q[t_idx] == -(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus])) -``` -""" -function constraint_ohms_yt_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) - p_to = getindex(pm.model, :p)[t_idx] - q_to = getindex(pm.model, :q)[t_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - - c1 = @NLconstraint(pm.model, p_to == g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr)) ) - c2 = @NLconstraint(pm.model, q_to == -(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr)) ) - return Set([c1, c2]) -end - -""" -Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) - -``` -p[f_idx] == g*(v[f_bus]/tr)^2 + -g*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -b*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as) -q[f_idx] == -(b+c/2)*(v[f_bus]/tr)^2 + b*v[f_bus]/tr*v[t_bus]*cos(t[f_bus]-t[t_bus]-as) + -g*v[f_bus]/tr*v[t_bus]*sin(t[f_bus]-t[t_bus]-as) -``` -""" -function constraint_ohms_y_from{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, as) - p_fr = getindex(pm.model, :p)[f_idx] - q_fr = getindex(pm.model, :q)[f_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - - c1 = @NLconstraint(pm.model, p_fr == g*(v_fr/tr)^2 + -g*v_fr/tr*v_to*cos(t_fr-t_to-as) + -b*v_fr/tr*v_to*sin(t_fr-t_to-as) ) - c2 = @NLconstraint(pm.model, q_fr == -(b+c/2)*(v_fr/tr)^2 + b*v_fr/tr*v_to*cos(t_fr-t_to-as) + -g*v_fr/tr*v_to*sin(t_fr-t_to-as) ) - return Set([c1, c2]) -end - -""" -Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) - -``` -p[t_idx] == g*v[t_bus]^2 + -g*v[t_bus]*v[f_bus]/tr*cos(t[t_bus]-t[f_bus]+as) + -b*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as) -q_to == -(b+c/2)*v[t_bus]^2 + b*v[t_bus]*v[f_bus]/tr*cos(t[f_bus]-t[t_bus]+as) + -g*v[t_bus]*v[f_bus]/tr*sin(t[t_bus]-t[f_bus]+as) -``` -""" -function constraint_ohms_y_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, as) - p_to = getindex(pm.model, :p)[t_idx] - q_to = getindex(pm.model, :q)[t_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - - c1 = @NLconstraint(pm.model, p_to == g*v_to^2 + -g*v_to*v_fr/tr*cos(t_to-t_fr+as) + -b*v_to*v_fr/tr*sin(t_to-t_fr+as) ) - c2 = @NLconstraint(pm.model, q_to == -(b+c/2)*v_to^2 + b*v_to*v_fr/tr*cos(t_fr-t_to+as) + -g*v_to*v_fr/tr*sin(t_to-t_fr+as) ) - return Set([c1, c2]) -end - -""" -``` -t[f_bus] - t[t_bus] <= angmax -t[f_bus] - t[t_bus] >= angmin -``` -""" -function constraint_phase_angle_difference{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - - c1 = @constraint(pm.model, t_fr - t_to <= angmax) - c2 = @constraint(pm.model, t_fr - t_to >= angmin) - return Set([c1, c2]) -end - -"" -function variable_voltage_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}; kwargs...) - variable_phase_angle(pm; kwargs...) - variable_voltage_magnitude(pm; kwargs...) -end - -"do nothing, this model does not have complex voltage constraints" -constraint_voltage_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}) = Set() - -""" -``` -p[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) -q[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) -``` -""" -function constraint_ohms_yt_from_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) - p_fr = getindex(pm.model, :p)[f_idx] - q_fr = getindex(pm.model, :q)[f_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_z)[i] - - c1 = @NLconstraint(pm.model, p_fr == z*(g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) - c2 = @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) - return Set([c1, c2]) -end - -""" -``` -p[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) -q[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) -``` -""" -function constraint_ohms_yt_to_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) - p_to = getindex(pm.model, :p)[t_idx] - q_to = getindex(pm.model, :q)[t_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_z)[i] - - c1 = @NLconstraint(pm.model, p_to == z*(g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) - c2 = @NLconstraint(pm.model, q_to == z*(-(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) - return Set([c1, c2]) -end - -""" -``` -p_ne[f_idx] == z*(g/tm*v[f_bus]^2 + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) -q_ne[f_idx] == z*(-(b+c/2)/tm*v[f_bus]^2 - (-b*tr-g*ti)/tm*(v[f_bus]*v[t_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr+b*ti)/tm*(v[f_bus]*v[t_bus]*sin(t[f_bus]-t[t_bus]))) -``` -""" -function constraint_ohms_yt_from_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) - p_fr = getindex(pm.model, :p_ne)[f_idx] - q_fr = getindex(pm.model, :q_ne)[f_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_ne)[i] - - c1 = @NLconstraint(pm.model, p_fr == z*(g/tm*v_fr^2 + (-g*tr+b*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-b*tr-g*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) - c2 = @NLconstraint(pm.model, q_fr == z*(-(b+c/2)/tm*v_fr^2 - (-b*tr-g*ti)/tm*(v_fr*v_to*cos(t_fr-t_to)) + (-g*tr+b*ti)/tm*(v_fr*v_to*sin(t_fr-t_to))) ) - return Set([c1, c2]) -end - -""" -``` -p_ne[t_idx] == z*(g*v[t_bus]^2 + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[t_bus]-t[f_bus])) + (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) -q_ne[t_idx] == z*(-(b+c/2)*v[t_bus]^2 - (-b*tr+g*ti)/tm*(v[t_bus]*v[f_bus]*cos(t[f_bus]-t[t_bus])) + (-g*tr-b*ti)/tm*(v[t_bus]*v[f_bus]*sin(t[t_bus]-t[f_bus]))) -``` -""" -function constraint_ohms_yt_to_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) - p_to = getindex(pm.model, :p_ne)[t_idx] - q_to = getindex(pm.model, :q_ne)[t_idx] - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_ne)[i] - - c1 = @NLconstraint(pm.model, p_to == z*(g*v_to^2 + (-g*tr-b*ti)/tm*(v_to*v_fr*cos(t_to-t_fr)) + (-b*tr+g*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) - c2 = @NLconstraint(pm.model, q_to == z*(-(b+c/2)*v_to^2 - (-b*tr+g*ti)/tm*(v_to*v_fr*cos(t_fr-t_to)) + (-g*tr-b*ti)/tm*(v_to*v_fr*sin(t_to-t_fr))) ) - return Set([c1, c2]) -end - -"`angmin <= line_z[i]*(t[f_bus] - t[t_bus]) <= angmax`" -function constraint_phase_angle_difference_on_off{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, angmin, angmax, t_min, t_max) - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_z)[i] - - c1 = @constraint(pm.model, z*(t_fr - t_to) <= angmax) - c2 = @constraint(pm.model, z*(t_fr - t_to) >= angmin) - return Set([c1, c2]) -end - -"`angmin <= line_ne[i]*(t[f_bus] - t[t_bus]) <= angmax`" -function constraint_phase_angle_difference_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, angmin, angmax, t_min, t_max) - t_fr = getindex(pm.model, :t)[f_bus] - t_to = getindex(pm.model, :t)[t_bus] - z = getindex(pm.model, :line_ne)[i] - - c1 = @constraint(pm.model, z*(t_fr - t_to) <= angmax) - c2 = @constraint(pm.model, z*(t_fr - t_to) >= angmin) - return Set([c1, c2]) -end - -""" -``` -p[f_idx] + p[t_idx] >= 0 -q[f_idx] + q[t_idx] >= -c/2*(v[f_bus]^2/tr^2 + v[t_bus]^2) -``` -""" -function constraint_loss_lb{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, c, tr) - v_fr = getindex(pm.model, :v)[f_bus] - v_to = getindex(pm.model, :v)[t_bus] - p_fr = getindex(pm.model, :p)[f_idx] - q_fr = getindex(pm.model, :q)[f_idx] - p_to = getindex(pm.model, :p)[t_idx] - q_to = getindex(pm.model, :q)[t_idx] - - c1 = @constraint(m, p_fr + p_to >= 0) - c2 = @constraint(m, q_fr + q_to >= -c/2*(v_fr^2/tr^2 + v_to^2)) - return Set([c1, c2]) -end - -"" -@compat abstract type APIACPForm <: AbstractACPForm end - -"" -const APIACDCPPowerModel = GenericPowerModel{APIACPForm} - -"default AC constructor" -APIACDCPPowerModel(data::Dict{String,Any}; kwargs...) = - GenericPowerModel(data, APIACPForm; kwargs...) - -"variable: load_factor >= 1.0" -variable_load_factor(pm::GenericPowerModel) = - @variable(pm.model, load_factor >= 1.0, start = 1.0) - -"objective: Max. load_factor" -objective_max_loading(pm::GenericPowerModel) = - @objective(pm.model, Max, getindex(pm.model, :load_factor)) - -"" -function objective_max_loading_voltage_norm(pm::GenericPowerModel) - # Seems to create too much reactive power and makes even small models hard to converge - load_factor = getindex(pm.model, :load_factor) - - scale = length(pm.ref[:bus]) - v = getindex(pm.model, :v) - - return @objective(pm.model, Max, 10*scale*load_factor - sum(((bus["vmin"] + bus["vmax"])/2 - v[i])^2 for (i,bus) in pm.ref[:bus] )) -end - -"" -function objective_max_loading_gen_output(pm::GenericPowerModel) - # Works but adds unnecessary runtime - load_factor = getindex(pm.model, :load_factor) - - scale = length(pm.ref[:gen]) - pg = getindex(pm.model, :pg) - qg = getindex(pm.model, :qg) - - return @NLobjective(pm.model, Max, 100*scale*load_factor - sum( (pg[i]^2 - (2*qg[i])^2)^2 for (i,gen) in pm.ref[:gen] )) -end - -"" -function bounds_tighten_voltage(pm::APIACDCPPowerModel; epsilon = 0.001) - for (i,bus) in pm.ref[:bus] - v = getindex(pm.model, :v)[i] - setupperbound(v, bus["vmax"]*(1.0-epsilon)) - setlowerbound(v, bus["vmin"]*(1.0+epsilon)) - end -end - -"" -function upperbound_negative_active_generation(pm::APIACDCPPowerModel) - for (i,gen) in pm.ref[:gen] - if gen["pmax"] <= 0 - pg = getindex(pm.model, :pg)[i] - setupperbound(pg, gen["pmax"]) - end - end -end - -"" -function constraint_kcl_shunt_scaled(pm::APIACDCPPowerModel, bus) - i = bus["index"] - bus_arcs = pm.ref[:bus_arcs][i] - bus_gens = pm.ref[:bus_gens][i] - - load_factor = getindex(pm.model, :load_factor) - v = getindex(pm.model, :v) - p = getindex(pm.model, :p) - q = getindex(pm.model, :q) - pg = getindex(pm.model, :pg) - qg = getindex(pm.model, :qg) - - if bus["pd"] > 0 && bus["qd"] > 0 - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - bus["pd"]*load_factor - bus["gs"]*v[i]^2) - else - # super fallback impl - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - bus["pd"] - bus["gs"]*v[i]^2) - end - - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - bus["qd"] + bus["bs"]*v[i]^2) - - return Set([c1, c2]) -end - -"" -function get_solution(pm::APIACDCPPowerModel) - # super fallback - sol = init_solution(pm) - add_bus_voltage_setpoint(sol, pm) - add_generator_power_setpoint(sol, pm) - add_branch_flow_setpoint(sol, pm) - - # extension - add_bus_demand_setpoint(sol, pm) - - return sol -end - -"" -function add_bus_demand_setpoint(sol, pm::APIACDCPPowerModel) - mva_base = pm.data["baseMVA"] - add_setpoint(sol, pm, "bus", "bus_i", "pd", :load_factor; default_value = (item) -> item["pd"], scale = (x,item) -> item["pd"] > 0 && item["qd"] > 0 ? x*item["pd"] : item["pd"], extract_var = (var,idx,item) -> var) - add_setpoint(sol, pm, "bus", "bus_i", "qd", :load_factor; default_value = (item) -> item["qd"], scale = (x,item) -> item["qd"], extract_var = (var,idx,item) -> var) -end diff --git a/src/form/acp.jl b/src/form/acp.jl index 930d4ecec..a0706ff99 100644 --- a/src/form/acp.jl +++ b/src/form/acp.jl @@ -1,4 +1,4 @@ -export +export ACPPowerModel, StandardACPForm, APIACPPowerModel, APIACPForm @@ -12,7 +12,7 @@ export const ACPPowerModel = GenericPowerModel{StandardACPForm} "default AC constructor" -ACPPowerModel(data::Dict{String,Any}; kwargs...) = +ACPPowerModel(data::Dict{String,Any}; kwargs...) = GenericPowerModel(data, StandardACPForm; kwargs...) "" @@ -50,19 +50,21 @@ end """ ``` -sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 -sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 +sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 +sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 ``` """ -function constraint_kcl_shunt{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) v = getindex(pm.model, :v)[i] p = getindex(pm.model, :p) q = getindex(pm.model, :q) pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) return Set([c1, c2]) end @@ -128,6 +130,21 @@ function constraint_ohms_yt_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f return Set([c1, c2]) end +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +(1-loss1) * p_fr + (p_to - loss0 * br_status) == 0 +``` +""" +function constraint_ohms_yt_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) + return Set([c1]) +end + """ Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) @@ -330,7 +347,7 @@ variable_load_factor(pm::GenericPowerModel) = @variable(pm.model, load_factor >= 1.0, start = 1.0) "objective: Max. load_factor" -objective_max_loading(pm::GenericPowerModel) = +objective_max_loading(pm::GenericPowerModel) = @objective(pm.model, Max, getindex(pm.model, :load_factor)) "" @@ -368,7 +385,7 @@ end "" function upperbound_negative_active_generation(pm::APIACPPowerModel) for (i,gen) in pm.ref[:gen] - if gen["pmax"] <= 0 + if gen["pmax"] <= 0 pg = getindex(pm.model, :pg)[i] setupperbound(pg, gen["pmax"]) end diff --git a/src/form/dcp.jl b/src/form/dcp.jl index e6097866a..6cb4b56ca 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -57,7 +57,7 @@ end "" function variable_active_line_flow_ne{T <: StandardDCPForm}(pm::GenericPowerModel{T}) @variable(pm.model, -pm.ref[:ne_branch][l]["rate_a"] <= p_ne[(l,i,j) in pm.ref[:ne_arcs_from]] <= pm.ref[:ne_branch][l]["rate_a"], start = getstart(pm.ref[:ne_branch], l, "p_start")) - + p_ne_expr = Dict([((l,i,j), 1.0*p_ne[(l,i,j)]) for (l,i,j) in pm.ref[:ne_arcs_from]]) p_ne_expr = merge(p_ne_expr, Dict([((l,j,i), -1.0*p_ne[(l,i,j)]) for (l,i,j) in pm.ref[:ne_arcs_from]])) @@ -81,11 +81,12 @@ constraint_voltage_magnitude_setpoint{T <: AbstractDCPForm}(pm::GenericPowerMode constraint_reactive_gen_setpoint{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, qg) = Set() "" -function constraint_kcl_shunt{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) pg = getindex(pm.model, :pg) p_expr = pm.model.ext[:p_expr] + p_dc = getindex(pm.model, :p_dc) - c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) + c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) # omit reactive constraint return Set([c]) end @@ -131,6 +132,21 @@ function constraint_ohms_yt_from_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{ return Set([c1, c2]) end +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +p_fr + p_to == loss0 + loss1 * p_fr +``` +""" +function constraint_ohms_yt_dc{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) + return Set([c1]) +end + "Do nothing, this model is symmetric" constraint_ohms_yt_to_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) = Set() diff --git a/src/form/wr.jl b/src/form/wr.jl index 7773df337..79effaa85 100644 --- a/src/form/wr.jl +++ b/src/form/wr.jl @@ -75,15 +75,17 @@ function constraint_voltage_magnitude_setpoint{T <: AbstractWRForm}(pm::GenericP end "" -function constraint_kcl_shunt{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) w = getindex(pm.model, :w)[i] p = getindex(pm.model, :p) q = getindex(pm.model, :q) pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*w) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*w) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w) return Set([c1, c2]) end @@ -147,6 +149,21 @@ function constraint_ohms_yt_to{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_ return Set([c1, c2]) end +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +p_fr + p_to == loss0 + loss1 * p_fr +``` +""" +function constraint_ohms_yt_dc{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) + return Set([c1]) +end + """ Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) @@ -247,10 +264,10 @@ end function constraint_voltage_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}) buses = pm.ref[:bus] branches = pm.ref[:ne_branch] - + wr_min, wr_max, wi_min, wi_max = calc_voltage_product_bounds(pm.ref[:ne_buspairs]) bi_bp = Dict([(i, (b["f_bus"], b["t_bus"])) for (i,b) in branches]) - + w = getindex(pm.model, :w) wr = getindex(pm.model, :wr_ne) wi = getindex(pm.model, :wi_ne) @@ -263,19 +280,19 @@ function constraint_voltage_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}) for (l,i,j) in pm.ref[:ne_arcs_from] c1 = @constraint(pm.model, w_from[l] <= z[l]*buses[branches[l]["f_bus"]]["vmax"]^2) c2 = @constraint(pm.model, w_from[l] >= z[l]*buses[branches[l]["f_bus"]]["vmin"]^2) - + c3 = @constraint(pm.model, wr[l] <= z[l]*wr_max[bi_bp[l]]) c4 = @constraint(pm.model, wr[l] >= z[l]*wr_min[bi_bp[l]]) c5 = @constraint(pm.model, wi[l] <= z[l]*wi_max[bi_bp[l]]) c6 = @constraint(pm.model, wi[l] >= z[l]*wi_min[bi_bp[l]]) - + c7 = @constraint(pm.model, w_to[l] <= z[l]*buses[branches[l]["t_bus"]]["vmax"]^2) c8 = @constraint(pm.model, w_to[l] >= z[l]*buses[branches[l]["t_bus"]]["vmin"]^2) - + c9 = relaxation_complex_product_on_off(pm.model, w[i], w[j], wr[l], wi[l], z[l]) c10 = relaxation_equality_on_off(pm.model, w[i], w_from[l], z[l]) c11 = relaxation_equality_on_off(pm.model, w[j], w_to[l], z[l]) - cs = Set([cs, c1, c2, c3, c4, c5, c6, c7, c8,c9, c10, c11]) + cs = Set([cs, c1, c2, c3, c4, c5, c6, c7, c8,c9, c10, c11]) end return cs end @@ -625,7 +642,7 @@ function constraint_power_magnitude_link(pm::QCWRPowerModel, f_bus, t_bus, arc_f end "`t[ref_bus] == 0`" -constraint_theta_ref(pm::QCWRPowerModel, ref_bus::Int) = +constraint_theta_ref(pm::QCWRPowerModel, ref_bus::Int) = @constraint(pm.model, getindex(pm.model, :t)[ref_bus] == 0) "" @@ -650,7 +667,7 @@ function constraint_phase_angle_difference(pm::QCWRPowerModel, f_bus, t_bus, ang c3 = cut_complex_product_and_angle_difference(pm.model, w_fr, w_to, wr, wi, angmin, angmax) - return Set([c1, c2, c3]) + return Set([c1, c2, c3]) end "" @@ -845,5 +862,3 @@ function constraint_power_magnitude_link_on_off(pm::QCWRPowerModel, i, arc_from, c = @constraint(pm.model, cm == (g^2 + b^2)*(w_fr/tm + w_to - 2*(tr*wr + ti*wi)/tm) - c*q_fr - ((c/2)/tm)^2*w_fr) return Set([c]) end - - diff --git a/src/form/wrm.jl b/src/form/wrm.jl index e6755dc84..87675d32e 100644 --- a/src/form/wrm.jl +++ b/src/form/wrm.jl @@ -1,4 +1,4 @@ -export +export SDPWRMPowerModel, SDPWRMForm "" @@ -74,7 +74,7 @@ end constraint_theta_ref{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, ref_bus::Int) = Set() "" -function constraint_kcl_shunt{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) WR = getindex(pm.model, :WR) w_index = pm.model.ext[:lookup_w_index][i] w = WR[w_index, w_index] @@ -83,9 +83,11 @@ function constraint_kcl_shunt{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, i, q = getindex(pm.model, :q) pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*w) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) == sum(qg[g] for g in bus_gens) - qd + bs*w) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w) return Set([c1, c2]) end @@ -129,6 +131,21 @@ function constraint_ohms_yt_to{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f return Set([c1, c2]) end +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +p_fr + p_to == loss0 + loss1 * p_fr +``` +""" +function constraint_ohms_yt_dc{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) + return Set([c1]) +end + "" function constraint_phase_angle_difference{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) WR = getindex(pm.model, :WR) diff --git a/src/io/matpower.jl b/src/io/matpower.jl index fbb1e24f7..69cc676a6 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -528,7 +528,6 @@ function parse_matpower_data(data_string::String) "pminf" => pminf, "pmaxt" => pmaxt, "pmaxf" => pmaxf, - "pmax" => parse(Float64, dcline_row[11]), "qminf" => parse(Float64, dcline_row[12]), "qmaxf" => parse(Float64, dcline_row[13]), "qmint" => parse(Float64, dcline_row[14]), diff --git a/src/prob/opf.jl b/src/prob/opf.jl index 7402a8203..0883ff089 100644 --- a/src/prob/opf.jl +++ b/src/prob/opf.jl @@ -45,7 +45,5 @@ function post_opf(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] constraint_ohms_yt_dc(pm, dcline) - constraint_thermal_limit_dc(pm, dcline) - constraint_voltage_dc(pm, dcline) end end diff --git a/test/data/case3_dc.m b/test/data/case3_dc.m new file mode 100644 index 000000000..52c939c65 --- /dev/null +++ b/test/data/case3_dc.m @@ -0,0 +1,85 @@ +% Case to test adding data to matpower file +% based on nesta_case3_lmbd from NESTA v0.6.0 +function mpc = case3 +mpc.version = '2'; +mpc.baseMVA = 100.0; + +mpc.bus = [ + 1 3 110.0 40.0 0.0 0.0 1 1.10000 -0.00000 240.0 1 1.10000 0.90000; + 2 2 110.0 40.0 0.0 0.0 1 0.92617 7.25883 240.0 1 1.10000 0.90000; + 3 2 95.0 50.0 0.0 0.0 1 0.90000 -17.26710 240.0 2 1.10000 0.90000; +]; + +mpc.gen = [ + 1 148.067 54.697 1000.0 -1000.0 1.1 100.0 1 2000.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 2 170.006 -8.791 1000.0 -1000.0 0.92617 100.0 1 1500.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 3 0.0 -4.843 1000.0 -1000.0 0.9 100.0 1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; +]; + +mpc.gencost = [ + 2 0.0 0.0 3 0.110000 5.000000 0.000000; + 2 0.0 0.0 3 0.085000 1.200000 0.000000; + 2 0.0 0.0 3 0.000000 0.000000 0.000000; +]; + +mpc.branch = [ + 1 3 0.065 0.62 0.45 9000.0 0.0 0.0 0.0 0.0 1 -30.0 30.0; + 3 2 0.025 0.75 0.7 50.0 0.0 0.0 0.0 0.0 1 -30.0 30.0; + 1 2 0.042 0.9 0.3 9000.0 0.0 0.0 0.0 0.0 1 -30.0 30.0; +]; + +mpc.dcline = [ + 1 2 1 0 0 0 0 1 1 0 0 -1000 1000 -1000 1000 0 0 0 0 0 0 0 0 +] + +% matpower data format extentions + +% adding single values +mpc.const_int = 123; +mpc.const_float = 4.56 +mpc.const_str = 'a string'; + + +% adding extra matrix values + +% generic table, comes in a matrix +mpc.areas = [ + 1 1; + 2 3; +]; + +% named column table +%column_names% area refbus +mpc.areas_named = [ + 4 5; + 5 6; +]; + +% add two new columns to "branch" matrix +%column_names% rate_i rate_p +mpc.branch_limit = [ + 50.2 45; + 36 60.1; + 12 30; +]; + + +% adding extra cell values + +mpc.areas_cells = { + 'Area 1' 123 987 'Slack \'Bus\' 1' 1.23 ; + 'Area 2' 456 987 'Slack Bus 3' 4.56 ; +}; + +%column_names% area_name area area2 refbus_name refbus +mpc.areas_named_cells = { + 'Area 1' 123 987 'Slack Bus 1' 1.23; + 'Area 2' 456 987 'Slack Bus 3' 4.56; +}; + +%column_names% name number_id +mpc.branch_names = { + 'Branch 1' 123; + 'Branch 2' 456; + 'Branch 3' 789; +}; diff --git a/test/data/case5_dc.m b/test/data/case5_dc.m new file mode 100644 index 000000000..f2769b6e8 --- /dev/null +++ b/test/data/case5_dc.m @@ -0,0 +1,65 @@ +% NESTA v0.6.0 +function mpc = nesta_case5_pjm +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% area data +% area refbus +mpc.areas = [ + 1 4; +]; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 2 0.0 0.0 0.0 0.0 1 1.07762 2.80377 230.0 1 1.10000 0.90000; + 2 1 300.0 98.61 0.0 0.0 1 1.08407 -0.73465 230.0 1 1.10000 0.90000; + 3 2 300.0 98.61 0.0 0.0 1 1.10000 -0.55972 230.0 1 1.10000 0.90000; + 4 3 400.0 131.47 0.0 0.0 1 1.06414 0.00000 230.0 1 1.10000 0.90000; + 5 2 0.0 0.0 0.0 0.0 1 1.06907 3.59033 230.0 1 1.10000 0.90000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf +mpc.gen = [ + 1 40.0 30.0 30.0 -30.0 1.07762 100.0 1 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 1 170.0 127.5 127.5 -127.5 1.07762 100.0 1 170.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 3 324.498 390.0 390.0 -390.0 1.1 100.0 1 520.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 4 0.0 -10.802 150.0 -150.0 1.06414 100.0 1 200.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 5 470.694 -165.039 450.0 -450.0 1.06907 100.0 1 600.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.000000 14.000000 0.000000; + 2 0.0 0.0 3 0.000000 15.000000 0.000000; + 2 0.0 0.0 3 0.000000 30.000000 0.000000; + 2 0.0 0.0 3 0.000000 40.000000 0.000000; + 2 0.0 0.0 3 0.000000 10.000000 0.000000; +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 2 0.00281 0.0281 0.00712 400.0 400.0 400.0 0.0 0.0 1 -30.0 30.0; + 1 4 0.00304 0.0304 0.00658 426 426 426 0.0 0.0 1 -30.0 30.0; + 1 5 0.00064 0.0064 0.03126 426 426 426 0.0 0.0 1 -30.0 30.0; + 2 3 0.00108 0.0108 0.01852 426 426 426 0.0 0.0 1 -30.0 30.0; + 3 4 0.00297 0.0297 0.00674 426 426 426 0.0 0.0 1 -30.0 30.0; + 4 5 0.00297 0.0297 0.00674 240.0 240.0 240.0 0.0 0.0 1 -30.0 30.0; +]; + + +%%----- DC Line Data ----- +% fbus tbus status Pf Pt Qf Qt Vf Vt Pmin Pmax QminF QmaxF QminT QmaxT loss0 loss1 +mpc.dcline = [ + 3 5 1 10 8.9 0 0 1.01 1 0 0 -100 100 -100 100 1 0.01; +]; + +%% DC line cost data +% 1 startup shutdown n x1 y1 ... xn yn +% 2 startup shutdown n c(n-1) ... c0 +mpc.dclinecost = [ + 2 0 0 2 0 0 0 0 0 0 0 0 0 0; +]; From 3a711037b73cb25ca6a71b6b1a7e6769ab13b079 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Mon, 24 Jul 2017 17:25:24 +0200 Subject: [PATCH 08/23] Bugfix after removal of dedicated acdc formulation --- src/PowerModels.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PowerModels.jl b/src/PowerModels.jl index 1a188f2e3..6c132a403 100644 --- a/src/PowerModels.jl +++ b/src/PowerModels.jl @@ -21,7 +21,6 @@ include("core/objective.jl") include("core/solution.jl") include("form/acp.jl") -include("form/acdcp.jl") include("form/dcp.jl") include("form/wr.jl") include("form/wrm.jl") From 2de5c838dd6abf18e10ed9e44a6276d017454551 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Mon, 24 Jul 2017 19:49:13 +0200 Subject: [PATCH 09/23] Further improve support for DC lines - Remove warning of not calculating DC lines - Fix compatibility with OTS, PF, MISC - Fix per unit conversion --- src/core/data.jl | 18 +++++++++++ src/core/variable.jl | 71 +++++++++++++++++++++++--------------------- src/form/dcp.jl | 14 +++++---- src/io/matpower.jl | 4 --- src/prob/misc.jl | 19 ++++++++++-- src/prob/ots.jl | 8 ++++- src/prob/pf.jl | 4 +++ test/data/case3.m | 6 +--- test/docs.jl | 5 ++-- test/opf.jl | 12 +++----- test/output.jl | 8 ++--- 11 files changed, 101 insertions(+), 68 deletions(-) diff --git a/src/core/data.jl b/src/core/data.jl index 2240e46db..fb27b255d 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -218,6 +218,12 @@ function make_mixed_units(data::Dict{String,Any}) if haskey(data, "branch") append!(branches, values(data["branch"])) end + + dclines =[] + if haskey(data, "dcline") + append!(dclines, values(data["dcline"])) + end + if haskey(data, "ne_branch") append!(branches, values(data["ne_branch"])) end @@ -232,6 +238,18 @@ function make_mixed_units(data::Dict{String,Any}) apply_func(branch, "angmin", rad2deg) end + for dcline in dclines + apply_func(dcline, "loss0", rescale) + apply_func(dcline, "pmaxt", rescale) + apply_func(dcline, "pmint", rescale) + apply_func(dcline, "pmaxf", rescale) + apply_func(dcline, "pminf", rescale) + apply_func(dcline, "qmaxt", rescale) + apply_func(dcline, "qmint", rescale) + apply_func(dcline, "qmaxf", rescale) + apply_func(dcline, "qminf", rescale) + end + if haskey(data, "gen") for (i, gen) in data["gen"] apply_func(gen, "pg", rescale) diff --git a/src/core/variable.jl b/src/core/variable.jl index aeccf0230..8bcddbc64 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -136,51 +136,54 @@ end "variable: `p_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) + pmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + pref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + pmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + loss0 = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) + for (l,i,j) in pm.ref[:arcs_from_dc] + pmin[(l,i,j)] = pm.ref[:dcline][l]["pminf"] + pmax[(l,i,j)] = pm.ref[:dcline][l]["pmaxf"] + pmin[(l,j,i)] = pm.ref[:dcline][l]["pmint"] + pmax[(l,j,i)] = pm.ref[:dcline][l]["pmaxt"] + pref[(l,i,j)] = pm.ref[:dcline][l]["pf"] + pref[(l,j,i)] = pm.ref[:dcline][l]["pt"] + loss0[(l,i,j)] = 0 + loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] + br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] + br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] + end if bounded - pmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - pref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - pmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - loss0 = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) - for (l,i,j) in pm.ref[:arcs_from_dc] - pmin[(l,i,j)] = pm.ref[:dcline][l]["pminf"] - pmax[(l,i,j)] = pm.ref[:dcline][l]["pmaxf"] - pmin[(l,j,i)] = pm.ref[:dcline][l]["pmint"] - pmax[(l,j,i)] = pm.ref[:dcline][l]["pmaxt"] - pref[(l,i,j)] = pm.ref[:dcline][l]["pf"] - pref[(l,j,i)] = pm.ref[:dcline][l]["pt"] - loss0[(l,i,j)] = 0 - loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] - br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] - br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] - end @variable(pm.model, br_status[(l,i,j)] * (pmin[(l,i,j)] + (loss0[(l,i,j)])) <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * (pmax[(l,i,j)] + (loss0[(l,i,j)])), start = pref[(l,i,j)]) else - @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]], start = 0) + M = 5; + @variable(pm.model, M*br_status[(l,i,j)] * (pmin[(l,i,j)] + (loss0[(l,i,j)])) <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * (pmax[(l,i,j)] + (loss0[(l,i,j)])), start = pref[(l,i,j)]) end return p_dc end "variable: `q_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) + qmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + qref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + qmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) + br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) + for (l,i,j) in pm.ref[:arcs_from_dc] + qmin[(l,i,j)] = pm.ref[:dcline][l]["qminf"] + qmax[(l,i,j)] = pm.ref[:dcline][l]["qmaxf"] + qmin[(l,j,i)] = pm.ref[:dcline][l]["qmint"] + qmax[(l,j,i)] = pm.ref[:dcline][l]["qmaxt"] + qref[(l,i,j)] = pm.ref[:dcline][l]["qf"] + qref[(l,j,i)] = pm.ref[:dcline][l]["qt"] + br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] + br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] + end if bounded - qmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - qref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - qmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) - for (l,i,j) in pm.ref[:arcs_from_dc] - qmin[(l,i,j)] = pm.ref[:dcline][l]["qminf"] - qmax[(l,i,j)] = pm.ref[:dcline][l]["qmaxf"] - qmin[(l,j,i)] = pm.ref[:dcline][l]["qmint"] - qmax[(l,j,i)] = pm.ref[:dcline][l]["qmaxt"] - qref[(l,i,j)] = pm.ref[:dcline][l]["qf"] - qref[(l,j,i)] = pm.ref[:dcline][l]["qt"] - br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] - br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] - end - @variable(pm.model, br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) + + @variable(pm.model, br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) else - @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]], start = 0) + M = 5; + @variable(pm.model, M*br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) end return q_dc end diff --git a/src/form/dcp.jl b/src/form/dcp.jl index 6cb4b56ca..874706284 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -290,22 +290,24 @@ const DCPLLPowerModel = GenericPowerModel{StandardDCPLLForm} "default DC constructor" DCPLLPowerModel(data::Dict{String,Any}; kwargs...) = GenericPowerModel(data, StandardDCPLLForm; kwargs...) -"`sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2`" -function constraint_kcl_shunt{T <: AbstractDCPLLForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_gens, pd, qd, gs, bs) +"`sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc)== sum(pg[g] for g in bus_gens) - pd - gs*1.0^2`" +function constraint_kcl_shunt{T <: AbstractDCPLLForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) pg = getindex(pm.model, :pg) p = getindex(pm.model, :p) + p_dc = getindex(pm.model, :p_dc) - c = @constraint(pm.model, sum(p[a] for a in bus_arcs) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) + c = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) return Set([c]) end -"`sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2`" -function constraint_kcl_shunt_ne{T <: AbstractDCPLLForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) +"`sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2`" +function constraint_kcl_shunt_ne{T <: AbstractDCPLLForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) p = getindex(pm.model, :p) p_ne = getindex(pm.model, :p_ne) + p_dc = getindex(pm.model, :p_dc) pg = getindex(pm.model, :pg) - c = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) + c = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) return Set([c]) end diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 69cc676a6..00f463665 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -14,10 +14,6 @@ function parse_matpower(file_string::String) merge_bus_name_data(mp_data) merge_generator_cost_data(mp_data) - if length(mp_data["dcline"]) > 0 - warn("this cases includes $(length(mp_data["dcline"])) dc lines, which are not currently supported by PowerModels problem formulations") - end - # after this call, Matpower data is consistent with PowerModels data mp_data_to_pm_data(mp_data) diff --git a/src/prob/misc.jl b/src/prob/misc.jl index 5df4e44aa..d2397f090 100644 --- a/src/prob/misc.jl +++ b/src/prob/misc.jl @@ -1,9 +1,9 @@ -export +export run_api_opf, run_sad_opf "" function run_api_opf(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_api_opf; kwargs...) + return run_generic_model(file, model_constructor, solver, post_api_opf; kwargs...) end "" @@ -15,6 +15,8 @@ function post_api_opf(pm::GenericPowerModel) upperbound_negative_active_generation(pm) variable_line_flow(pm) + variable_line_flow_dc(pm) + variable_load_factor(pm) @@ -47,11 +49,16 @@ function post_api_opf(pm::GenericPowerModel) constraint_thermal_limit_from(pm, branch; scale = 0.999) constraint_thermal_limit_to(pm, branch; scale = 0.999) end + + + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + end end "" function run_sad_opf(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_sad_opf; kwargs...) + return run_generic_model(file, model_constructor, solver, post_sad_opf; kwargs...) end "" @@ -59,6 +66,8 @@ function post_sad_opf{T <: Union{AbstractACPForm, AbstractDCPForm}}(pm::GenericP variable_voltage(pm) variable_generation(pm) variable_line_flow(pm) + variable_line_flow_dc(pm, bounded = false) + @variable(pm.model, theta_delta_bound >= 0.0, start = 0.523598776) @objective(pm.model, Min, theta_delta_bound) @@ -87,4 +96,8 @@ function post_sad_opf{T <: Union{AbstractACPForm, AbstractDCPForm}}(pm::GenericP constraint_thermal_limit_from(pm, branch; scale = 0.999) constraint_thermal_limit_to(pm, branch; scale = 0.999) end + + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + end end diff --git a/src/prob/ots.jl b/src/prob/ots.jl index d85d0d2d4..ac776b240 100644 --- a/src/prob/ots.jl +++ b/src/prob/ots.jl @@ -8,7 +8,7 @@ export run_ots "" function run_ots(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_ots; solution_builder = get_ots_solution, kwargs...) + return run_generic_model(file, model_constructor, solver, post_ots; solution_builder = get_ots_solution, kwargs...) end "" @@ -17,6 +17,8 @@ function post_ots(pm::GenericPowerModel) variable_voltage_on_off(pm) variable_generation(pm) variable_line_flow(pm) + variable_line_flow_dc(pm) + objective_min_fuel_cost(pm) @@ -39,6 +41,10 @@ function post_ots(pm::GenericPowerModel) constraint_thermal_limit_from_on_off(pm, branch) constraint_thermal_limit_to_on_off(pm, branch) end + + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + end end "" diff --git a/src/prob/pf.jl b/src/prob/pf.jl index 2bc4d25d0..666c2516a 100644 --- a/src/prob/pf.jl +++ b/src/prob/pf.jl @@ -49,4 +49,8 @@ function post_pf(pm::GenericPowerModel) constraint_ohms_yt_from(pm, branch) constraint_ohms_yt_to(pm, branch) end + + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + end end diff --git a/test/data/case3.m b/test/data/case3.m index bf1412e7f..e700da8f0 100644 --- a/test/data/case3.m +++ b/test/data/case3.m @@ -29,7 +29,7 @@ ]; mpc.dcline = [ - 10 20 1 0 0 0 0 1 1 0 inf -inf inf -inf inf 0 0 0 0 0 0 0 0 + 1 2 0 0 0 0 0 1 1 0 inf -900 900 -900 900 0 0 0 0 0 0 0 0 ] % matpower data format extentions @@ -83,7 +83,3 @@ 'Branch 2' 456; 'Branch 3' 789; }; - - - - diff --git a/test/docs.jl b/test/docs.jl index 7ab2132d9..2c9eebf15 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -31,10 +31,10 @@ #pretty print the model to the terminal #print(pm.model) - @test MathProgBase.numlinconstr(pm.model) == 7 + @test MathProgBase.numlinconstr(pm.model) == 8 @test MathProgBase.numquadconstr(pm.model) == 12 @test MathProgBase.numconstr(pm.model) - MathProgBase.numlinconstr(pm.model) - MathProgBase.numquadconstr(pm.model) == 12 - @test MathProgBase.numvar(pm.model) == 24 + @test MathProgBase.numvar(pm.model) == 28 result = solve_generic_model(pm, IpoptSolver(print_level=0)) @@ -42,4 +42,3 @@ @test isapprox(result["objective"], 5812.64; atol = 1e0) end end - diff --git a/test/opf.jl b/test/opf.jl index 274d476da..bd2406265 100644 --- a/test/opf.jl +++ b/test/opf.jl @@ -19,7 +19,7 @@ @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 11567; atol = 1e0) @test isapprox(result["solution"]["bus"]["1"]["va"], 0.0; atol = 1e-4) - @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) + @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) end @testset "24-bus rts case" begin result = run_opf("../test/data/case24.m", ACPPowerModel, ipopt_solver) @@ -49,7 +49,7 @@ end @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 11396; atol = 1e0) @test isapprox(result["solution"]["bus"]["1"]["va"], 0.0; atol = 1e-4) - @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) + @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) end # TODO verify this is really infeasible #@testset "24-bus rts case" begin @@ -108,7 +108,7 @@ end @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 11567; atol = 1e0) @test isapprox(result["solution"]["bus"]["1"]["va"], 0.0; atol = 1e-4) - @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) + @test isapprox(result["solution"]["bus"]["4"]["va"], 0.0; atol = 1e-4) end @testset "24-bus rts case" begin result = run_opf("../test/data/case24.m", QCWRPowerModel, ipopt_solver) @@ -121,7 +121,7 @@ end @testset "test sdp opf" begin @testset "3-bus case" begin - result = run_opf("../test/data/case3.m", SDPWRMPowerModel, scs_solver) + result = run_opf("../test/data/case3_dc.m", SDPWRMPowerModel, scs_solver) @test result["status"] == :Optimal @test isapprox(result["objective"], 5788.7; atol = 1e0) @@ -147,7 +147,3 @@ end # @test isapprox(result["objective"], 75153; atol = 1e0) #end end - - - - diff --git a/test/output.jl b/test/output.jl index 649c1f022..0f5d496e7 100644 --- a/test/output.jl +++ b/test/output.jl @@ -12,7 +12,7 @@ @test haskey(result, "data") == true @test haskey(result, "solution") == true @test haskey(result["solution"], "branch") == false - + @test !isnan(result["solve_time"]) @test length(result["solution"]["bus"]) == 24 @@ -33,7 +33,7 @@ end @test haskey(result, "data") == true @test haskey(result, "solution") == true @test haskey(result["solution"], "branch") == true - + @test length(result["solution"]["bus"]) == 24 @test length(result["solution"]["gen"]) == 33 @test length(result["solution"]["branch"]) == 38 @@ -52,7 +52,7 @@ end @test haskey(result, "solution") == true @test haskey(result["solution"], "branch") == true - + @test length(result["solution"]["bus"]) == 3 @test length(result["solution"]["gen"]) == 3 @test length(result["solution"]["branch"]) == 3 @@ -64,4 +64,4 @@ end @test isnan(branches["3"]["q_from"]) @test isnan(branches["3"]["q_to"]) end -end \ No newline at end of file +end From 8471dca4413a8b5427d245d18a34875b32b06f19 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Mon, 24 Jul 2017 22:40:13 +0200 Subject: [PATCH 10/23] Add distflow based models - Distflow implementation, only for OPF - added variable definition for current magnitude squared --- src/core/variable.jl | 5 ++ src/form/distflow.jl | 141 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/form/distflow.jl diff --git a/src/core/variable.jl b/src/core/variable.jl index 8bcddbc64..8f715f257 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -55,6 +55,11 @@ function variable_voltage_magnitude_sqr(pm::GenericPowerModel; bounded = true) return w end +function variable_current_magnitude_sqr(pm::GenericPowerModel) + @variable(pm.model, i_sq[i in keys(pm.ref[:branch])] >= 0) + return i_sq +end + "variable: `0 <= w_from[l] <= buses[branches[l][\"f_bus\"]][\"vmax\"]^2` for `l` in `branch`es" function variable_voltage_magnitude_sqr_from_on_off(pm::GenericPowerModel) buses = pm.ref[:bus] diff --git a/src/form/distflow.jl b/src/form/distflow.jl new file mode 100644 index 000000000..e238b079b --- /dev/null +++ b/src/form/distflow.jl @@ -0,0 +1,141 @@ +export + SOCDistflowPowerModel, SOCDistflowForm + +"" +@compat abstract type AbstractDistflowForm <: AbstractPowerFormulation end + +"" +@compat abstract type SOCDistflowForm <: AbstractDistflowForm end + +"" +const SOCDistflowPowerModel = GenericPowerModel{SOCDistflowForm} + +"default SOC constructor" +SOCDistflowPowerModel(data::Dict{String,Any}; kwargs...) = GenericPowerModel(data, SOCDistflowForm; kwargs...) + +"" +function variable_voltage{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}; kwargs...) + variable_voltage_magnitude_sqr(pm; kwargs...) +# variable_voltage_product(pm; kwargs...) + variable_current_magnitude_sqr(pm; kwargs...) +end + +"" +function constraint_voltage{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}) + w = getindex(pm.model, :w) +end + +"Do nothing, no way to represent this in these variables" +constraint_theta_ref{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, ref_bus::Int) = Set() + +function constraint_voltage_magnitude_setpoint{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, i, vm, epsilon) + w = getindex(pm.model, :w)[i] + + if epsilon == 0.0 + c = @constraint(pm.model, w == vm^2) + return Set([c]) + else + @assert epsilon > 0.0 + c1 = @constraint(pm.model, w <= (vm + epsilon)^2) + c2 = @constraint(pm.model, w >= (vm - epsilon)^2) + return Set([c1, c2]) + end +end + +"" +function constraint_kcl_shunt{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) + w = getindex(pm.model, :w)[i] + p = getindex(pm.model, :p) + q = getindex(pm.model, :q) + pg = getindex(pm.model, :pg) + qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) + + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w) + return Set([c1, c2]) +end + +"Do nothing, this model is symmetric" +constraint_ohms_yt_from{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) = Set() + + +""" +Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) + +``` +p[t_idx] == g*w[t_bus] + (-g*tr-b*ti)/tm*(wr[f_bus,t_bus]) + (-b*tr+g*ti)/tm*(-wi[f_bus,t_bus]) +q[t_idx] == -(b+c/2)*w[t_bus] - (-b*tr+g*ti)/tm*(wr[f_bus,t_bus]) + (-g*tr-b*ti)/tm*(-wi[f_bus,t_bus]) +``` +""" +function constraint_ohms_yt_to{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) + q_fr = getindex(pm.model, :q)[f_idx] + q_to = getindex(pm.model, :q)[t_idx] + p_fr = getindex(pm.model, :p)[f_idx] + p_to = getindex(pm.model, :p)[t_idx] + w_fr = getindex(pm.model, :w)[f_bus] + w_to = getindex(pm.model, :w)[t_bus] + i_sq = getindex(pm.model, :i_sq)[f_idx[1]] + r = g/(g^2 + b^2) + x = -b/(g^2 + b^2) + g_sh = 0 + b_sh = c/2 + + c1 = @constraint(pm.model, p_to + p_fr == g_sh*w_fr +r*i_sq + g_sh*w_to) + c2 = @constraint(pm.model, q_to + p_fr == -b_sh*w_fr + x*i_sq - b_sh*w_to) + c3 = @constraint(pm.model, (p_fr - g_sh*w_fr)^2 + (q_fr - b_sh*w_fr)^2 <= i_sq*w_fr) + c4 = @constraint(pm.model, w_to - w_fr == -2*(r*(p_fr - g_sh*w_fr) +x*(q_fr - b_sh*w_fr)) +(r^2+x^2)*i_sq) + return Set([c1, c2, c3, c4]) +end + + +function constraint_ohms_yt_from_on_off{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) + q_fr = getindex(pm.model, :q)[f_idx] + q_to = getindex(pm.model, :q)[t_idx] + p_fr = getindex(pm.model, :p)[f_idx] + p_to = getindex(pm.model, :p)[t_idx] + w_fr = getindex(pm.model, :w)[f_bus] + w_to = getindex(pm.model, :w)[t_bus] + i_sq = getindex(pm.model, :i_sq)[f_idx[1]] + z = getindex(pm.model, :line_z) + + r = g/(g^2 + b^2) + x = -b/(g^2 + b^2) + g_sh = 0 + b_sh = c/2 + + c1 = @constraint(pm.model, p_to + p_fr == g_sh*w_fr +r*i_sq + g_sh*w_to) + c2 = @constraint(pm.model, q_to + p_fr == -b_sh*w_fr + x*i_sq - b_sh*w_to) + c3 = @constraint(pm.model, (p_fr - g_sh*w_fr)^2 + (q_fr - b_sh*w_fr)^2 <= i_sq*w_fr) + c4 = @constraint(pm.model, w_to - w_fr == -2*(r*(p_fr - g_sh*w_fr) +x*(q_fr - b_sh*w_fr)) +(r^2+x^2)*i_sq) + return Set([c1, c2, c3, c4]) +end + + +""" +Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) + +``` +p_fr + p_to == loss0 + loss1 * p_fr +``` +""" +function constraint_ohms_yt_dc{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) + return Set([c1]) +end + + +"" +function add_bus_voltage_setpoint{T <: AbstractDistflowForm}(sol, pm::GenericPowerModel{T}) + add_setpoint(sol, pm, "bus", "bus_i", "vm", :w; scale = (x,item) -> sqrt(x)) + # What should the default value be? + #add_setpoint(sol, pm, "bus", "bus_i", "va", :t; default_value = 0) +end + + +"Do nothing, this model doesn't have voltage angle variables" +constraint_phase_angle_difference{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) = Set() From e3a560090db9a1a82baa711a4aeb4f5ecf890047 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Tue, 25 Jul 2017 09:52:52 +0200 Subject: [PATCH 11/23] Removal of Distflow, will become separate project --- src/core/variable.jl | 5 -- src/form/distflow.jl | 141 ------------------------------------------- 2 files changed, 146 deletions(-) delete mode 100644 src/form/distflow.jl diff --git a/src/core/variable.jl b/src/core/variable.jl index 8f715f257..8bcddbc64 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -55,11 +55,6 @@ function variable_voltage_magnitude_sqr(pm::GenericPowerModel; bounded = true) return w end -function variable_current_magnitude_sqr(pm::GenericPowerModel) - @variable(pm.model, i_sq[i in keys(pm.ref[:branch])] >= 0) - return i_sq -end - "variable: `0 <= w_from[l] <= buses[branches[l][\"f_bus\"]][\"vmax\"]^2` for `l` in `branch`es" function variable_voltage_magnitude_sqr_from_on_off(pm::GenericPowerModel) buses = pm.ref[:bus] diff --git a/src/form/distflow.jl b/src/form/distflow.jl deleted file mode 100644 index e238b079b..000000000 --- a/src/form/distflow.jl +++ /dev/null @@ -1,141 +0,0 @@ -export - SOCDistflowPowerModel, SOCDistflowForm - -"" -@compat abstract type AbstractDistflowForm <: AbstractPowerFormulation end - -"" -@compat abstract type SOCDistflowForm <: AbstractDistflowForm end - -"" -const SOCDistflowPowerModel = GenericPowerModel{SOCDistflowForm} - -"default SOC constructor" -SOCDistflowPowerModel(data::Dict{String,Any}; kwargs...) = GenericPowerModel(data, SOCDistflowForm; kwargs...) - -"" -function variable_voltage{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}; kwargs...) - variable_voltage_magnitude_sqr(pm; kwargs...) -# variable_voltage_product(pm; kwargs...) - variable_current_magnitude_sqr(pm; kwargs...) -end - -"" -function constraint_voltage{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}) - w = getindex(pm.model, :w) -end - -"Do nothing, no way to represent this in these variables" -constraint_theta_ref{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, ref_bus::Int) = Set() - -function constraint_voltage_magnitude_setpoint{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, i, vm, epsilon) - w = getindex(pm.model, :w)[i] - - if epsilon == 0.0 - c = @constraint(pm.model, w == vm^2) - return Set([c]) - else - @assert epsilon > 0.0 - c1 = @constraint(pm.model, w <= (vm + epsilon)^2) - c2 = @constraint(pm.model, w >= (vm - epsilon)^2) - return Set([c1, c2]) - end -end - -"" -function constraint_kcl_shunt{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) - w = getindex(pm.model, :w)[i] - p = getindex(pm.model, :p) - q = getindex(pm.model, :q) - pg = getindex(pm.model, :pg) - qg = getindex(pm.model, :qg) - p_dc = getindex(pm.model, :p_dc) - q_dc = getindex(pm.model, :q_dc) - - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w) - return Set([c1, c2]) -end - -"Do nothing, this model is symmetric" -constraint_ohms_yt_from{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) = Set() - - -""" -Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) - -``` -p[t_idx] == g*w[t_bus] + (-g*tr-b*ti)/tm*(wr[f_bus,t_bus]) + (-b*tr+g*ti)/tm*(-wi[f_bus,t_bus]) -q[t_idx] == -(b+c/2)*w[t_bus] - (-b*tr+g*ti)/tm*(wr[f_bus,t_bus]) + (-g*tr-b*ti)/tm*(-wi[f_bus,t_bus]) -``` -""" -function constraint_ohms_yt_to{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) - q_fr = getindex(pm.model, :q)[f_idx] - q_to = getindex(pm.model, :q)[t_idx] - p_fr = getindex(pm.model, :p)[f_idx] - p_to = getindex(pm.model, :p)[t_idx] - w_fr = getindex(pm.model, :w)[f_bus] - w_to = getindex(pm.model, :w)[t_bus] - i_sq = getindex(pm.model, :i_sq)[f_idx[1]] - r = g/(g^2 + b^2) - x = -b/(g^2 + b^2) - g_sh = 0 - b_sh = c/2 - - c1 = @constraint(pm.model, p_to + p_fr == g_sh*w_fr +r*i_sq + g_sh*w_to) - c2 = @constraint(pm.model, q_to + p_fr == -b_sh*w_fr + x*i_sq - b_sh*w_to) - c3 = @constraint(pm.model, (p_fr - g_sh*w_fr)^2 + (q_fr - b_sh*w_fr)^2 <= i_sq*w_fr) - c4 = @constraint(pm.model, w_to - w_fr == -2*(r*(p_fr - g_sh*w_fr) +x*(q_fr - b_sh*w_fr)) +(r^2+x^2)*i_sq) - return Set([c1, c2, c3, c4]) -end - - -function constraint_ohms_yt_from_on_off{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm) - q_fr = getindex(pm.model, :q)[f_idx] - q_to = getindex(pm.model, :q)[t_idx] - p_fr = getindex(pm.model, :p)[f_idx] - p_to = getindex(pm.model, :p)[t_idx] - w_fr = getindex(pm.model, :w)[f_bus] - w_to = getindex(pm.model, :w)[t_bus] - i_sq = getindex(pm.model, :i_sq)[f_idx[1]] - z = getindex(pm.model, :line_z) - - r = g/(g^2 + b^2) - x = -b/(g^2 + b^2) - g_sh = 0 - b_sh = c/2 - - c1 = @constraint(pm.model, p_to + p_fr == g_sh*w_fr +r*i_sq + g_sh*w_to) - c2 = @constraint(pm.model, q_to + p_fr == -b_sh*w_fr + x*i_sq - b_sh*w_to) - c3 = @constraint(pm.model, (p_fr - g_sh*w_fr)^2 + (q_fr - b_sh*w_fr)^2 <= i_sq*w_fr) - c4 = @constraint(pm.model, w_to - w_fr == -2*(r*(p_fr - g_sh*w_fr) +x*(q_fr - b_sh*w_fr)) +(r^2+x^2)*i_sq) - return Set([c1, c2, c3, c4]) -end - - -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -p_fr + p_to == loss0 + loss1 * p_fr -``` -""" -function constraint_ohms_yt_dc{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) - return Set([c1]) -end - - -"" -function add_bus_voltage_setpoint{T <: AbstractDistflowForm}(sol, pm::GenericPowerModel{T}) - add_setpoint(sol, pm, "bus", "bus_i", "vm", :w; scale = (x,item) -> sqrt(x)) - # What should the default value be? - #add_setpoint(sol, pm, "bus", "bus_i", "va", :t; default_value = 0) -end - - -"Do nothing, this model doesn't have voltage angle variables" -constraint_phase_angle_difference{T <: AbstractDistflowForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) = Set() From a036afe3ab164040f8b1ade988e63cb8724de9c8 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Tue, 25 Jul 2017 14:17:56 +0200 Subject: [PATCH 12/23] Fix OTS and TNEP tests - All (pure ac model) tests now work as before supporting dc lines - Tests of mixed ac-dc still to be developed --- src/core/constraint_template.jl | 3 ++- src/form/dcp.jl | 4 ++-- src/form/wr.jl | 6 +++--- src/prob/tnep.jl | 17 +++++++++++------ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 649753c34..869d9796a 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -58,10 +58,11 @@ end function constraint_kcl_shunt_ne(pm::GenericPowerModel, bus) i = bus["index"] bus_arcs = pm.ref[:bus_arcs][i] + bus_arcs_dc = pm.ref[:bus_arcs_dc][i] bus_arcs_ne = pm.ref[:ne_bus_arcs][i] bus_gens = pm.ref[:bus_gens][i] - return constraint_kcl_shunt_ne(pm, i, bus_arcs, bus_arcs_ne, bus_gens, bus["pd"], bus["qd"], bus["gs"], bus["bs"]) + return constraint_kcl_shunt_ne(pm, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, bus["pd"], bus["qd"], bus["gs"], bus["bs"]) end ### Branch - Ohm's Law Constraints ### diff --git a/src/form/dcp.jl b/src/form/dcp.jl index 874706284..70483dd55 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -92,12 +92,12 @@ function constraint_kcl_shunt{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, end "" -function constraint_kcl_shunt_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) pg = getindex(pm.model, :pg) p_expr = pm.model.ext[:p_expr] p_ne_expr = pm.model.ext[:p_ne_expr] - c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) + sum(p_ne_expr[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) + c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) + sum(p_ne_expr[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc)== sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) return Set([c]) end diff --git a/src/form/wr.jl b/src/form/wr.jl index 79effaa85..794aa73ac 100644 --- a/src/form/wr.jl +++ b/src/form/wr.jl @@ -95,7 +95,7 @@ sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*w[i] ``` """ -function constraint_kcl_shunt_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) w = getindex(pm.model, :w)[i] p = getindex(pm.model, :p) q = getindex(pm.model, :q) @@ -104,8 +104,8 @@ function constraint_kcl_shunt_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}, pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*w) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*w) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w) return Set([c1, c2]) end diff --git a/src/prob/tnep.jl b/src/prob/tnep.jl index 8894cde6d..9ab4cbd01 100644 --- a/src/prob/tnep.jl +++ b/src/prob/tnep.jl @@ -6,20 +6,21 @@ export run_tnep "" function run_tnep(file, model_constructor, solver; kwargs...) - return run_generic_model(file, model_constructor, solver, post_tnep; solution_builder = get_tnep_solution, kwargs...) + return run_generic_model(file, model_constructor, solver, post_tnep; solution_builder = get_tnep_solution, kwargs...) end "the general form of the tnep optimization model" function post_tnep(pm::GenericPowerModel) - variable_line_ne(pm) + variable_line_ne(pm) variable_voltage(pm) variable_voltage_ne(pm) variable_generation(pm) variable_line_flow(pm) + variable_line_flow_dc(pm) variable_line_flow_ne(pm) objective_tnep_cost(pm) - + constraint_voltage(pm) constraint_voltage_ne(pm) @@ -39,17 +40,21 @@ function post_tnep(pm::GenericPowerModel) constraint_thermal_limit_from(pm, branch) constraint_thermal_limit_to(pm, branch) - end + end for (i,branch) in pm.ref[:ne_branch] constraint_ohms_yt_from_ne(pm, branch) - constraint_ohms_yt_to_ne(pm, branch) + constraint_ohms_yt_to_ne(pm, branch) constraint_phase_angle_difference_ne(pm, branch) constraint_thermal_limit_from_ne(pm, branch) constraint_thermal_limit_to_ne(pm, branch) end + + for (i,dcline) in pm.ref[:dcline] + constraint_ohms_yt_dc(pm, dcline) + end end "" @@ -58,7 +63,7 @@ function get_tnep_solution(pm::GenericPowerModel) add_bus_voltage_setpoint(sol, pm) add_generator_power_setpoint(sol, pm) add_branch_flow_setpoint(sol, pm) - add_branch_flow_setpoint_ne(sol, pm) + add_branch_flow_setpoint_ne(sol, pm) add_branch_ne_setpoint(sol, pm) return sol end From db51ca1e75c95629a70f26833f636e82b50f3924 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Tue, 25 Jul 2017 18:28:59 +0200 Subject: [PATCH 13/23] Bugfix/rewrite for negative PMIN values in a matpower case - losses not considered in variable bounds - but bounds are now derived according to matpower (see toggle_dcline.m) --- src/core/variable.jl | 18 ++++++++++-------- src/io/matpower.jl | 36 +++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/core/variable.jl b/src/core/variable.jl index 8bcddbc64..6de898716 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -131,6 +131,7 @@ end ############## DC Lines ############################################ function variable_line_flow_dc(pm::GenericPowerModel; kwargs...) variable_active_line_flow_dc(pm; kwargs...) + variable_reactive_line_flow_dc(pm; kwargs...) end @@ -148,17 +149,18 @@ function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) pmax[(l,j,i)] = pm.ref[:dcline][l]["pmaxt"] pref[(l,i,j)] = pm.ref[:dcline][l]["pf"] pref[(l,j,i)] = pm.ref[:dcline][l]["pt"] - loss0[(l,i,j)] = 0 - loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] + loss0[(l,i,j)] = 0 #loss completely assigned to to side as per matpower + loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] #loss completely assigned to to side as per matpower br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] end - if bounded - @variable(pm.model, br_status[(l,i,j)] * (pmin[(l,i,j)] + (loss0[(l,i,j)])) <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * (pmax[(l,i,j)] + (loss0[(l,i,j)])), start = pref[(l,i,j)]) - else - M = 5; - @variable(pm.model, M*br_status[(l,i,j)] * (pmin[(l,i,j)] + (loss0[(l,i,j)])) <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * (pmax[(l,i,j)] + (loss0[(l,i,j)])), start = pref[(l,i,j)]) - end + + if bounded + @variable(pm.model, br_status[(l,i,j)] * pmin[(l,i,j)] <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * pmax[(l,i,j)], start = pref[(l,i,j)]) + else + @variable(pm.model, M*br_status[(l,i,j)] * pmin[(l,i,j)] <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * pmax[(l,i,j)], start = pref[(l,i,j)]) + end + print(p_dc) return p_dc end diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 00f463665..0217662f4 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -494,20 +494,26 @@ function parse_matpower_data(data_string::String) dclines = [] for (i, dcline_row) in enumerate(parsed_matrix["data"]) - if parse(Float64, dcline_row[10]) > 0 - pminf = parse(Float64, dcline_row[10]) - pmint = -min(abs(parse(Float64, dcline_row[10])),abs(parse(Float64, dcline_row[11]))) - else - pmint = parse(Float64, dcline_row[10]) - pminf = -min(abs(parse(Float64, dcline_row[10])),abs(parse(Float64, dcline_row[11]))) + pmin = parse(Float64, dcline_row[10]) + pmax = parse(Float64, dcline_row[11]) + pmaxt = Inf + pmaxf = Inf + pminf = -Inf + pmint = -Inf + + if pmin >= 0 + pminf = pmin # fg(k, PMAX) = -dc(k, c.PMIN); end - if parse(Float64, dcline_row[11]) > 0 - pmaxf = parse(Float64, dcline_row[11]) - pmaxt = max(abs(parse(Float64, dcline_row[11])),abs(parse(Float64, dcline_row[10]))) - else - pmaxt = parse(Float64, dcline_row[11]) - pmaxf = max(abs(parse(Float64, dcline_row[11])),abs(parse(Float64, dcline_row[10]))) + if pmax >= 0 + pmaxf = pmax # fg(k, PMIN) = -dc(k, c.PMAX); end + if pmin <0 + pmaxt = -pmin # tg(k, PMIN) = dc(k, c.PMIN); + end + if pmax < 0 + pmint = pmax # tg(k, PMAX) = dc(k, c.PMAX); + end + print([pmin pmax pminf pmaxf pmint pmaxt]) dcline_data = Dict{String,Any}( "index" => i, @@ -515,9 +521,9 @@ function parse_matpower_data(data_string::String) "t_bus" => parse(Int, dcline_row[2]), "br_status" => parse(Int, dcline_row[3]), "pf" => parse(Float64, dcline_row[4]), - "pt" => parse(Float64, dcline_row[5]), - "qf" => parse(Float64, dcline_row[6]), - "qt" => parse(Float64, dcline_row[7]), + "pt" => -parse(Float64, dcline_row[5]), # matpower has opposite convention + "qf" => -parse(Float64, dcline_row[6]), # matpower has opposite convention TODO futher validate starting point signs + "qt" => -parse(Float64, dcline_row[7]), # matpower has opposite convention "vf" => parse(Float64, dcline_row[8]), "vt" => parse(Float64, dcline_row[9]), "pmint" => pmint, From 32c08f3294aa3f4f21f9d142aadcfe4d3caeb80f Mon Sep 17 00:00:00 2001 From: hakanergun Date: Wed, 26 Jul 2017 17:32:53 +0200 Subject: [PATCH 14/23] Finalized testing of DC Line implementation - Added case3_dc, case5_dc with active DC lines - Updated \test\opf.j and \test\pf.jl and validated active DC lines cases against matpower - Warning that DC line costs are not supported - Implemented Carleton's code review + additional clean-up --- CHANGELOG.md | 9 ++++--- src/core/base.jl | 31 +++++++---------------- src/core/constraint.jl | 19 ++++++++++++++ src/core/constraint_template.jl | 43 +++++++++++++++++++++++++++++--- src/core/data.jl | 8 ++++++ src/core/solution.jl | 4 +-- src/core/variable.jl | 20 ++++----------- src/form/acp.jl | 39 ++++++++++++++++++----------- src/form/dcp.jl | 18 +++----------- src/form/wr.jl | 38 +++++++++++++++++----------- src/form/wrm.jl | 18 +++----------- src/io/matpower.jl | 4 +-- src/prob/misc.jl | 4 +-- src/prob/opf.jl | 2 +- src/prob/ots.jl | 2 +- src/prob/pf.jl | 4 ++- src/prob/tnep.jl | 2 +- test/data/case3_dc.m | 12 ++++----- test/data/case5_dc.m | 18 +++++++------- test/docs.jl | 4 +-- test/opf.jl | 14 ++++++++++- test/pf.jl | 44 ++++++++++++++++++++++++++++----- 22 files changed, 219 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 458121b3d..4c33054c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -PowerModels.jl Change Log +PowerModels.jl Change Log ================= ### Staged @@ -7,16 +7,17 @@ PowerModels.jl Change Log - Fixed bug in constants for w-space phase angle difference constraints - Fixed bug when no refrence bus was specified - Fixed dcline parsing bug +- Support for DC Line formulation compatible with matpower ### v0.3.3 - Added JuMP v0.17 compatibility -- Reorganized documentation into Manual, Library, Developer, and Experimental Results +- Reorganized documentation into Manual, Library, Developer, and Experimental Results ### v0.3.2 - Updated type declarations to Julia v0.6 syntax - Moved documentation to Documenter.jl (thanks to @yeesian) - Added basic OPF results to Documentation -- Extended pm.ref include all fields from pm.data +- Extended pm.ref include all fields from pm.data ### v0.3.1 - Added JuMP v0.16 and Julia v0.6 compatibility @@ -46,7 +47,7 @@ PowerModels.jl Change Log - Added support Matlab cell arrays - Added support for Matpower bus_names - Added ability for reading non-standard Matpower data elements -- Added JuMP version v0.14 upper bound +- Added JuMP version v0.14 upper bound ### v0.2.2 - Added Transmission Network Expansion Planning (tnep) problem. diff --git a/src/core/base.jl b/src/core/base.jl index dba37720e..36fbfc7b2 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -176,18 +176,15 @@ function build_ref(data::Dict{String,Any}) ref[:bus] = filter((i, bus) -> bus["bus_type"] != 4, ref[:bus]) ref[:gen] = filter((i, gen) -> gen["gen_status"] == 1 && gen["gen_bus"] in keys(ref[:bus]), ref[:gen]) ref[:branch] = filter((i, branch) -> branch["br_status"] == 1 && branch["f_bus"] in keys(ref[:bus]) && branch["t_bus"] in keys(ref[:bus]), ref[:branch]) + ref[:dcline] = filter((i, dcline) -> dcline["br_status"] == 1 && dcline["f_bus"] in keys(ref[:bus]) && dcline["t_bus"] in keys(ref[:bus]), ref[:dcline]) ref[:arcs_from] = [(i,branch["f_bus"],branch["t_bus"]) for (i,branch) in ref[:branch]] ref[:arcs_to] = [(i,branch["t_bus"],branch["f_bus"]) for (i,branch) in ref[:branch]] ref[:arcs] = [ref[:arcs_from]; ref[:arcs_to]] -#############################DC LINES############## - if haskey(ref, :dcline) - ref[:arcs_from_dc] = [(i,dcline["f_bus"],dcline["t_bus"]) for (i,dcline) in ref[:dcline]] - ref[:arcs_to_dc] = [(i,dcline["t_bus"],dcline["f_bus"]) for (i,dcline) in ref[:dcline]] - ref[:arcs_dc] = [ref[:arcs_from_dc]; ref[:arcs_to_dc]] - end -################################################### + ref[:arcs_from_dc] = [(i,dcline["f_bus"],dcline["t_bus"]) for (i,dcline) in ref[:dcline]] + ref[:arcs_to_dc] = [(i,dcline["t_bus"],dcline["f_bus"]) for (i,dcline) in ref[:dcline]] + ref[:arcs_dc] = [ref[:arcs_from_dc]; ref[:arcs_to_dc]] bus_gens = Dict([(i, []) for (i,bus) in ref[:bus]]) for (i,gen) in ref[:gen] @@ -201,17 +198,11 @@ function build_ref(data::Dict{String,Any}) end ref[:bus_arcs] = bus_arcs - -######################### DC LINES ################################### - if haskey(ref, :dcline) - bus_arcs_dc = Dict([(i, []) for (i,bus) in ref[:bus]]) - for (l,i,j) in ref[:arcs_dc] - push!(bus_arcs_dc[i], (l,i,j)) - end - ref[:bus_arcs_dc] = bus_arcs_dc + bus_arcs_dc = Dict([(i, []) for (i,bus) in ref[:bus]]) + for (l,i,j) in ref[:arcs_dc] + push!(bus_arcs_dc[i], (l,i,j)) end -################################################################# - + ref[:bus_arcs_dc] = bus_arcs_dc # a set of buses to support multiple connected components ref_buses = Dict() @@ -343,11 +334,7 @@ function buspair_parameters_dc(arcs_from_dc, dclines, buses) "qf"=>dclines[bp_line[(i,j)]]["qf"], "qt"=>dclines[bp_line[(i,j)]]["qt"], "vf"=>dclines[bp_line[(i,j)]]["vf"], - "vt"=>dclines[bp_line[(i,j)]]["vt"], - "v_from_min"=>buses[i]["vmin"], - "v_from_max"=>buses[i]["vmax"], - "v_to_min"=>buses[j]["vmin"], - "v_to_max"=>buses[j]["vmax"] + "vt"=>dclines[bp_line[(i,j)]]["vt"] )) for (i,j) in buspair_indexes]) return buspairs_dc diff --git a/src/core/constraint.jl b/src/core/constraint.jl index 74a955cea..52cd2c363 100644 --- a/src/core/constraint.jl +++ b/src/core/constraint.jl @@ -88,3 +88,22 @@ function constraint_reactive_gen_setpoint(pm::GenericPowerModel, i, qg) c = @constraint(pm.model, qg_var == qg) return Set([c]) end + +"`pf[i] == pf, pt[i] == pt`" +function constraint_active_dc_line_setpoint(pm::GenericPowerModel, i, f_idx, t_idx, pf, pt, epsilon) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + if epsilon == 0.0 + c1 = @constraint(pm.model, p_fr == pf) + c2 = @constraint(pm.model, p_to == pt) + return Set([c1,c2]) + else + c1 = @constraint(pm.model, p_fr >= pf - epsilon) + c2 = @constraint(pm.model, p_to >= pt - epsilon) + c3 = @constraint(pm.model, p_fr <= pf + epsilon) + c4 = @constraint(pm.model, p_to <= pt + epsilon) + return Set([c1,c2,c3,c4]) + end + +end diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 869d9796a..6770b6b68 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -86,17 +86,54 @@ end ### Branch - Loss Constraints DC LINES### "" -function constraint_ohms_yt_dc(pm::GenericPowerModel, dcline) +function constraint_dc_line(pm::GenericPowerModel, dcline) i = dcline["index"] f_bus = dcline["f_bus"] t_bus = dcline["t_bus"] f_idx = (i, f_bus, t_bus) t_idx = (i, t_bus, f_bus) - br_status = dcline["br_status"] loss0 = dcline["loss0"] loss1 = dcline["loss1"] - return constraint_ohms_yt_dc(pm, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) + return constraint_dc_line(pm, f_bus, t_bus, f_idx, t_idx, loss0, loss1) +end + +""" +Creates Line Flow constraint for DC Lines (Matpower Formulation) + +``` +p_fr + p_to == loss0 + p_fr * loss1 +``` +""" +function constraint_dc_line{T}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, loss0, loss1) + p_fr = getindex(pm.model, :p_dc)[f_idx] + p_to = getindex(pm.model, :p_dc)[t_idx] + + c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0) == 0) + return Set([c1]) +end + +"" +function constraint_dc_line_voltage(pm::GenericPowerModel, dcline; epsilon = 0.0) + @assert epsilon >= 0.0 + i = dcline["index"] + f_bus = dcline["f_bus"] + t_bus = dcline["t_bus"] + vf = dcline["vf"] + vt = dcline["vt"] + + return constraint_dc_line_voltage(pm, f_bus, t_bus, vf, vt, epsilon) +end + +function constraint_active_dc_line_setpoint(pm::GenericPowerModel, dcline; epsilon = 0.0) + i = dcline["index"] + f_bus = dcline["f_bus"] + t_bus = dcline["t_bus"] + f_idx = (i, f_bus, t_bus) + t_idx = (i, t_bus, f_bus) + pf = dcline["pf"] + pt = dcline["pt"] + return constraint_active_dc_line_setpoint(pm, i, f_idx, t_idx, pf, pt, epsilon) end "" diff --git a/src/core/data.jl b/src/core/data.jl index fb27b255d..fbc9358fc 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -157,6 +157,10 @@ function make_per_unit(data::Dict{String,Any}) for dcline in dclines apply_func(dcline, "loss0", rescale) + apply_func(dcline, "pf", rescale) + apply_func(dcline, "pt", rescale) + apply_func(dcline, "qf", rescale) + apply_func(dcline, "qt", rescale) apply_func(dcline, "pmaxt", rescale) apply_func(dcline, "pmint", rescale) apply_func(dcline, "pmaxf", rescale) @@ -240,6 +244,10 @@ function make_mixed_units(data::Dict{String,Any}) for dcline in dclines apply_func(dcline, "loss0", rescale) + apply_func(dcline, "pf", rescale) + apply_func(dcline, "pt", rescale) + apply_func(dcline, "qf", rescale) + apply_func(dcline, "qt", rescale) apply_func(dcline, "pmaxt", rescale) apply_func(dcline, "pmint", rescale) apply_func(dcline, "pmaxf", rescale) diff --git a/src/core/solution.jl b/src/core/solution.jl index 4ce1bd968..0aca56f80 100644 --- a/src/core/solution.jl +++ b/src/core/solution.jl @@ -44,7 +44,7 @@ function get_solution(pm::GenericPowerModel) add_bus_voltage_setpoint(sol, pm) add_generator_power_setpoint(sol, pm) add_branch_flow_setpoint(sol, pm) - add_branch_flow_setpoint_dc(sol, pm) + add_dc_line_flow_setpoint(sol, pm) return sol end @@ -82,7 +82,7 @@ function add_branch_flow_setpoint(sol, pm::GenericPowerModel) end "" -function add_branch_flow_setpoint_dc(sol, pm::GenericPowerModel) +function add_dc_line_flow_setpoint(sol, pm::GenericPowerModel) # check the line flows were requested if haskey(pm.setting, "output") && haskey(pm.setting["output"], "line_flows") && pm.setting["output"]["line_flows"] == true mva_base = pm.data["baseMVA"] diff --git a/src/core/variable.jl b/src/core/variable.jl index 6de898716..f7951d97a 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -131,7 +131,6 @@ end ############## DC Lines ############################################ function variable_line_flow_dc(pm::GenericPowerModel; kwargs...) variable_active_line_flow_dc(pm; kwargs...) - variable_reactive_line_flow_dc(pm; kwargs...) end @@ -141,7 +140,6 @@ function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) pref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) pmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) loss0 = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) for (l,i,j) in pm.ref[:arcs_from_dc] pmin[(l,i,j)] = pm.ref[:dcline][l]["pminf"] pmax[(l,i,j)] = pm.ref[:dcline][l]["pmaxf"] @@ -151,16 +149,12 @@ function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) pref[(l,j,i)] = pm.ref[:dcline][l]["pt"] loss0[(l,i,j)] = 0 #loss completely assigned to to side as per matpower loss0[(l,j,i)] = pm.ref[:dcline][l]["loss0"] #loss completely assigned to to side as per matpower - br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] - br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] end - if bounded - @variable(pm.model, br_status[(l,i,j)] * pmin[(l,i,j)] <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * pmax[(l,i,j)], start = pref[(l,i,j)]) + @variable(pm.model, pmin[(l,i,j)] <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= pmax[(l,i,j)], start = pref[(l,i,j)]) else - @variable(pm.model, M*br_status[(l,i,j)] * pmin[(l,i,j)] <= p_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * pmax[(l,i,j)], start = pref[(l,i,j)]) + @variable(pm.model, p_dc[(l,i,j) in pm.ref[:arcs_dc]], start = pref[(l,i,j)]) end - print(p_dc) return p_dc end @@ -169,7 +163,6 @@ function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) qmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) qref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) qmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) - br_status = Dict([(a, 0) for a in pm.ref[:arcs_dc]]) for (l,i,j) in pm.ref[:arcs_from_dc] qmin[(l,i,j)] = pm.ref[:dcline][l]["qminf"] qmax[(l,i,j)] = pm.ref[:dcline][l]["qmaxf"] @@ -177,15 +170,12 @@ function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) qmax[(l,j,i)] = pm.ref[:dcline][l]["qmaxt"] qref[(l,i,j)] = pm.ref[:dcline][l]["qf"] qref[(l,j,i)] = pm.ref[:dcline][l]["qt"] - br_status[(l,i,j)] = pm.ref[:dcline][l]["br_status"] - br_status[(l,j,i)] = pm.ref[:dcline][l]["br_status"] - end + end if bounded - @variable(pm.model, br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) + @variable(pm.model, qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= qmax[(l,i,j)], start = qref[(l,i,j)]) else - M = 5; - @variable(pm.model, M*br_status[(l,i,j)] * qmin[(l,i,j)] <= q_dc[(l,i,j) in pm.ref[:arcs_dc]] <= M*br_status[(l,i,j)] * qmax[(l,i,j)], start = qref[(l,i,j)]) + @variable(pm.model, q_dc[(l,i,j) in pm.ref[:arcs_dc]], start = qref[(l,i,j)]) end return q_dc end diff --git a/src/form/acp.jl b/src/form/acp.jl index a0706ff99..4211d47c9 100644 --- a/src/form/acp.jl +++ b/src/form/acp.jl @@ -48,6 +48,30 @@ function constraint_voltage_magnitude_setpoint{T <: AbstractACPForm}(pm::Generic end end +""" +for DC line power flow: +''' +v_from - epsilon <= v[i] <= v_from + epsilon +v_to - epsilon <= v[i] <= v_to + epsilon +''' +""" +function constraint_dc_line_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) + v_f = getindex(pm.model, :v)[f_bus] + v_t = getindex(pm.model, :v)[t_bus] + + if epsilon == 0.0 + c1 = @constraint(pm.model, v_f == vf) + c2 = @constraint(pm.model, v_t == vt) + return Set([c1, c2]) + else + c1 = @constraint(pm.model, v_f <= vf + epsilon) + c2 = @constraint(pm.model, v_f >= vf - epsilon) + c3 = @constraint(pm.model, v_t <= vt + epsilon) + c4 = @constraint(pm.model, v_t >= vt - epsilon) + return Set([c1, c2, c3, c4]) + end +end + """ ``` sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 @@ -130,21 +154,6 @@ function constraint_ohms_yt_to{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f return Set([c1, c2]) end -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -(1-loss1) * p_fr + (p_to - loss0 * br_status) == 0 -``` -""" -function constraint_ohms_yt_dc{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) - return Set([c1]) -end - """ Creates Ohms constraints for AC models (y post fix indicates that Y values are in rectangular form) diff --git a/src/form/dcp.jl b/src/form/dcp.jl index 70483dd55..f621d5ce0 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -80,6 +80,9 @@ constraint_voltage_magnitude_setpoint{T <: AbstractDCPForm}(pm::GenericPowerMode "do nothing, this model does not have reactive variables" constraint_reactive_gen_setpoint{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, qg) = Set() +"do nothing, this model does not have voltage variables" +constraint_dc_line_voltage{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() + "" function constraint_kcl_shunt{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) pg = getindex(pm.model, :pg) @@ -132,21 +135,6 @@ function constraint_ohms_yt_from_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{ return Set([c1, c2]) end -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -p_fr + p_to == loss0 + loss1 * p_fr -``` -""" -function constraint_ohms_yt_dc{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) - return Set([c1]) -end - "Do nothing, this model is symmetric" constraint_ohms_yt_to_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, f_bus, t_bus, f_idx, t_idx, g, b, c, tr, ti, tm, t_min, t_max) = Set() diff --git a/src/form/wr.jl b/src/form/wr.jl index 794aa73ac..e27d19121 100644 --- a/src/form/wr.jl +++ b/src/form/wr.jl @@ -74,6 +74,29 @@ function constraint_voltage_magnitude_setpoint{T <: AbstractWRForm}(pm::GenericP end end +""" +for DC line voltage: +''' +(v_from - epsilon)^2 <= w[i] <= (v_from + epsilon)^2 +(v_to - epsilon)^2 <= w[i] <= (v_to + epsilon)^2 +''' +""" +function constraint_dc_line_voltage{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) + w_f = getindex(pm.model, :w)[f_bus] + w_t = getindex(pm.model, :w)[t_bus] + if epsilon == 0.0 + c1 = @constraint(pm.model, w_f == vf^2) + c2 = @constraint(pm.model, w_t == vt^2) + return Set([c1, c2]) + else + c1 = @constraint(pm.model, w_f <= (vf + epsilon)^2) + c2 = @constraint(pm.model, w_f >= (vf - epsilon)^2) + c3 = @constraint(pm.model, w_t <= (vt + epsilon)^2) + c4 = @constraint(pm.model, w_t >= (vt - epsilon)^2) + return Set([c1, c2, c3, c4]) + end +end + "" function constraint_kcl_shunt{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) w = getindex(pm.model, :w)[i] @@ -149,21 +172,6 @@ function constraint_ohms_yt_to{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_ return Set([c1, c2]) end -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -p_fr + p_to == loss0 + loss1 * p_fr -``` -""" -function constraint_ohms_yt_dc{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) - return Set([c1]) -end - """ Creates Ohms constraints (yt post fix indicates that Y and T values are in rectangular form) diff --git a/src/form/wrm.jl b/src/form/wrm.jl index 87675d32e..8a7759455 100644 --- a/src/form/wrm.jl +++ b/src/form/wrm.jl @@ -131,21 +131,6 @@ function constraint_ohms_yt_to{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f return Set([c1, c2]) end -""" -Creates Ohms constraints for DC Lines (yt post fix indicates that Y and T values are in rectangular form) - -``` -p_fr + p_to == loss0 + loss1 * p_fr -``` -""" -function constraint_ohms_yt_dc{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, br_status, loss0, loss1) - p_fr = getindex(pm.model, :p_dc)[f_idx] - p_to = getindex(pm.model, :p_dc)[t_idx] - - c1 = @constraint(pm.model, (1-loss1) * p_fr + (p_to - loss0 * br_status) == 0) - return Set([c1]) -end - "" function constraint_phase_angle_difference{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, angmin, angmax) WR = getindex(pm.model, :WR) @@ -173,3 +158,6 @@ function add_bus_voltage_setpoint{T <: AbstractWRMForm}(sol, pm::GenericPowerMod # What should the default value be? #add_setpoint(sol, pm, "bus", "bus_i", "va", :t; default_value = 0) end + +"DC Line voltage constraint not supported" +constraint_dc_line_voltage{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 0217662f4..6798e3436 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -492,6 +492,7 @@ function parse_matpower_data(data_string::String) elseif parsed_matrix["name"] == "dcline" dclines = [] + warn("DC Line costs are not considered") for (i, dcline_row) in enumerate(parsed_matrix["data"]) pmin = parse(Float64, dcline_row[10]) @@ -513,7 +514,6 @@ function parse_matpower_data(data_string::String) if pmax < 0 pmint = pmax # tg(k, PMAX) = dc(k, c.PMAX); end - print([pmin pmax pminf pmaxf pmint pmaxt]) dcline_data = Dict{String,Any}( "index" => i, @@ -522,7 +522,7 @@ function parse_matpower_data(data_string::String) "br_status" => parse(Int, dcline_row[3]), "pf" => parse(Float64, dcline_row[4]), "pt" => -parse(Float64, dcline_row[5]), # matpower has opposite convention - "qf" => -parse(Float64, dcline_row[6]), # matpower has opposite convention TODO futher validate starting point signs + "qf" => -parse(Float64, dcline_row[6]), # matpower has opposite convention "qt" => -parse(Float64, dcline_row[7]), # matpower has opposite convention "vf" => parse(Float64, dcline_row[8]), "vt" => parse(Float64, dcline_row[9]), diff --git a/src/prob/misc.jl b/src/prob/misc.jl index d2397f090..accd002d3 100644 --- a/src/prob/misc.jl +++ b/src/prob/misc.jl @@ -52,7 +52,7 @@ function post_api_opf(pm::GenericPowerModel) for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + constraint_dc_line(pm, dcline) end end @@ -98,6 +98,6 @@ function post_sad_opf{T <: Union{AbstractACPForm, AbstractDCPForm}}(pm::GenericP end for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + constraint_dc_line(pm, dcline) end end diff --git a/src/prob/opf.jl b/src/prob/opf.jl index 0883ff089..f87aa3608 100644 --- a/src/prob/opf.jl +++ b/src/prob/opf.jl @@ -44,6 +44,6 @@ function post_opf(pm::GenericPowerModel) constraint_thermal_limit_to(pm, branch) end for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + constraint_dc_line(pm, dcline) end end diff --git a/src/prob/ots.jl b/src/prob/ots.jl index ac776b240..548b77be6 100644 --- a/src/prob/ots.jl +++ b/src/prob/ots.jl @@ -43,7 +43,7 @@ function post_ots(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + constraint_dc_line(pm, dcline) end end diff --git a/src/prob/pf.jl b/src/prob/pf.jl index 666c2516a..e5ff0e1c1 100644 --- a/src/prob/pf.jl +++ b/src/prob/pf.jl @@ -51,6 +51,8 @@ function post_pf(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + #constraint_dc_line(pm, dcline) + constraint_active_dc_line_setpoint(pm, dcline; epsilon = 0.0) + constraint_dc_line_voltage(pm, dcline; epsilon = 0.00001) end end diff --git a/src/prob/tnep.jl b/src/prob/tnep.jl index 9ab4cbd01..0d47ee02e 100644 --- a/src/prob/tnep.jl +++ b/src/prob/tnep.jl @@ -53,7 +53,7 @@ function post_tnep(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - constraint_ohms_yt_dc(pm, dcline) + constraint_dc_line(pm, dcline) end end diff --git a/test/data/case3_dc.m b/test/data/case3_dc.m index 52c939c65..ea54e2213 100644 --- a/test/data/case3_dc.m +++ b/test/data/case3_dc.m @@ -1,6 +1,6 @@ % Case to test adding data to matpower file % based on nesta_case3_lmbd from NESTA v0.6.0 -function mpc = case3 +function mpc = case3_dc mpc.version = '2'; mpc.baseMVA = 100.0; @@ -11,9 +11,9 @@ ]; mpc.gen = [ - 1 148.067 54.697 1000.0 -1000.0 1.1 100.0 1 2000.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; - 2 170.006 -8.791 1000.0 -1000.0 0.92617 100.0 1 1500.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; - 3 0.0 -4.843 1000.0 -1000.0 0.9 100.0 1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 1 158.066931397567 28.7880705116472 1000.0 -1000.0 1.1 100.0 1 2000.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 2 160.006267696445 -4.62694670645669 1000.0 -1000.0 0.92617 100.0 1 1500.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 3 0.0 -4.84256468513695 1000.0 -1000.0 0.9 100.0 1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; ]; mpc.gencost = [ @@ -29,7 +29,7 @@ ]; mpc.dcline = [ - 1 2 1 0 0 0 0 1 1 0 0 -1000 1000 -1000 1000 0 0 0 0 0 0 0 0 + 1 2 1 10 10 25.9092634604825 -4.16425203581105 1.1 0.92617 10 900 -900 900 -900 900 0 0 0 0 0 0 0 0 ] % matpower data format extentions @@ -67,7 +67,7 @@ % adding extra cell values mpc.areas_cells = { - 'Area 1' 123 987 'Slack \'Bus\' 1' 1.23 ; + 'Area 1' 123 987 'Slack Bus 1' 1.23 ; 'Area 2' 456 987 'Slack Bus 3' 4.56 ; }; diff --git a/test/data/case5_dc.m b/test/data/case5_dc.m index f2769b6e8..5237bb72a 100644 --- a/test/data/case5_dc.m +++ b/test/data/case5_dc.m @@ -12,11 +12,11 @@ %% bus data % bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin mpc.bus = [ - 1 2 0.0 0.0 0.0 0.0 1 1.07762 2.80377 230.0 1 1.10000 0.90000; - 2 1 300.0 98.61 0.0 0.0 1 1.08407 -0.73465 230.0 1 1.10000 0.90000; - 3 2 300.0 98.61 0.0 0.0 1 1.10000 -0.55972 230.0 1 1.10000 0.90000; - 4 3 400.0 131.47 0.0 0.0 1 1.06414 0.00000 230.0 1 1.10000 0.90000; - 5 2 0.0 0.0 0.0 0.0 1 1.06907 3.59033 230.0 1 1.10000 0.90000; + 1 1 0.0 0.0 0.0 0.0 1 1.06355268364716 2.87618561241116 230.0 1 1.10000 0.90000; + 2 1 300.0 98.61 0.0 0.0 1 1.08008955844464 -0.797080116316831 230.0 1 1.10000 0.90000; + 3 1 300.0 98.61 0.0 0.0 1 1.1 -0.649253101490103 230.0 1 1.10000 0.90000; + 4 3 400.0 131.47 0.0 0.0 1 1.06414 0.00000 230.0 1 1.10000 0.90000; + 5 1 0.0 0.0 0.0 0.0 1 1.05303670911989 3.70098518514844 230.0 1 1.10000 0.90000; ]; %% generator data @@ -24,9 +24,9 @@ mpc.gen = [ 1 40.0 30.0 30.0 -30.0 1.07762 100.0 1 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 1 170.0 127.5 127.5 -127.5 1.07762 100.0 1 170.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; - 3 324.498 390.0 390.0 -390.0 1.1 100.0 1 520.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; - 4 0.0 -10.802 150.0 -150.0 1.06414 100.0 1 200.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; - 5 470.694 -165.039 450.0 -450.0 1.06907 100.0 1 600.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 3 333.6866 390.0 390.0 -390.0 1.1 100.0 1 520.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 4 0.0 -70.8186 150.0 -150.0 1.06414 100.0 1 200.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; + 5 463.5555 -184.9224 450.0 -450.0 1.06907 100.0 1 600.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; ]; %% generator cost data @@ -54,7 +54,7 @@ %%----- DC Line Data ----- % fbus tbus status Pf Pt Qf Qt Vf Vt Pmin Pmax QminF QmaxF QminT QmaxT loss0 loss1 mpc.dcline = [ - 3 5 1 10 8.9 0 0 1.01 1 0 0 -100 100 -100 100 1 0.01; + 3 5 1 10 8.9 99.9934 -10.4049 1.1 1.05303670911989 10 100 -100 100 -100 100 1 0.01; ]; %% DC line cost data diff --git a/test/docs.jl b/test/docs.jl index 2c9eebf15..138c35bdc 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -31,10 +31,10 @@ #pretty print the model to the terminal #print(pm.model) - @test MathProgBase.numlinconstr(pm.model) == 8 + @test MathProgBase.numlinconstr(pm.model) == 7 @test MathProgBase.numquadconstr(pm.model) == 12 @test MathProgBase.numconstr(pm.model) - MathProgBase.numlinconstr(pm.model) - MathProgBase.numquadconstr(pm.model) == 12 - @test MathProgBase.numvar(pm.model) == 28 + @test MathProgBase.numvar(pm.model) == 24 result = solve_generic_model(pm, IpoptSolver(print_level=0)) diff --git a/test/opf.jl b/test/opf.jl index bd2406265..66a8986bc 100644 --- a/test/opf.jl +++ b/test/opf.jl @@ -7,12 +7,24 @@ @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 5812; atol = 1e0) end + @testset "3-bus case with active DC Line" begin + result = run_ac_opf("../test/data/case3_dc.m", ipopt_solver) + + @test result["status"] == :LocalOptimal + @test isapprox(result["objective"], 5906.88; atol = 1e0) + end @testset "5-bus asymmetric case" begin result = run_ac_opf("../test/data/case5_asym.m", ipopt_solver) @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 17551; atol = 1e0) end + @testset "5-bus with active DC line" begin + result = run_ac_opf("../test/data/case5_dc.m", ipopt_solver) + + @test result["status"] == :LocalOptimal + @test isapprox(result["objective"], 17756.17; atol = 1e0) + end @testset "6-bus case" begin result = run_ac_opf("../test/data/case6.m", ipopt_solver) @@ -121,7 +133,7 @@ end @testset "test sdp opf" begin @testset "3-bus case" begin - result = run_opf("../test/data/case3_dc.m", SDPWRMPowerModel, scs_solver) + result = run_opf("../test/data/case3.m", SDPWRMPowerModel, scs_solver) @test result["status"] == :Optimal @test isapprox(result["objective"], 5788.7; atol = 1e0) diff --git a/test/pf.jl b/test/pf.jl index 863a14cd7..cc28da88a 100644 --- a/test/pf.jl +++ b/test/pf.jl @@ -17,12 +17,50 @@ @test isapprox(result["solution"]["bus"]["3"]["vm"], 0.90000; atol = 1e-3) @test isapprox(result["solution"]["bus"]["3"]["va"], -17.26711; atol = 1e-3) end + @testset "3-bus case with active DC line" begin + result = run_ac_pf("../test/data/case3_dc.m", ipopt_solver, setting = Dict("output" => Dict("line_flows" => true))) + + @test result["status"] == :LocalOptimal + @test isapprox(result["objective"], 0; atol = 1e-2) + + @test isapprox(result["solution"]["gen"]["2"]["pg"], 160.0063; atol = 1e-1) + @test isapprox(result["solution"]["gen"]["3"]["pg"], 0; atol = 1e-1) + + @test isapprox(result["solution"]["bus"]["1"]["vm"], 1.10000; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["1"]["va"], 0.00000; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["2"]["vm"], 0.92617; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["3"]["vm"], 0.90000; atol = 1e-3) + + @test isapprox(result["solution"]["dcline"]["1"]["p_from"], 10; atol = 1e-3) + @test isapprox(result["solution"]["dcline"]["1"]["p_to"], -10; atol = 1e-3) + + end @testset "5-bus asymmetric case" begin result = run_pf("../test/data/case5_asym.m", ACPPowerModel, ipopt_solver) @test result["status"] == :LocalOptimal @test isapprox(result["objective"], 0; atol = 1e-2) end + @testset "5-bus case with active DC line" begin + result = run_ac_pf("../test/data/case5_dc.m", ipopt_solver, setting = Dict("output" => Dict("line_flows" => true))) + + @test result["status"] == :LocalOptimal + @test isapprox(result["objective"], 0; atol = 1e-2) + + @test isapprox(result["solution"]["gen"]["3"]["pg"], 333.6866; atol = 1e-1) + + @test isapprox(result["solution"]["bus"]["1"]["vm"], 1.0635; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["2"]["vm"], 1.0808; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["3"]["vm"], 1.1; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["4"]["vm"], 1.0641; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["4"]["va"], -0; atol = 1e-3) + @test isapprox(result["solution"]["bus"]["5"]["vm"], 1.0530; atol = 1e-3) + + + @test isapprox(result["solution"]["dcline"]["1"]["p_from"], 10; atol = 1e-3) + @test isapprox(result["solution"]["dcline"]["1"]["p_to"], -8.9; atol = 1e-3) + + end @testset "6-bus case" begin result = run_pf("../test/data/case6.m", ACPPowerModel, ipopt_solver) @@ -112,9 +150,3 @@ end @test isapprox(result["objective"], 0; atol = 1e-2) end end - - - - - - From 9dd4c3cba23456096940f26af5d48a9c187e2dc3 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Wed, 26 Jul 2017 17:53:17 +0200 Subject: [PATCH 15/23] Case 3 fix the case3_dc.m is already updated --- test/data/case3.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/case3.m b/test/data/case3.m index e700da8f0..afcb50466 100644 --- a/test/data/case3.m +++ b/test/data/case3.m @@ -67,7 +67,7 @@ % adding extra cell values mpc.areas_cells = { - 'Area 1' 123 987 'Slack \'Bus\' 1' 1.23 ; + 'Area 1' 123 987 'Slack Bus 1' 1.23 ; 'Area 2' 456 987 'Slack Bus 3' 4.56 ; }; From 589023b81e6699fe744e854085a948be156d9e98 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Thu, 27 Jul 2017 09:42:05 +0200 Subject: [PATCH 16/23] Data warnings about dc lines - documentation on dc line output signs w.r.t. matpower - checks on loss0, loss1 --- docs/src/network-data.md | 2 ++ src/core/data.jl | 40 ++++++++++++++++++++++++++++++++++++++++ src/io/common.jl | 1 + 3 files changed, 43 insertions(+) diff --git a/docs/src/network-data.md b/docs/src/network-data.md index 2ca8fb213..bfe15efc4 100644 --- a/docs/src/network-data.md +++ b/docs/src/network-data.md @@ -78,6 +78,8 @@ The data exchange via JSON files is ideal for building algorithms, however it is In addition to parsing the standard Matpower parameters, PowerModels also supports extending the standard Matpower format in a number of ways as illustrated by the following examples. In these examples JSON document fragments are used to indicate the structure of the PowerModel dictionary. +Note that for DC lines, the flow results are returned using the same convention as for the AC lines, i.e. positive values for p_from/q_from and p_to/q_to indicating power flow from the 'to' node or 'from' node into the line. This means that w.r.t matpower the sign is identical for p_from, but opposite for q_from/p_to/q_to. + ### Single Values Single values are added to the root of the dictionary as follows, diff --git a/src/core/data.jl b/src/core/data.jl index fbc9358fc..796cea7a2 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -392,3 +392,43 @@ function check_bus_types(data) end end + + +"checks that flow bounds for dc lines are reasonable" +function check_dc_line_limits(data) + assert("per_unit" in keys(data) && data["per_unit"]) + mva_base = data["baseMVA"] + + for (i, dcline) in data["dcline"] + if dcline["loss0"] < 0.0 + new_rate = 0.0 + warn("this code only supports positive loss0 values, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + branch["loss0"] = new_rate + end + + if dcline["loss0"] >= dcline["pmaxf"]*(1-dcline["loss1"] )+ dcline["pmaxt"] + new_rate = 0.0 + warn("this code only supports loss0 values which are consistent with the line flow bounds, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + branch["loss0"] = new_rate + end + + if dcline["loss1"] < 0.0 + new_rate = 0.0 + warn("this code only supports positive loss1 values, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss1"]) to $(mva_base*new_rate)") + branch["loss1"] = new_rate + end + + if dcline["loss1"] >= 1.0 + new_rate = 0.0 + warn("this code only supports loss1 values < 1, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss1"]) to $(mva_base*new_rate)") + branch["loss1"] = new_rate + end + + if dcline["pmint"] <0.0 && dcline["loss1"] > 0.0 + #new_rate = 0.0 + warn("the dc line model is not meant to be used bi-directionally when loss0 > 0, be careful interpreting the results as the dc line losses can now be negative") + #branch["loss0"] = new_rate + end + + end +end diff --git a/src/io/common.jl b/src/io/common.jl index c111c9a81..5a33f1f76 100644 --- a/src/io/common.jl +++ b/src/io/common.jl @@ -18,4 +18,5 @@ function check_network_data(data::Dict{String,Any}) check_phase_angle_differences(data) check_thermal_limits(data) check_bus_types(data) + check_dc_line_limits(data) end From dc4fce07bd5e57381614e5a772146adbbac38992 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Thu, 27 Jul 2017 11:32:20 +0200 Subject: [PATCH 17/23] Consistent formulation of DC line bounds - Avoiding infinite bounds on pmin and pmax for DC lines - Avoiding negative losses, by checking input data, overwriting bad values and throwing warnings --- src/core/data.jl | 40 ++++++++++++++++++++++++++++++++++++++++ src/io/matpower.jl | 36 +++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/core/data.jl b/src/core/data.jl index fbc9358fc..1fbcb05ad 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -392,3 +392,43 @@ function check_bus_types(data) end end + + +"checks that flow bounds for dc lines are reasonable" +function check_dc_line_limits(data) + assert("per_unit" in keys(data) && data["per_unit"]) + mva_base = data["baseMVA"] + + for (i, dcline) in data["dcline"] + if dcline["loss0"] < 0.0 + new_rate = 0.0 + warn("this code only supports positive loss0 values, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + dcline["loss0"] = new_rate + end + + if dcline["loss0"] >= dcline["pmaxf"]*(1-dcline["loss1"] )+ dcline["pmaxt"] + new_rate = 0.0 + warn("this code only supports loss0 values which are consistent with the line flow bounds, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + dcline["loss0"] = new_rate + end + + if dcline["loss1"] < 0.0 + new_rate = 0.0 + warn("this code only supports positive loss1 values, changing the value on dcline $(dcline["index"]) from $(dcline["loss1"]) to $(new_rate)") + dcline["loss1"] = new_rate + end + + if dcline["loss1"] >= 1.0 + new_rate = 0.0 + warn("this code only supports loss1 values < 1, changing the value on dcline $(dcline["index"]) from $(dcline["loss1"]) to $(new_rate)") + dcline["loss1"] = new_rate + end + + if dcline["pmint"] <0.0 && dcline["loss1"] > 0.0 + #new_rate = 0.0 + warn("the dc line model is not meant to be used bi-directionally when loss1 > 0, be careful interpreting the results as the dc line losses can now be negative") + #branch["loss0"] = new_rate + end + + end +end diff --git a/src/io/matpower.jl b/src/io/matpower.jl index 6798e3436..e9c30e840 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -497,22 +497,32 @@ function parse_matpower_data(data_string::String) for (i, dcline_row) in enumerate(parsed_matrix["data"]) pmin = parse(Float64, dcline_row[10]) pmax = parse(Float64, dcline_row[11]) - pmaxt = Inf - pmaxf = Inf - pminf = -Inf - pmint = -Inf - - if pmin >= 0 - pminf = pmin # fg(k, PMAX) = -dc(k, c.PMIN); + loss0 = parse(Float64, dcline_row[16]) + loss1 = parse(Float64, dcline_row[17]) + + if pmin >= 0 && pmax >=0 + pminf = pmin + pmaxf = pmax + pmint = loss0 - pmaxf * (1 - loss1) + pmaxt = loss0 - pminf * (1 - loss1) end - if pmax >= 0 - pmaxf = pmax # fg(k, PMIN) = -dc(k, c.PMAX); + if pmin >= 0 && pmax < 0 + pminf = pmin + pmint = pmax + pmaxf = (-pmint + loss0) / (1-loss1) + pmaxt = loss0 - pminf * (1 - loss1) end - if pmin <0 - pmaxt = -pmin # tg(k, PMIN) = dc(k, c.PMIN); + if pmin < 0 && pmax >= 0 + pmaxt = -pmin + pmaxf = pmax + pminf = (-pmaxt + loss0) / (1-loss1) + pmint = loss0 - pmaxf * (1 - loss1) end - if pmax < 0 - pmint = pmax # tg(k, PMAX) = dc(k, c.PMAX); + if pmin < 0 && pmax < 0 + pmaxt = -pmin + pmint = pmax + pmaxf = (-pmint + loss0) / (1-loss1) + pminf = (-pmaxt + loss0) / (1-loss1) end dcline_data = Dict{String,Any}( From acd972944342d7ce54cdc400185f8eb6f671211d Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Thu, 27 Jul 2017 13:06:05 +0200 Subject: [PATCH 18/23] Update of documentation - problem definitions - dcline result convention --- docs/src/network-data.md | 2 +- docs/src/specifications.md | 24 +++++++++++++++++++++--- src/prob/pf.jl | 4 ++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/src/network-data.md b/docs/src/network-data.md index bfe15efc4..2102a01b8 100644 --- a/docs/src/network-data.md +++ b/docs/src/network-data.md @@ -78,7 +78,7 @@ The data exchange via JSON files is ideal for building algorithms, however it is In addition to parsing the standard Matpower parameters, PowerModels also supports extending the standard Matpower format in a number of ways as illustrated by the following examples. In these examples JSON document fragments are used to indicate the structure of the PowerModel dictionary. -Note that for DC lines, the flow results are returned using the same convention as for the AC lines, i.e. positive values for p_from/q_from and p_to/q_to indicating power flow from the 'to' node or 'from' node into the line. This means that w.r.t matpower the sign is identical for p_from, but opposite for q_from/p_to/q_to. +Note that for DC lines, the flow results are returned using the same convention as for the AC lines, i.e. positive values for `p_from`/`q_from `and `p_to`/`q_to` indicating power flow from the 'to' node or 'from' node into the line. This means that w.r.t matpower the sign is identical for `p_from`, but opposite for `q_from`/`p_to`/`q_to`. ### Single Values Single values are added to the root of the dictionary as follows, diff --git a/docs/src/specifications.md b/docs/src/specifications.md index d250b9334..953ad25f8 100644 --- a/docs/src/specifications.md +++ b/docs/src/specifications.md @@ -13,6 +13,7 @@ variable_voltage(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) +variable_line_flow_dc(pm) ``` ### Constraints @@ -31,6 +32,9 @@ for (i,branch) in pm.ref[:branch] constraint_thermal_limit_from(pm, branch) constraint_thermal_limit_to(pm, branch) end +for (i,dcline) in pm.ref[:dcline] + constraint_dc_line(pm, dcline) +end ``` ## Optimal Transmission Switching (OTS) @@ -48,6 +52,7 @@ variable_voltage_on_off(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) +variable_line_flow_dc(pm) ``` ### Objective @@ -73,6 +78,9 @@ for (i,branch) in pm.ref[:branch] constraint_thermal_limit_from_on_off(pm, branch) constraint_thermal_limit_to_on_off(pm, branch) end +for (i,dcline) in pm.ref[:dcline] + constraint_dc_line(pm, dcline) +end ``` ## Power Flow (PF) @@ -85,6 +93,7 @@ variable_voltage(pm, bounded = false) variable_active_generation(pm, bounded = false) variable_reactive_generation(pm, bounded = false) variable_line_flow(pm, bounded = false) +variable_line_flow_dc(pm, bounded = false) ``` ### Constraints @@ -93,6 +102,7 @@ constraint_theta_ref(pm) constraint_voltage_magnitude_setpoint(pm, pm.ref[:bus][pm.ref[:ref_bus]]) constraint_voltage(pm) + for (i,bus) in pm.ref[:bus] constraint_kcl_shunt(pm, bus) @@ -113,6 +123,10 @@ for (i,branch) in pm.ref[:branch] constraint_ohms_yt_from(pm, branch) constraint_ohms_yt_to(pm, branch) end +for (i,dcline) in pm.ref[:dcline] + constraint_active_dc_line_setpoint(pm, dcline) + constraint_dc_line_voltage(pm, dcline; epsilon = 0.00001) +end ``` ## Transmission Network Expansion Planning (TNEP) @@ -124,12 +138,13 @@ objective_tnep_cost(pm) ### Variables ```julia -variable_line_ne(pm) +variable_line_ne(pm) variable_voltage(pm) variable_voltage_ne(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) +variable_line_flow_dc(pm) variable_line_flow_ne(pm) ``` @@ -151,15 +166,18 @@ for (i,branch) in pm.ref[:branch] constraint_thermal_limit_from(pm, branch) constraint_thermal_limit_to(pm, branch) -end +end for (i,branch) in pm.ref[:ne_branch] constraint_ohms_yt_from_ne(pm, branch) - constraint_ohms_yt_to_ne(pm, branch) + constraint_ohms_yt_to_ne(pm, branch) constraint_phase_angle_difference_ne(pm, branch) constraint_thermal_limit_from_ne(pm, branch) constraint_thermal_limit_to_ne(pm, branch) end +for (i,dcline) in pm.ref[:dcline] + constraint_dc_line(pm, dcline) +end ``` diff --git a/src/prob/pf.jl b/src/prob/pf.jl index e5ff0e1c1..289880913 100644 --- a/src/prob/pf.jl +++ b/src/prob/pf.jl @@ -51,8 +51,8 @@ function post_pf(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - #constraint_dc_line(pm, dcline) - constraint_active_dc_line_setpoint(pm, dcline; epsilon = 0.0) + #constraint_dc_line(pm, dcline) not needed, active power flow fully defined by dc line setpoints + constraint_active_dc_line_setpoint(pm, dcline) constraint_dc_line_voltage(pm, dcline; epsilon = 0.00001) end end From 8d24a9553797715f399b866d50762f93b9142372 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Thu, 27 Jul 2017 13:11:35 +0200 Subject: [PATCH 19/23] update of dc line warnings --- src/core/data.jl | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/core/data.jl b/src/core/data.jl index 1fbcb05ad..96017ca0c 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -393,24 +393,23 @@ function check_bus_types(data) end - -"checks that flow bounds for dc lines are reasonable" +"checks that parameters for dc lines are reasonable" function check_dc_line_limits(data) assert("per_unit" in keys(data) && data["per_unit"]) mva_base = data["baseMVA"] for (i, dcline) in data["dcline"] - if dcline["loss0"] < 0.0 - new_rate = 0.0 - warn("this code only supports positive loss0 values, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") - dcline["loss0"] = new_rate - end - - if dcline["loss0"] >= dcline["pmaxf"]*(1-dcline["loss1"] )+ dcline["pmaxt"] - new_rate = 0.0 - warn("this code only supports loss0 values which are consistent with the line flow bounds, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") - dcline["loss0"] = new_rate - end + if dcline["loss0"] < 0.0 + new_rate = 0.0 + warn("this code only supports positive loss0 values, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + dcline["loss0"] = new_rate + end + + if dcline["loss0"] >= dcline["pmaxf"]*(1-dcline["loss1"] )+ dcline["pmaxt"] + new_rate = 0.0 + warn("this code only supports loss0 values which are consistent with the line flow bounds, changing the value on dcline $(dcline["index"]) from $(mva_base*dcline["loss0"]) to $(mva_base*new_rate)") + dcline["loss0"] = new_rate + end if dcline["loss1"] < 0.0 new_rate = 0.0 @@ -426,9 +425,8 @@ function check_dc_line_limits(data) if dcline["pmint"] <0.0 && dcline["loss1"] > 0.0 #new_rate = 0.0 - warn("the dc line model is not meant to be used bi-directionally when loss1 > 0, be careful interpreting the results as the dc line losses can now be negative") - #branch["loss0"] = new_rate + warn("the dc line model is not meant to be used bi-directionally when loss1 > 0, be careful interpreting the results as the dc line losses can now be negative. change loss1 to 0 to avoid this warning") + #dcline["loss0"] = new_rate end - end end From 49007142d489baaba449b586413df141f704f7da Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Thu, 27 Jul 2017 13:23:50 +0200 Subject: [PATCH 20/23] Escape chars in case3.m Adapted test of parsing string with escape chars --- test/data/case3.m | 2 +- test/matpower.jl | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/data/case3.m b/test/data/case3.m index afcb50466..181628557 100644 --- a/test/data/case3.m +++ b/test/data/case3.m @@ -67,7 +67,7 @@ % adding extra cell values mpc.areas_cells = { - 'Area 1' 123 987 'Slack Bus 1' 1.23 ; + 'Area 1' 123 987 'Slack \"Bus\" 1' 1.23 ; 'Area 2' 456 987 'Slack Bus 3' 4.56 ; }; diff --git a/test/matpower.jl b/test/matpower.jl index c9d7cdc7f..6e62fbd2c 100644 --- a/test/matpower.jl +++ b/test/matpower.jl @@ -108,7 +108,7 @@ end @test haskey(data, "areas_cells") @test data["areas_cells"]["1"]["col_1"] == "Area 1" @test data["areas_cells"]["1"]["col_2"] == 123 - @test data["areas_cells"]["1"]["col_4"] == "Slack 'Bus' 1" + @test data["areas_cells"]["1"]["col_4"] == "Slack \\\"Bus\\\" 1" @test data["areas_cells"]["1"]["col_5"] == 1.23 @test data["areas_cells"]["2"]["col_1"] == "Area 2" @test data["areas_cells"]["2"]["col_2"] == 456 @@ -159,10 +159,9 @@ end @testset "`build_ref` for 3-bus tnep case" begin data = PowerModels.parse_file("../test/data/case3_tnep.m") ref = PowerModels.build_ref(data) - + @test haskey(data, "name") @test haskey(ref, :name) @test data["name"] == ref[:name] end end - From f3c367781027a7fa5ad688b4f5c7572bec431211 Mon Sep 17 00:00:00 2001 From: hakanergun Date: Fri, 28 Jul 2017 10:33:17 +0200 Subject: [PATCH 21/23] Suggested changes by Carleton - Consistent dcline naming - DC line removed from case3 - Warning about DC line costs thrown if mpc.dclinecost is provided --- README.md | 5 +++-- src/core/constraint.jl | 2 +- src/core/constraint_template.jl | 14 +++++++------- src/core/data.jl | 2 +- src/core/solution.jl | 4 ++-- src/core/variable.jl | 11 +++++------ src/form/acp.jl | 14 ++++++++------ src/form/dcp.jl | 4 ++-- src/form/wr.jl | 13 +++++++++---- src/form/wrm.jl | 2 +- src/io/common.jl | 2 +- src/io/matpower.jl | 9 +++------ src/prob/misc.jl | 8 ++++---- src/prob/opf.jl | 4 ++-- src/prob/ots.jl | 4 ++-- src/prob/pf.jl | 8 ++++---- src/prob/tnep.jl | 4 ++-- test/data/case3.m | 4 ---- 18 files changed, 57 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index af078b58b..92145c3a5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# PowerModels.jl +# PowerModels.jl -Release: [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.4.svg)](http://pkg.julialang.org/?pkg=PowerModels), [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.5.svg)](http://pkg.julialang.org/?pkg=PowerModels), [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.6.svg)](http://pkg.julialang.org/?pkg=PowerModels), +Release: [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.4.svg)](http://pkg.julialang.org/?pkg=PowerModels), [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.5.svg)](http://pkg.julialang.org/?pkg=PowerModels), [![PowerModels](http://pkg.julialang.org/badges/PowerModels_0.6.svg)](http://pkg.julialang.org/?pkg=PowerModels), [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://lanl-ansi.github.io/PowerModels.jl/stable) Dev: @@ -42,6 +42,7 @@ The primary developer is Carleton Coffrin, with significant contributions from R Special thanks to Miles Lubin for his assistance in integrating with Julia/JuMP. +Frederik Geth and Hakan Ergun (both KU Leuven) contributed to the Matpower-compatible DC Line formulation. ## License diff --git a/src/core/constraint.jl b/src/core/constraint.jl index 52cd2c363..6d70d6eba 100644 --- a/src/core/constraint.jl +++ b/src/core/constraint.jl @@ -90,7 +90,7 @@ function constraint_reactive_gen_setpoint(pm::GenericPowerModel, i, qg) end "`pf[i] == pf, pt[i] == pt`" -function constraint_active_dc_line_setpoint(pm::GenericPowerModel, i, f_idx, t_idx, pf, pt, epsilon) +function constraint_active_dcline_setpoint(pm::GenericPowerModel, i, f_idx, t_idx, pf, pt, epsilon) p_fr = getindex(pm.model, :p_dc)[f_idx] p_to = getindex(pm.model, :p_dc)[t_idx] diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 6770b6b68..5d56fc16e 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -86,7 +86,7 @@ end ### Branch - Loss Constraints DC LINES### "" -function constraint_dc_line(pm::GenericPowerModel, dcline) +function constraint_dcline(pm::GenericPowerModel, dcline) i = dcline["index"] f_bus = dcline["f_bus"] t_bus = dcline["t_bus"] @@ -95,7 +95,7 @@ function constraint_dc_line(pm::GenericPowerModel, dcline) loss0 = dcline["loss0"] loss1 = dcline["loss1"] - return constraint_dc_line(pm, f_bus, t_bus, f_idx, t_idx, loss0, loss1) + return constraint_dcline(pm, f_bus, t_bus, f_idx, t_idx, loss0, loss1) end """ @@ -105,7 +105,7 @@ Creates Line Flow constraint for DC Lines (Matpower Formulation) p_fr + p_to == loss0 + p_fr * loss1 ``` """ -function constraint_dc_line{T}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, loss0, loss1) +function constraint_dcline{T}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_idx, loss0, loss1) p_fr = getindex(pm.model, :p_dc)[f_idx] p_to = getindex(pm.model, :p_dc)[t_idx] @@ -114,7 +114,7 @@ function constraint_dc_line{T}(pm::GenericPowerModel{T}, f_bus, t_bus, f_idx, t_ end "" -function constraint_dc_line_voltage(pm::GenericPowerModel, dcline; epsilon = 0.0) +function constraint_dcline_voltage(pm::GenericPowerModel, dcline; epsilon = 0.0) @assert epsilon >= 0.0 i = dcline["index"] f_bus = dcline["f_bus"] @@ -122,10 +122,10 @@ function constraint_dc_line_voltage(pm::GenericPowerModel, dcline; epsilon = 0.0 vf = dcline["vf"] vt = dcline["vt"] - return constraint_dc_line_voltage(pm, f_bus, t_bus, vf, vt, epsilon) + return constraint_dcline_voltage(pm, f_bus, t_bus, vf, vt, epsilon) end -function constraint_active_dc_line_setpoint(pm::GenericPowerModel, dcline; epsilon = 0.0) +function constraint_active_dcline_setpoint(pm::GenericPowerModel, dcline; epsilon = 0.0) i = dcline["index"] f_bus = dcline["f_bus"] t_bus = dcline["t_bus"] @@ -133,7 +133,7 @@ function constraint_active_dc_line_setpoint(pm::GenericPowerModel, dcline; epsil t_idx = (i, t_bus, f_bus) pf = dcline["pf"] pt = dcline["pt"] - return constraint_active_dc_line_setpoint(pm, i, f_idx, t_idx, pf, pt, epsilon) + return constraint_active_dcline_setpoint(pm, i, f_idx, t_idx, pf, pt, epsilon) end "" diff --git a/src/core/data.jl b/src/core/data.jl index 96017ca0c..6c40e9344 100644 --- a/src/core/data.jl +++ b/src/core/data.jl @@ -394,7 +394,7 @@ function check_bus_types(data) end "checks that parameters for dc lines are reasonable" -function check_dc_line_limits(data) +function check_dcline_limits(data) assert("per_unit" in keys(data) && data["per_unit"]) mva_base = data["baseMVA"] diff --git a/src/core/solution.jl b/src/core/solution.jl index 0aca56f80..87cb2fab5 100644 --- a/src/core/solution.jl +++ b/src/core/solution.jl @@ -44,7 +44,7 @@ function get_solution(pm::GenericPowerModel) add_bus_voltage_setpoint(sol, pm) add_generator_power_setpoint(sol, pm) add_branch_flow_setpoint(sol, pm) - add_dc_line_flow_setpoint(sol, pm) + add_dcline_flow_setpoint(sol, pm) return sol end @@ -82,7 +82,7 @@ function add_branch_flow_setpoint(sol, pm::GenericPowerModel) end "" -function add_dc_line_flow_setpoint(sol, pm::GenericPowerModel) +function add_dcline_flow_setpoint(sol, pm::GenericPowerModel) # check the line flows were requested if haskey(pm.setting, "output") && haskey(pm.setting["output"], "line_flows") && pm.setting["output"]["line_flows"] == true mva_base = pm.data["baseMVA"] diff --git a/src/core/variable.jl b/src/core/variable.jl index f7951d97a..8d7a2da96 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -128,14 +128,13 @@ function variable_reactive_line_flow(pm::GenericPowerModel; bounded = true) return q end -############## DC Lines ############################################ -function variable_line_flow_dc(pm::GenericPowerModel; kwargs...) - variable_active_line_flow_dc(pm; kwargs...) - variable_reactive_line_flow_dc(pm; kwargs...) +function variable_dcline_flow(pm::GenericPowerModel; kwargs...) + variable_active_dcline_flow(pm; kwargs...) + variable_reactive_dcline_flow(pm; kwargs...) end "variable: `p_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" -function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) +function variable_active_dcline_flow(pm::GenericPowerModel; bounded = true) pmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) pref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) pmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) @@ -159,7 +158,7 @@ function variable_active_line_flow_dc(pm::GenericPowerModel; bounded = true) end "variable: `q_dc[l,i,j]` for `(l,i,j)` in `arcs_dc`" -function variable_reactive_line_flow_dc(pm::GenericPowerModel; bounded = true) +function variable_reactive_dcline_flow(pm::GenericPowerModel; bounded = true) qmin = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) qref = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) qmax = Dict([(a, 0.0) for a in pm.ref[:arcs_dc]]) diff --git a/src/form/acp.jl b/src/form/acp.jl index 4211d47c9..60e8d46b9 100644 --- a/src/form/acp.jl +++ b/src/form/acp.jl @@ -55,7 +55,7 @@ v_from - epsilon <= v[i] <= v_from + epsilon v_to - epsilon <= v[i] <= v_to + epsilon ''' """ -function constraint_dc_line_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) +function constraint_dcline_voltage{T <: AbstractACPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) v_f = getindex(pm.model, :v)[f_bus] v_t = getindex(pm.model, :v)[t_bus] @@ -94,11 +94,11 @@ end """ ``` -sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 -sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 +sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2 +sum(q[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2 ``` """ -function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_ne, bus_gens, pd, qd, gs, bs) +function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) v = getindex(pm.model, :v)[i] p = getindex(pm.model, :p) q = getindex(pm.model, :q) @@ -106,9 +106,11 @@ function constraint_kcl_shunt_ne{T <: AbstractACPForm}(pm::GenericPowerModel{T}, q_ne = getindex(pm.model, :q_ne) pg = getindex(pm.model, :pg) qg = getindex(pm.model, :qg) + p_dc = getindex(pm.model, :p_dc) + q_dc = getindex(pm.model, :q_dc) - c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) - c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) + c1 = @constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*v^2) + c2 = @constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*v^2) return Set([c1, c2]) end diff --git a/src/form/dcp.jl b/src/form/dcp.jl index f621d5ce0..035da5cc4 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -81,7 +81,7 @@ constraint_voltage_magnitude_setpoint{T <: AbstractDCPForm}(pm::GenericPowerMode constraint_reactive_gen_setpoint{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, qg) = Set() "do nothing, this model does not have voltage variables" -constraint_dc_line_voltage{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() +constraint_dcline_voltage{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() "" function constraint_kcl_shunt{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) @@ -100,7 +100,7 @@ function constraint_kcl_shunt_ne{T <: AbstractDCPForm}(pm::GenericPowerModel{T}, p_expr = pm.model.ext[:p_expr] p_ne_expr = pm.model.ext[:p_ne_expr] - c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) + sum(p_ne_expr[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc)== sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) + c = @constraint(pm.model, sum(p_expr[a] for a in bus_arcs) + sum(p_ne_expr[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*1.0^2) return Set([c]) end diff --git a/src/form/wr.jl b/src/form/wr.jl index e27d19121..cd735709a 100644 --- a/src/form/wr.jl +++ b/src/form/wr.jl @@ -81,7 +81,7 @@ for DC line voltage: (v_to - epsilon)^2 <= w[i] <= (v_to + epsilon)^2 ''' """ -function constraint_dc_line_voltage{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) +function constraint_dcline_voltage{T <: AbstractWRForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) w_f = getindex(pm.model, :w)[f_bus] w_t = getindex(pm.model, :w)[t_bus] if epsilon == 0.0 @@ -97,7 +97,12 @@ function constraint_dc_line_voltage{T <: AbstractWRForm}(pm::GenericPowerModel{T end end -"" +""" +``` +sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w[i] +sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w[i] +``` +""" function constraint_kcl_shunt{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_gens, pd, qd, gs, bs) w = getindex(pm.model, :w)[i] p = getindex(pm.model, :p) @@ -114,8 +119,8 @@ end """ ``` -sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) == sum(pg[g] for g in bus_gens) - pd - gs*w[i] -sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) == sum(qg[g] for g in bus_gens) - qd + bs*w[i] +sum(p[a] for a in bus_arcs) + sum(p_ne[a] for a in bus_arcs_ne) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - pd - gs*w[i] +sum(q[a] for a in bus_arcs) + sum(q_ne[a] for a in bus_arcs_ne) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - qd + bs*w[i] ``` """ function constraint_kcl_shunt_ne{T <: AbstractWRForm}(pm::GenericPowerModel{T}, i, bus_arcs, bus_arcs_dc, bus_arcs_ne, bus_gens, pd, qd, gs, bs) diff --git a/src/form/wrm.jl b/src/form/wrm.jl index 8a7759455..a1680d7b0 100644 --- a/src/form/wrm.jl +++ b/src/form/wrm.jl @@ -160,4 +160,4 @@ function add_bus_voltage_setpoint{T <: AbstractWRMForm}(sol, pm::GenericPowerMod end "DC Line voltage constraint not supported" -constraint_dc_line_voltage{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() +constraint_dcline_voltage{T <: AbstractWRMForm}(pm::GenericPowerModel{T}, f_bus, t_bus, vf, vt, epsilon) = Set() diff --git a/src/io/common.jl b/src/io/common.jl index 5a33f1f76..d7f265f16 100644 --- a/src/io/common.jl +++ b/src/io/common.jl @@ -18,5 +18,5 @@ function check_network_data(data::Dict{String,Any}) check_phase_angle_differences(data) check_thermal_limits(data) check_bus_types(data) - check_dc_line_limits(data) + check_dcline_limits(data) end diff --git a/src/io/matpower.jl b/src/io/matpower.jl index e9c30e840..638e66937 100644 --- a/src/io/matpower.jl +++ b/src/io/matpower.jl @@ -492,8 +492,6 @@ function parse_matpower_data(data_string::String) elseif parsed_matrix["name"] == "dcline" dclines = [] - warn("DC Line costs are not considered") - for (i, dcline_row) in enumerate(parsed_matrix["data"]) pmin = parse(Float64, dcline_row[10]) pmax = parse(Float64, dcline_row[11]) @@ -555,13 +553,12 @@ function parse_matpower_data(data_string::String) dcline_data["mu_qmint"] = parse(Float64, dcline_row[22]) dcline_data["mu_qmaxt"] = parse(Float64, dcline_row[23]) end - push!(dclines, dcline_data) end case["dcline"] = dclines - - case["dcline"] = dclines - + elseif parsed_matrix["name"] == "dclinecost" + case["dclinecost"] = [] + warn("DC Line costs are not considered") else name = parsed_matrix["name"] data = parsed_matrix["data"] diff --git a/src/prob/misc.jl b/src/prob/misc.jl index accd002d3..b304d15eb 100644 --- a/src/prob/misc.jl +++ b/src/prob/misc.jl @@ -15,7 +15,7 @@ function post_api_opf(pm::GenericPowerModel) upperbound_negative_active_generation(pm) variable_line_flow(pm) - variable_line_flow_dc(pm) + variable_dcline_flow(pm) variable_load_factor(pm) @@ -52,7 +52,7 @@ function post_api_opf(pm::GenericPowerModel) for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end end @@ -66,7 +66,7 @@ function post_sad_opf{T <: Union{AbstractACPForm, AbstractDCPForm}}(pm::GenericP variable_voltage(pm) variable_generation(pm) variable_line_flow(pm) - variable_line_flow_dc(pm, bounded = false) + variable_dcline_flow(pm, bounded = false) @variable(pm.model, theta_delta_bound >= 0.0, start = 0.523598776) @@ -98,6 +98,6 @@ function post_sad_opf{T <: Union{AbstractACPForm, AbstractDCPForm}}(pm::GenericP end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end end diff --git a/src/prob/opf.jl b/src/prob/opf.jl index f87aa3608..18c308fc9 100644 --- a/src/prob/opf.jl +++ b/src/prob/opf.jl @@ -20,7 +20,7 @@ function post_opf(pm::GenericPowerModel) variable_voltage(pm) variable_generation(pm) variable_line_flow(pm) - variable_line_flow_dc(pm) + variable_dcline_flow(pm) objective_min_fuel_cost(pm) @@ -44,6 +44,6 @@ function post_opf(pm::GenericPowerModel) constraint_thermal_limit_to(pm, branch) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end end diff --git a/src/prob/ots.jl b/src/prob/ots.jl index 548b77be6..95ca82913 100644 --- a/src/prob/ots.jl +++ b/src/prob/ots.jl @@ -17,7 +17,7 @@ function post_ots(pm::GenericPowerModel) variable_voltage_on_off(pm) variable_generation(pm) variable_line_flow(pm) - variable_line_flow_dc(pm) + variable_dcline_flow(pm) objective_min_fuel_cost(pm) @@ -43,7 +43,7 @@ function post_ots(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end end diff --git a/src/prob/pf.jl b/src/prob/pf.jl index 289880913..d69f57fcc 100644 --- a/src/prob/pf.jl +++ b/src/prob/pf.jl @@ -20,7 +20,7 @@ function post_pf(pm::GenericPowerModel) variable_voltage(pm, bounded = false) variable_generation(pm, bounded = false) variable_line_flow(pm, bounded = false) - variable_line_flow_dc(pm, bounded = false) + variable_dcline_flow(pm, bounded = false) constraint_voltage(pm) @@ -51,8 +51,8 @@ function post_pf(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - #constraint_dc_line(pm, dcline) not needed, active power flow fully defined by dc line setpoints - constraint_active_dc_line_setpoint(pm, dcline) - constraint_dc_line_voltage(pm, dcline; epsilon = 0.00001) + #constraint_dcline(pm, dcline) not needed, active power flow fully defined by dc line setpoints + constraint_active_dcline_setpoint(pm, dcline) + constraint_dcline_voltage(pm, dcline; epsilon = 0.00001) end end diff --git a/src/prob/tnep.jl b/src/prob/tnep.jl index 0d47ee02e..7202179f2 100644 --- a/src/prob/tnep.jl +++ b/src/prob/tnep.jl @@ -16,7 +16,7 @@ function post_tnep(pm::GenericPowerModel) variable_voltage_ne(pm) variable_generation(pm) variable_line_flow(pm) - variable_line_flow_dc(pm) + variable_dcline_flow(pm) variable_line_flow_ne(pm) objective_tnep_cost(pm) @@ -53,7 +53,7 @@ function post_tnep(pm::GenericPowerModel) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end end diff --git a/test/data/case3.m b/test/data/case3.m index 181628557..7bb3e30c0 100644 --- a/test/data/case3.m +++ b/test/data/case3.m @@ -28,10 +28,6 @@ 1 2 0.042 0.9 0.3 9000.0 0.0 0.0 0.0 0.0 1 -30.0 30.0; ]; -mpc.dcline = [ - 1 2 0 0 0 0 0 1 1 0 inf -900 900 -900 900 0 0 0 0 0 0 0 0 -] - % matpower data format extentions % adding single values From db8892dfed7e9422ca605a28af284ba36befebd3 Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Fri, 28 Jul 2017 16:34:17 +0200 Subject: [PATCH 22/23] Updated description of keys in pm.ref --- src/core/base.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/base.jl b/src/core/base.jl index 36fbfc7b2..880a054f1 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -150,8 +150,13 @@ Some of the common keys include: * `:arcs_to` -- the set `[(i,b["t_bus"],b["f_bus"]) for (i,b) in ref[:branch]]`, * `:arcs` -- the set of arcs from both `arcs_from` and `arcs_to`, * `:bus_arcs` -- the mapping `Dict(i => [(l,i,j) for (l,i,j) in ref[:arcs]])`, -* `:buspairs` -- (see `buspair_parameters(ref[:arcs_from], ref[:branch], ref[:bus])`), and +* `:buspairs` -- (see `buspair_parameters(ref[:arcs_from], ref[:branch], ref[:bus])`), * `:bus_gens` -- the mapping `Dict(i => [gen["gen_bus"] for (i,gen) in ref[:gen]])`. +* `:arcs_from_dc` -- the set `[(i,b["f_bus"],b["t_bus"]) for (i,b) in ref[:dcline]]`, +* `:arcs_to_dc` -- the set `[(i,b["t_bus"],b["f_bus"]) for (i,b) in ref[:dcline]]`, +* `:arcs_dc` -- the set of arcs from both `arcs_from_dc` and `arcs_to_dc`, +* `:bus_arcs_dc` -- the mapping `Dict(i => [(l,i,j) for (l,i,j) in ref[:arcs_dc]])`, and +* `:buspairs_dc` -- (see `buspair_parameters(ref[:arcs_from_dc], ref[:dcline], ref[:bus])`), If `:ne_branch` exists, then the following keys are also available with similar semantics: From ec90a9af01eb2e3467b2602e94f4f4f3228c7bbd Mon Sep 17 00:00:00 2001 From: frederikgeth Date: Sat, 29 Jul 2017 12:44:40 +0200 Subject: [PATCH 23/23] Updated documentation - added dc line constraints - updated quickguide with how to inspect line flow variables and losses - specifications with renamed functions --- docs/src/constraints.md | 7 +++++++ docs/src/quickguide.md | 15 +++++++++++++++ docs/src/specifications.md | 16 ++++++++-------- src/form/acp.jl | 1 - src/form/wr.jl | 1 - 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/src/constraints.md b/docs/src/constraints.md index a2a900da0..605a527a5 100644 --- a/docs/src/constraints.md +++ b/docs/src/constraints.md @@ -84,6 +84,13 @@ constraint_phase_angle_difference_ne constraint_loss_lb ``` +## DC Line Constraints +### Network Flow Constraints + +```@docs +constraint_dcline +``` + ## Commonly Used Constraints The following methods generally assume that the model contains `p` and `q` values for branches line flows and bus flow conservation. diff --git a/docs/src/quickguide.md b/docs/src/quickguide.md index 383fb4cd2..61e8c8d67 100644 --- a/docs/src/quickguide.md +++ b/docs/src/quickguide.md @@ -73,6 +73,21 @@ run_opf(network_data, ACPPowerModel, IpoptSolver()) For additional details about the network data, see the [PowerModels Network Data Format](@ref) section. +## Inspecting AC and DC branch flow results +The flow AC and DC branch results are not written to the result by default. To inspect the flow results, pass a settings Dict +```julia +result = run_opf("nesta_case3_dc.m", ACPPowerModel, IpoptSolver(), setting = Dict("output" => Dict("line_flows" => true))) +result["solution"]["dcline"]["1"] +result["solution"]["branch"]["2"] +``` + +The losses of a AC or DC branch can be derived: +```julia +loss_ac = Dict(name => data["p_to"]+data["p_from"] for (name, data) in result["solution"]["branch"]) +loss_dc = Dict(name => data["p_to"]+data["p_from"] for (name, data) in result["solution"]["dcline"]) +``` + + ## Inspecting the Formulation The following example demonstrates how to break a `run_opf` call into seperate model building and solving steps. This allows inspection of the JuMP model created by PowerModels for the AC-OPF problem, diff --git a/docs/src/specifications.md b/docs/src/specifications.md index 953ad25f8..eed4c8209 100644 --- a/docs/src/specifications.md +++ b/docs/src/specifications.md @@ -13,7 +13,7 @@ variable_voltage(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) -variable_line_flow_dc(pm) +variable_dcline_flow(pm) ``` ### Constraints @@ -33,7 +33,7 @@ for (i,branch) in pm.ref[:branch] constraint_thermal_limit_to(pm, branch) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end ``` @@ -52,7 +52,7 @@ variable_voltage_on_off(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) -variable_line_flow_dc(pm) +variable_dcline_flow(pm) ``` ### Objective @@ -79,7 +79,7 @@ for (i,branch) in pm.ref[:branch] constraint_thermal_limit_to_on_off(pm, branch) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end ``` @@ -93,7 +93,7 @@ variable_voltage(pm, bounded = false) variable_active_generation(pm, bounded = false) variable_reactive_generation(pm, bounded = false) variable_line_flow(pm, bounded = false) -variable_line_flow_dc(pm, bounded = false) +variable_dcline_flow(pm, bounded = false) ``` ### Constraints @@ -125,7 +125,7 @@ for (i,branch) in pm.ref[:branch] end for (i,dcline) in pm.ref[:dcline] constraint_active_dc_line_setpoint(pm, dcline) - constraint_dc_line_voltage(pm, dcline; epsilon = 0.00001) + constraint_dcline_voltage(pm, dcline; epsilon = 0.00001) end ``` @@ -144,7 +144,7 @@ variable_voltage_ne(pm) variable_active_generation(pm) variable_reactive_generation(pm) variable_line_flow(pm) -variable_line_flow_dc(pm) +variable_dcline_flow(pm) variable_line_flow_ne(pm) ``` @@ -178,6 +178,6 @@ for (i,branch) in pm.ref[:ne_branch] constraint_thermal_limit_to_ne(pm, branch) end for (i,dcline) in pm.ref[:dcline] - constraint_dc_line(pm, dcline) + constraint_dcline(pm, dcline) end ``` diff --git a/src/form/acp.jl b/src/form/acp.jl index 60e8d46b9..a70ce2529 100644 --- a/src/form/acp.jl +++ b/src/form/acp.jl @@ -49,7 +49,6 @@ function constraint_voltage_magnitude_setpoint{T <: AbstractACPForm}(pm::Generic end """ -for DC line power flow: ''' v_from - epsilon <= v[i] <= v_from + epsilon v_to - epsilon <= v[i] <= v_to + epsilon diff --git a/src/form/wr.jl b/src/form/wr.jl index cd735709a..48dd4f985 100644 --- a/src/form/wr.jl +++ b/src/form/wr.jl @@ -75,7 +75,6 @@ function constraint_voltage_magnitude_setpoint{T <: AbstractWRForm}(pm::GenericP end """ -for DC line voltage: ''' (v_from - epsilon)^2 <= w[i] <= (v_from + epsilon)^2 (v_to - epsilon)^2 <= w[i] <= (v_to + epsilon)^2