PowerModelsGraph
The PowerModels data dictionary is useful for storing and accessing data about a grid, but a graph structure can be useful to analyse metrics like node degree or eigenvector centrality. It is used in this pacakge to create Layouts for plotting networks.
mutable struct PowerModelsGraph
graph::Graphs.SimpleDiGraph
node_comp_map::Dict{Int,Tuple{String, String}}
edge_comp_map::Dict{Tuple{Int,Int},Tuple{String, String}}
edge_connector_map::Dict{Tuple{Int,Int},Tuple{String, String}}
The PowerModelsGraph
type stores a directed graph of the network, and mapping between the nodes and edges and the components that they refer to.
The node_comp_map
is a Dictionary where the keys are the graph nodes and the values are a tuple of the component type and id, e.g.
node_comp_map = Dict(
1 => ("bus","2"),
2 => ("gen","4")
)
The edge_comp_map
is a similar mapping for components that form the edges of the network. Here, the keys are the endpoints of the directed edge.
edge_comp_map = Dict(
(1,2) => ("branch","1"),
(2,3) => ("dcline","4")
)
Connectors are additional lines that connect non-bus nodes to a bus, for example generators. The mapping is similar to the edge_comp_map
.
edge_connector_map = Dict(
(1,4) => ("gen","1"),
(1,5) => ("gen","2")
)
To create a PowerModelsGraph
, the component types for the central nodes, edges, and the connected components must be specified.
PowerModelsGraph(data::Dict{String,<:Any},
node_types::Vector{String},
edge_types::Vector{String},
connected_types::Vector{String},
)
There is also a convenient function with default node and edge types as keyword arguments that include all the default supported components.
PowerModelsGraph(data::Dict{String,<:Any},
node_components=supported_node_types,
edge_components=supported_edge_types,
connected_components=supported_connected_types
)
PowerModelsGraph Example
using PowerModels
using PowerPlots
case = parse_file("case14.m")
# Specify node and edge types
case_PMG = PowerModelsGraph(case, node_components=[:bus], edge_components=["branch","dcline"], connected_components=["gen"])
# Use default node and edge types
case_PMG = PowerModelsGraph(case)
PowerModelsGraph(Graphs.SimpleGraphs.SimpleGraph{Int64}(37, [[7, 10, 15], [3, 14, 28], [2, 11, 29], [5, 11, 30], [4, 6, 11, 21], [5, 14, 22], [1, 8, 9, 10, 16, 20], [7, 9, 17, 23], [7, 8, 10, 12, 14, 24], [1, 7, 9, 11, 25] … [6], [8], [9], [10], [11], [14], [2], [3], [4], [14]]), Dict(5 => (:bus, Symbol("13")), 16 => (:gen, Symbol("2")), 20 => (:load, Symbol("1")), 12 => (:bus, Symbol("7")), 24 => (:load, Symbol("3")), 28 => (:load, Symbol("7")), 8 => (:bus, Symbol("3")), 17 => (:gen, Symbol("3")), 30 => (:load, Symbol("9")), 1 => (:bus, Symbol("1"))…), Dict((4, 5) => (:branch, Symbol("19")), (11, 5) => (:branch, Symbol("13")), (12, 13) => (:branch, Symbol("14")), (12, 14) => (:branch, Symbol("15")), (9, 10) => (:branch, Symbol("7")), (10, 11) => (:branch, Symbol("10")), (11, 3) => (:branch, Symbol("11")), (7, 9) => (:branch, Symbol("4")), (14, 2) => (:branch, Symbol("16")), (9, 12) => (:branch, Symbol("8"))…), Dict((11, 18) => (:gen, Symbol("4")), (2, 28) => (:load, Symbol("7")), (3, 29) => (:load, Symbol("8")), (1, 15) => (:gen, Symbol("1")), (4, 30) => (:load, Symbol("9")), (7, 20) => (:load, Symbol("1")), (14, 31) => (:shunt, Symbol("1")), (14, 27) => (:load, Symbol("6")), (7, 16) => (:gen, Symbol("2")), (9, 24) => (:load, Symbol("3"))…))
Using PowerModelsGraph
using PowerModels
using PowerPlots
using Graphs
case = parse_file("case14.m")
# Create a graph where buses are nodes and branches are edges
case_PMG = PowerModelsGraph(case, node_components=["bus"], edge_components=["branch"],);
PowerModelsGraph(Graphs.SimpleGraphs.SimpleGraph{Int64}(37, [[7, 10, 15], [3, 14, 28], [2, 11, 29], [5, 11, 30], [4, 6, 11, 21], [5, 14, 22], [1, 8, 9, 10, 16, 20], [7, 9, 17, 23], [7, 8, 10, 12, 14, 24], [1, 7, 9, 11, 25] … [6], [8], [9], [10], [11], [14], [2], [3], [4], [14]]), Dict(5 => (:bus, Symbol("13")), 16 => (:gen, Symbol("2")), 20 => (:load, Symbol("1")), 12 => (:bus, Symbol("7")), 24 => (:load, Symbol("3")), 28 => (:load, Symbol("7")), 8 => (:bus, Symbol("3")), 17 => (:gen, Symbol("3")), 30 => (:load, Symbol("9")), 1 => (:bus, Symbol("1"))…), Dict((4, 5) => (:branch, Symbol("19")), (11, 5) => (:branch, Symbol("13")), (12, 13) => (:branch, Symbol("14")), (12, 14) => (:branch, Symbol("15")), (9, 10) => (:branch, Symbol("7")), (10, 11) => (:branch, Symbol("10")), (11, 3) => (:branch, Symbol("11")), (7, 9) => (:branch, Symbol("4")), (14, 2) => (:branch, Symbol("16")), (9, 12) => (:branch, Symbol("8"))…), Dict((11, 18) => (:gen, Symbol("4")), (2, 28) => (:load, Symbol("7")), (3, 29) => (:load, Symbol("8")), (1, 15) => (:gen, Symbol("1")), (4, 30) => (:load, Symbol("9")), (7, 20) => (:load, Symbol("1")), (14, 31) => (:shunt, Symbol("1")), (14, 27) => (:load, Symbol("6")), (7, 16) => (:gen, Symbol("2")), (9, 24) => (:load, Symbol("3"))…))
g = Graphs.SimpleGraph(case_PMG.graph) # Does the graph contain cycles?
is_cyclic(g)
true
# Get the adjacency matrix
adjacency_matrix(case_PMG.graph)
31×31 SparseArrays.SparseMatrixCSC{Int64, Int64} with 74 stored entries:
⎡⠠⠂⡀⠁⠈⡄⠐⠁⠀⠀⠀⠀⠀⠐⢄⠀⎤
⎢⠄⠈⠊⡠⡤⠁⠐⠠⡀⠠⠑⡀⠀⠀⠀⠀⎥
⎢⠂⠤⠄⠋⡪⠊⣈⠀⠠⠀⠀⠈⠢⠀⠀⠀⎥
⎢⠔⠀⠐⡀⠂⠘⠀⠀⠀⠁⠀⠀⠀⠂⠀⠂⎥
⎢⠀⠀⠀⡈⠀⠂⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠑⠠⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⢀⠀⠀⠀⠈⠂⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎣⠀⠑⠀⠀⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⎦