Building Engineering Data Models with Helper Functions

In this notebook we will demonstrate an easy way to start building new distribution network models in the engineering format using new helper functions add in PowerModelsDistribution v0.9

using PowerModelsDistribution

First, we need a optimizer. In this case we will use Ipopt and initialize it with JuMP's optimizer_with_attributes, which we have exported from PowerModelsDistribution by default for the user

using LinearAlgebra: diagm
import Ipopt

ipopt_solver = optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "tol"=>1e-6)
MathOptInterface.OptimizerWithAttributes(Ipopt.Optimizer, Pair{MathOptInterface.AbstractOptimizerAttribute, Any}[MathOpt
Interface.RawParameter("print_level") => 0, MathOptInterface.RawParameter("tol") => 1.0e-6])

Initialize an empty ENGINEERING model

eng = Model()
Dict{String, Any} with 3 entries:
  "settings"   => Dict{String, Any}("sbase_default"=>1.0, "vbases_default"=>Dic…
  "per_unit"   => false
  "data_model" => ENGINEERING

In this block we build a three bus network, with neutrals grounded at the source and loads.

We start with buses, with the sourcebus and loadbus having 4 terminals, with the last terminal grounded.

Then we add a generation source, in this case a voltage source, which is WYE configured by default, and therefore expects the last conductor to be a grounded neutral

We add two three phase lines to connect the buses sourcebus, primary, and loadbus. Note that none of the lines have a neutral conductor.

We finally add a three-phase load a the loadbus bus, but note again that this is a WYE configured load, and like the voltage source, this implies that the last conductor is a grounded neutral for the purposes of kron reduction (which is required by default until explicit 4-wire modeling is added to PowerModelsDistribution)

Lastly, we need to define the default vbase of the system at the sourcebus

add_bus!(eng, "sourcebus"; terminals=[1,2,3,4], grounded=[4])
add_bus!(eng, "primary"; terminals=[1,2,3])
add_bus!(eng, "loadbus"; terminals=[1,2,3,4], grounded=[4])

add_voltage_source!(eng, "source", "sourcebus", [1,2,3,4]; vm=[1, 1, 1])

add_linecode!(eng, "default", diagm(0=>fill(0.01, 3)), diagm(0=>fill(0.2, 3)))

add_line!(eng, "trunk", "sourcebus", "primary", [1,2,3], [1,2,3]; linecode="default")
add_line!(eng, "primary", "primary", "loadbus", [1,2,3], [1,2,3]; linecode="default")

add_load!(eng, "balanced", "loadbus", [1,2,3,4]; pd_nom=[5, 5, 5], qd_nom=[1, 1, 1])

add_vbase_default!(eng, "sourcebus", 1)

eng
Dict{String, Any} with 8 entries:
  "voltage_source" => Dict{Any, Any}("source"=>Dict{String, Any}("source_id"=>"…
  "line"           => Dict{Any, Any}("primary"=>Dict{String, Any}("length"=>1.0…
  "settings"       => Dict{String, Any}("sbase_default"=>1.0, "vbases_default"=…
  "load"           => Dict{Any, Any}("balanced"=>Dict{String, Any}("source_id"=…
  "bus"            => Dict{Any, Any}("primary"=>Dict{String, Any}("source_id"=>…
  "linecode"       => Dict{Any, Any}("default"=>Dict{String, Any}("b_fr"=>[0.0 …
  "per_unit"       => false
  "data_model"     => ENGINEERING

Running this case with OPF gives the results below

result = solve_mc_opf(eng, ACPPowerModel, ipopt_solver)
Error: BoundsError: attempt to access 3-element Vector{Int64} at index [Bool[1, 1, 1, 0]]

In the following example, we provide examples of a wider range of component types that can be added using helper functions to give a flavor of what is possible in PowerModelsDistribution v0.9

eng2 = deepcopy(eng)

add_bus!(eng2, "ttbus"; terminals=[1,2,3,4], grounded=[4])

add_transformer!(eng2, "tx1", "sourcebus", "ttbus", [1,2,3,4], [1,2,3,4])

add_bus!(eng2, "loadbus2"; terminals=[1,2,3,4], grounded=[4])

add_switch!(eng2, "breaker", "ttbus", "loadbus2", [1,2,3], [1,2,3])

add_load!(eng2, "tload", "loadbus2", [1,2,3,4]; pd_nom=[5, 5, 5], qd_nom=[1, 1, 1])

add_generator!(eng2, "secondary", "loadbus2", [1,2,3,4]; cost_pg_parameters=[0.0, 1.2, 0])

add_shunt!(eng2, "cap", "loadbus2", [1,2,3,4]; bs=diagm(0=>fill(1, 3)))

eng2
Dict{String, Any} with 12 entries:
  "bus"            => Dict{Any, Any}("primary"=>Dict{String, Any}("source_id"=>…
  "settings"       => Dict{String, Any}("sbase_default"=>1.0, "vbases_default"=…
  "generator"      => Dict{Any, Any}("secondary"=>Dict{String, Any}("source_id"…
  "switch"         => Dict{Any, Any}("breaker"=>Dict{String, Any}("source_id"=>…
  "voltage_source" => Dict{Any, Any}("source"=>Dict{String, Any}("source_id"=>"…
  "line"           => Dict{Any, Any}("primary"=>Dict{String, Any}("length"=>1.0…
  "per_unit"       => false
  "data_model"     => ENGINEERING
  "transformer"    => Dict{Any, Any}("tx1"=>Dict{String, Any}("source_id"=>"tra…
  "shunt"          => Dict{Any, Any}("cap"=>Dict{String, Any}("source_id"=>"shu…
  "load"           => Dict{Any, Any}("tload"=>Dict{String, Any}("source_id"=>"l…
  "linecode"       => Dict{Any, Any}("default"=>Dict{String, Any}("b_fr"=>[0.0 …
result2 = solve_mc_opf(eng2, ACPPowerModel, ipopt_solver)
Error: BoundsError: attempt to access 3-element Vector{Int64} at index [Bool[1, 1, 1, 0]]