Skip to content

Commit

Permalink
Merge pull request #673 from NREL-SIIP/jd/docs_dyn
Browse files Browse the repository at this point in the history
docs dyn
  • Loading branch information
jd-lara authored Nov 23, 2020
2 parents e9a1e43 + 5694799 commit 8bb030d
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 14 deletions.
3 changes: 2 additions & 1 deletion docs/src/api/public.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ Filter = t -> t ∈ [InfrastructureSystems.get_time_series,
Modules = [PowerSystems]
Pages = ["utils/network_calculations/ybus_calculations.jl",
"utils/network_calculations/ptdf_calculations.jl",
"utils/network_calculations/lodf_calculations.jl"]
"utils/network_calculations/lodf_calculations.jl",
"utils/network_calculations/common.jl"]
Private = false
Public = true
```
Expand Down
Binary file modified docs/src/assets/inv_metamodel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 72 additions & 2 deletions docs/src/modeler_guide/network_matrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,76 @@
# `PowerSystems.jl` is able to build classic power systems modeling network matrices such as
# [Ybus](https://en.wikipedia.org/wiki/Nodal_admittance_matrix), [PTDF](https://www.powerworld.com/WebHelp/Content/MainDocumentation_HTML/Power_Transfer_Distribution_Factors.htm) and LODF

# Check section [Network Matrices](@ref net_mat)
# Check section [Network Matrices](@ref net_mat) for more details

# **UNDER CONSTRUCTION**
# ## Overview
#
# Network matrices are implemented in `PowerSystems.jl` as arrays that enable using Branch or Bus
# names a indexes to facilitate exploration and analysis. Ybus is stored as an SparseMatrix
# and the PTDF and LODF are stored as dense matrices. **Note*** Ybus is converted to a dense
# matrix for printing in the REPL,
# The network matrices code implements the Goderya algorithm to find islands.

using PowerSystems
const PSY = PowerSystems
DATA_DIR = "../../../data" #hide
system_data = System(joinpath(DATA_DIR, "matpower/case14.m"))

# ## Ybus
#
# The ybus can be calculated as follows:
ybus = Ybus(system_data)

# The matrix can be indexed using directly the bus numbers. In this example buses are numbered
# 1-14. However, in large systems buses don't usually follow sequential numbering. You can access
# the entries of the Ybus with direct indexing or using the buses.

ybus_entry = ybus[3,3]
#
bus3 = get_component(Bus, system_data, "Bus 3 HV")
ybus_entry = ybus[bus3, bus3]

# We recognize that many models require matrix operations. For those cases, you can access the
# sparse data as follows:

sparse_array = get_data(ybus)

# ## PTDF
#
# The PTDF matrix can be calculated as follows:
ptdf = PTDF(system_data)

# The entries of the matrix can also be indexed using the devices directly:
line = get_component(Line, system_data, "Bus 1 HV-Bus 2 HV-i_1")
bus = get_component(Bus, system_data, "Bus 3 HV")

ptdf_entry = ptdf[line, bus]

# Alternatively, the branch name and bus number can be used. For instance, for the same PTDF
# entry we can do:

ptdf_entry = ptdf["Bus 1 HV-Bus 2 HV-i_1", 3]

# PTDF also takes a vector of distributed slacks, for now this feature requires passing a
# vector of weights with the same number of elements are buses in the system. For more details
# check the API entry for [`PTDF`](@ref).

# In the same fashion as in the case of the Ybus, we recognize many models use matrix operations
# when using the PTDF matrix. The raw data is available using `get_data` and the lookup table
# between (names,numbers) and (i,j) matrix entries is available using [`get_lookup`](@ref)

branch_lookup, bus_lookup = get_lookup(ptdf);

# Branch lookup:

branch_lookup

# Bus Look up

bus_lookup

# ## LODF

# LODF and PTDF share the same characteristics in terms of indexing and calculation:

lodf = LODF(system_data)
59 changes: 55 additions & 4 deletions docs/src/modeler_guide/power_flow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,62 @@

# `PowerSystems.jl` provides the capability to run a power flow with the intention of
# providing a valid initial AC operating point to the system. It is not meant as an analytics
# tool; the main issue is to determine if the system has feasible AC data.
# tool; the main issue is to determine if the system has feasible AC data. This solver does
# not check for reactive power limits or other limiting mechanisms in the grid.

# The power flow solver uses [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) under
# the hood and takes any keyword argument accepted by NLsolve
# the hood and takes any keyword argument accepted by NLsolve. The solver uses the current
# operating point in the buses to provide the initial guess.

# Check section [Power Flow](@ref pf)
# **Limitations**: The PowerFlow solver doesn't support systems with HVDC lines or
# Phase Shifting transformers yet. The power flow solver can't handle systems with islands.

# **Under Construction**
# Check section [Power Flow](@ref pf) for detailed usage instructions

using PowerSystems
const PSY = PowerSystems

DATA_DIR = "../../../data" #hide
system_data = System(joinpath(DATA_DIR, "matpower/case14.m"))

# `PowerSystems.jl` has two modes of using the power flow solver.

# 1. Solving the power flow for the current operating point in the system.
# Takes the data in the buses, the `active_power` and `reactive_power` fields
# in the static injection devices. Returns a dictionary with results in a DataFrame that
# can be exported or manipulated as needed.
#
# 2. Solves the power flow and updated the devices in the system to the operating condition.
# This model will update the values of magnitudes and angles in the system's buses. It
# also updates the active and reactive power flows in the branches and devices connected
# to PV buses. This utility is useful to initialize systems before serializing or checking
# the addition of new devices is still AC feasible.

# Solving the powwer flow with mode 1:

results = solve_powerflow(system_data)
results["bus_results"]

# Solving the powwer flow with mode 2:

# Before running the power flow command this are the values of the
# voltages:

for b in get_components(Bus, system_data)
println("$(get_name(b)) - Magnitude $(get_magnitude(b)) - Angle (rad) $(get_angle(b))")
end

# [`solve_powerflow!`](@ref) return true or false to signal the successful result of the power
# flow. This enables the integration of a power flow check into functions. For instance,
# initializing dynamic simulations. Also, because [`solve_powerflow!`](@ref) uses
# [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl) all the parameters used for NLsolve
# are also available for [`solve_powerflow!`](@ref)

solve_powerflow!(system_data; finite_diff = true, method = :newton)

# After running the power flow command this are the values of the
# voltages:

for b in get_components(Bus, system_data)
println("$(get_name(b)) - Magnitude $(get_magnitude(b)) - Angle (rad) $(get_angle(b))")
end
1 change: 1 addition & 0 deletions src/PowerSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export get_forecast_initial_times
export get_forecast_total_period
export get_resolution
export get_data
export get_lookup
export iterate_components
export get_time_series_multiple
export get_variable_cost
Expand Down
9 changes: 9 additions & 0 deletions src/utils/network_calculations/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,12 @@ end
Base.to_index(b::Bus) = get_number(b)
Base.to_index(b::T) where {T <: ACBranch} = get_name(b)
Base.to_index(ix::Component...) = to_index.(ix)

"""returns the raw array data of the `PowerNetworkMatrix`"""
get_data(mat::PowerNetworkMatrix) = mat.data

"""
returns the lookup tuple of the `PowerNetworkMatrix`. The first entry corresponds
to the first dimension and the second entry corresponds to the second dimension
"""
get_lookup(mat::PowerNetworkMatrix) = mat.lookup
14 changes: 7 additions & 7 deletions test/test_network_matrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ include(joinpath(BASE_DIR, "test", "data_5bus_pu.jl"))
include(joinpath(BASE_DIR, "test", "data_14bus_pu.jl"))

# The 5-bus case from PowerModels data is modified to include 2 phase shifters
sys = PowerSystems.System(PowerSystems.PowerModelsData(joinpath(MATPOWER_DIR, "case5.m")))
sys = System(joinpath(MATPOWER_DIR, "case5.m"))
RTS = create_rts_system();

# mixed up ids for data_5bus_pu
Expand Down Expand Up @@ -420,13 +420,13 @@ Ybus5_phaseshifter[5, 5] = 18.8039637297063 - 188.020637297063im;
@testset "PTDF matrices" begin
nodes_5 = nodes5()
branches_5 = branches5(nodes_5)
P5 = PowerSystems.PTDF(branches_5, nodes_5)
P5 = PTDF(branches_5, nodes_5)
@test maximum(P5.data - S5_slackB4) <= 1e-3
@test P5[branches_5[1], nodes_5[1]] == 0.1939166051164976

nodes_14 = nodes14()
branches_14 = branches14(nodes_14)
P14 = PowerSystems.PTDF(branches_14, nodes_14)
P14 = PTDF(branches_14, nodes_14)
@test maximum(P14.data - S14_slackB1) <= 1e-3

P5NS = PTDF([branches_5[b] for b in Br5NS_ids], [nodes_5[b] for b in Bu5NS_ids])
Expand All @@ -435,7 +435,7 @@ Ybus5_phaseshifter[5, 5] = 18.8039637297063 - 188.020637297063im;
end

PRTS = PTDF(RTS)
bnums = sort([PowerSystems.get_number(b) for b in get_components(Bus, RTS)])
bnums = sort([get_number(b) for b in get_components(Bus, RTS)])
for (ibr, br) in enumerate(RTS_branchnames), (ib, b) in enumerate(bnums)
@test getindex(PRTS, br, b) - SRTS_GMLC[ibr, ib] <= 1e-3
end
Expand All @@ -444,16 +444,16 @@ end
@testset "LODF matrices" begin
nodes_5 = nodes5()
branches_5 = branches5(nodes_5)
L5 = PowerSystems.LODF(branches_5, nodes_5)
L5 = LODF(branches_5, nodes_5)
@test maximum(L5.data - Lodf_5) <= 1e-3
@test L5[branches_5[1], branches_5[2]] == 0.3447946513849091

nodes_14 = nodes14()
branches_14 = branches14(nodes_14)
L14 = PowerSystems.LODF(branches_14, nodes_14)
L14 = LODF(branches_14, nodes_14)
@test maximum(L14.data - Lodf_14) <= 1e-3

L5NS = PowerSystems.LODF(sys)
L5NS = LODF(sys)
@test getindex(L5NS, "3-4-i_5", "2-3-i_4") - 0.0003413469090 <= 1e-4

L5NS = LODF([branches_5[b] for b in Br5NS_ids], [nodes_5[b] for b in Bu5NS_ids])
Expand Down

0 comments on commit 8bb030d

Please sign in to comment.