diff --git a/src/form/dcp.jl b/src/form/dcp.jl index 25afb03b..44c36728 100644 --- a/src/form/dcp.jl +++ b/src/form/dcp.jl @@ -72,6 +72,25 @@ function expression_branch_power_ohms_yt_to(pm::AbstractDCPModel, n::Int, f_bus, # omit reactive constraint end +function constraint_ohms_y_oltc_pst_from(pm::AbstractDCPModel, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, g_fr, b_fr) + p_fr = var(pm, n, :p, f_idx) + va_fr = var(pm, n, :va, f_bus) + va_to = var(pm, n, :va, t_bus) + ta = var(pm, n, :ta, f_idx[1]) + + JuMP.@constraint(pm.model, p_fr == -b*(va_fr - va_to - ta)) +end + +function constraint_ohms_y_oltc_pst_to(pm::AbstractDCPModel, n::Int, f_bus, t_bus, f_idx, t_idx, g, b, g_to, b_to) + p_to = var(pm, n, :p, t_idx) + va_fr = var(pm, n, :va, f_bus) + va_to = var(pm, n, :va, t_bus) + ta = var(pm, n, :ta, f_idx[1]) + + JuMP.@constraint(pm.model, p_to == -b*(va_to - va_fr + ta)) +end + + function constraint_ne_ohms_yt_from(pm::AbstractDCPModel, n::Int, i, f_bus, t_bus, f_idx, t_idx, g, b, g_fr, b_fr, tr, ti, tm, vad_min, vad_max) p_fr = var(pm, n, :p_ne, f_idx) va_fr = var(pm, n, :va, f_bus) diff --git a/test/opf-var.jl b/test/opf-var.jl index e6ee6b86..1781d43f 100644 --- a/test/opf-var.jl +++ b/test/opf-var.jl @@ -941,4 +941,48 @@ end @test isapprox(result["solution"]["branch"]["3"]["ta"], 5.0/180*pi; atol = 1e-1) end end + + @testset "test dc polar opf" begin + @testset "3-bus case with fixed phase shift / tap" begin + file = "../test/data/matpower/case3_oltc_pst.m" + data = PowerModels.parse_file(file) + result = PowerModels.run_opf(data, DCPPowerModel, milp_solver) + + @test result["termination_status"] == OPTIMAL + @test isapprox(result["objective"], 5782.0; atol = 1e0) + end + + @testset "3-bus case with optimal phase shifting / tap changing" begin + file = "../test/data/matpower/case3_oltc_pst.m" + data = PowerModels.parse_file(file) + result = PowerModels._solve_opf_oltc_pst(data, DCPPowerModel, milp_solver) + + @test result["termination_status"] == OPTIMAL + @test isapprox(result["objective"], 5639.0; atol = 1e0) + + @test haskey(result["solution"]["branch"]["1"], "ta") + + @test isapprox(result["solution"]["branch"]["1"]["ta"], 0.000; atol = 1e-3) + @test isapprox(result["solution"]["branch"]["2"]["ta"], 0.000; atol = 1e-3) + @test isapprox(result["solution"]["branch"]["3"]["ta"], 15.0/180*pi; atol = 1e-1) + end + + + @testset "3-bus case with optimal phase shifting / tap changing with equal lb/ub" begin + file = "../test/data/matpower/case3_oltc_pst.m" + data = PowerModels.parse_file(file) + for (i, branch) in data["branch"] + branch["ta_min"] = branch["shift"] + branch["ta_max"] = branch["shift"] + end + result = PowerModels._solve_opf_oltc_pst(data, DCPPowerModel, milp_solver) + + @test result["termination_status"] == OPTIMAL + @test isapprox(result["objective"], 5698.1; atol = 1e0) + + @test isapprox(result["solution"]["branch"]["1"]["ta"], 0.000; atol = 1e-3) + @test isapprox(result["solution"]["branch"]["2"]["ta"], 0.000; atol = 1e-3) + @test isapprox(result["solution"]["branch"]["3"]["ta"], 5.0/180*pi; atol = 1e-1) + end + end end