Power Flow Computations
The typical goal of PowerModelsDistribution is to build a JuMP model that is used to solve distribution power network optimization problems. The JuMP model abstraction enables PowerModelsDistribution to have state-of-the-art performance on a wide range of problem formulations. That said, for the specific case of power flow computations, in some specific applications performance gains can be had by avoiding the JuMP model abstraction and solving the problem more directly. To that end, PowerModelsDistribution includes Julia-native solvers for AC power flow in rectangular voltage coordinates. This section provides an overview of the different power flow options that are available in PowerModelsDistribution and under what circumstances they may be beneficial.
Generic Power Flow
The general purpose power flow solver in PowerModelsDistribution is,
PowerModelsDistribution.solve_mc_pf
— FunctionPower Flow Problem
This function builds a JuMP model for a wide variety of unbalanced power flow formulations supported by PowerModelsDistribution. For example it supports,
ACPUPowerModel
- a non-convex nonlinear AC unbalanced power flow using complex voltages in polar coordinatesACRPowerModel
- a non-convex nonlinear AC unbalanced power flow using complex voltages in rectangular coordinatesACRENPowerModel
- a non-convex nonlinear AC unbalanced power flow using complex voltages in rectangular coordinates with explicit neutral conductorIVRUPowerModel
- a non-convex nonlinear AC power unbalanced flow using current voltage variables in rectangular coordinatesIVRENPowerModel
- a non-convex nonlinear AC unbalanced power flow using current voltage variables in rectangular coordinates with explicit neutral conductor
The solve_mc_pf
solution method is both formulation and solver agnostic and can leverage the wide range of solvers that are available in the JuMP ecosystem. Many of these solvers are commercial-grade, which in turn makes solve_mc_pf
the most reliable power flow solution method in PowerModelsDistribution.
Warm Starting
In some applications an initial guess of the power flow solution may be available. In such a case, this information may be able to decrease a solver's time to convergence, especially when solving systems of nonlinear equations. The _start
postfix can be used in the network data to initialize the solver's variables and provide a suitable solution guess. The most common values are as follows,
For each generator,
pg_start
- active power injection starting pointqg_start
- reactive power injection starting point
For each bus,
vm_start
- voltage magnitude starting point for theACPUPowerModel
modelva_start
- voltage angle starting point for theACPUPowerModel
modelvr_start
- real voltage starting point for theIVRUPowerModel
modelvi_start
- imaginary voltage starting point for theIVRUPowerModel
model
The following helper function can be used to use the solution point in the network data as the starting point for solve_mc_pf
.
PowerModelsDistribution.add_start_voltage!
— Functionadd_start_voltage!(
data_math::Dict{String,Any};
coordinates=:rectangular,
uniform_v_start=missing,
vr_default=0.0,
vi_default=0.0,
vm_default=0.0,
va_default=0.0,
epsilon::Number=1E-3,
)::Dict{String,Any}
Adds start values for the voltage to the buses. For a multinetwork data model, you can calculate the start voltages for a representative network through 'calcstartvoltage', and pass the result as 'uniformvstart' to use the same values for all networks and avoid recalculating it for each network. The argument 'epsilon' controls the offset added to ungrounded terminals which would otherwise be set to zero.
Warm starting a solver is a very delicate task and can easily result in degraded performance. Using PowerModelsDistribution' default flat-start values is recommended before experimenting with warm starting a solver.
Native Power Flow
The AC Unbalanced Power Flow problem is ubiquitous in power system analysis. The problem requires solving a system of nonlinear equations, usually via a Newton-Raphson type of algorithm. In PowerModelsDistribution, the standard Julia library is used for solving this system of nonlinear equations. The following function is used to solve Unbalanced Power Flow problem with voltages in rectangular coordinates.
PowerModelsDistribution.compute_mc_pf
— Functioncompute_mc_pf(
data::Dict{String,<:Any};
explicit_neutral::Bool=false,
max_iter::Int=100,
v_start::Union{Dict{<:Any,<:Any},Missing}=missing,
stat_tol::Real=1e-8,
verbose::Bool=false,
kron_reduce::Bool=true,
phase_project::Bool=false,
multinetwork::Bool=false,
global_keys::Set{String}=Set{String}(),
eng2math_extensions::Vector{<:Function}=Function[],
eng2math_passthrough::Dict{String,<:Vector{<:String}}=Dict{String,Vector{String}}(),
make_pu_extensions::Vector{<:Function}=Function[],
map_math2eng_extensions::Dict{String,<:Function}=Dict{String,Function}(),
make_si::Bool=!get(data, "per_unit", false),
make_si_extensions::Vector{<:Function}=Function[],
dimensionalize_math_extensions::Dict{String,Dict{String,Vector{String}}}=Dict{String,Dict{String,Vector{String}}}(),
)::Dict{String,Any}
Takes data in either the ENGINEERING or MATHEMATICAL model, a model type (e.g., ACRUPowerModel
), and model builder function (e.g., build_mc_opf
), and returns a solution in the original data model defined by data
.
Technical description of the native power flow can be found at https://arxiv.org/abs/2305.04405 where implementation fo the fixed-point current injection algorithm, inspired by the existing open-source implementation in OpenDSS. The current injection method is commonly conceived as a system of nonlinear equalities solved by Newton’s method. However, the fixed point iteration variant commonly outperforms most methods, while supporting meshed topologies from the ground up
If make_si
is false, data will remain in per-unit.
For an explanation of multinetwork
and global_keys
, see make_multinetwork
For an explanation of eng2math_extensions
and eng2math_passthrough
, see transform_data_model
For an explanation of make_pu_extensions
, see make_per_unit!
For an explanation of ref_extensions
, see instantiate_mc_model
For an explanation of map_math2eng_extensions
, make_si
, make_si_extensions
, and dimensionalize_math_extensions
, see solution_make_si
compute_mc_pf(
pdf::PowerFlowData,
max_iter::Int,
stat_tol::Float,
verbose::Bool
)
Computes native power flow and requires PowerFlowData (See https://arxiv.org/abs/2305.04405).
compute_mc_pf
is based on the current injection method and is inspired by OpenDSS's algorithm. compute_mc_pf
will typically provide an identical result to solve_mc_pf
. However, the existence of solution degeneracy around generator injection assignments and multiple power flow solutions can yield different results. The primary advantage of compute_mc_pf
over solve_mc_pf
is that it does not require building a JuMP model. If the initial point for the Unbalanced Power Flow solution is near-feasible then compute_mc_pf
can result in a significant runtime saving by converging quickly and reducing data-wrangling and memory allocation overheads. This initial guess is provided using the standard _start
values. The add_start_voltage!
function provides a convenient way of setting a suitable starting point.
If compute_mc_pf
fails to converge try solve_mc_pf
instead.
The table below reports the accuracy of the native power flow with respect to OpenDSS native solver tested on three IEEE testcases: | IEEE testcases | maximum voltage p.u difference with OpenDSS power flow solver | | –––––––-| ––––––––––––––––––––––––––––––- | | IEEE13 | 3.765096388188572e-6 | | IEEE34 | 6.805369850332029e-8 | | IEEE123 | 4.021326251365659e-8 |
Input arguments
compute_mc_pf
receives input arguments as follows,
data_math
- network data in MATHEMATICAL formatexplicit_neutral
- a boolean input indication wether or not the neutral is explicitly modelledv_start
- warm start if different from in-built initialization algorithmmax_iter
- maximum iterationsstat_tol
- statistical tolerance
Outputs
compute_mc_pf
provides the following outputs,
solution
- solution dictionaryiterations
- number of iterationstime_build
- time spent on building the power flow datatime_solve
- time spent on solving the native power flowtime_post
- time spent to generate solutionstime_total
- total timetermination_status
- termination status
Limitations
compute_mc_pf
has the following limitations,
- starting from the math dictionary means that transformer decomposition is already done, which is different from what OpenDSS does
- we calculate the primitive admittance matrix in p.u. whereas OpenDSS algorithm works with actual units
- no load model relaxation is performed
- inspired by OpenDSS, we add small ppm values to certain component primitive admittance values to avoid singularity issues
- inspired by OpenDSS, switch primitive admittance has specific values
Network Admittance Matrix
Internally compute_mc_pf
utilizes an admittance matrix representation of the network data, which may be useful in other contexts. The foundational type for the admittance matrix representations is SparseMatrixCSC
.
The following function can be used to compute the admittance matrix from PowerModelsDistribution network data.
PowerModelsDistribution.calc_admittance_matrix
— Functioncalc_admittance_matrix(
data_math::Dict,
v_start::Dict,
explicit_neutral::Bool
)
Calculates the admittance matrix from PowerFlowData struct.