Input Formats
CommmonOPF provides three ways to construct the Network Model model:
- YAML file(s)
- JSON file(s)
- Julia code (manual)
Only Network
and Conductor
are required to build the Network
. Note that the input keys are, singular, CamelCase words to align with the data type names. For example a single phase, single time step model looks like:
Network:
substation_bus: b1
Conductor:
- name: cond1
busses:
- b1
- b2
r1: 0.301 # impedance has units of ohm/per-unit-length
x1: 0.627
length: 100
- busses:
- b2
- b3
template: cond1 # <- reuse impedance of cond1
length: 200
Load:
- bus: b2
kws1:
- 5.6 # you can specify more loads at each bus to add time steps
kvars1:
- 1.2
- bus: b3
kws1:
- 5.6
kvars1:
- 1.2
The Network(fp::String)
constructor excepts a path to a yaml file.
Conductor
CommonOPF.Conductor
— Typestruct Conductor <: AbstractEdge
Interface for conductors in a Network. Fieldnames can be provided via a YAML file, JSON file, or populated manually. Conductors are specified via two busses, the impedance in ohms per-unit length, and a length value.
Single phase models
The minimum inputs for a single phase conductor look like:
Conductor:
- busses:
- b1
- b2
r1: 0.1
x1: 0.1
length: 100
Note that the order of the items in the YAML file does not matter.
A conductor can also leverage a template
, i.e. another conductor with a name
that matches the template
value so that we can re-use the impedance values:
Conductor:
- name: cond1
busses:
- b1
- b2
r1: 0.1
x1: 0.1
length: 100
- busses:
- b2
- b3
template: cond1
length: 200
The second conductor in the conductors
above will use the r0
and x0
values from cond1
, scaled by the length
of 200 and normalized by Zbase
.
The name
field is optional unless a conductor.name
is also the template
of another conductor.
If any phases
properties are set in the conductors
then it is assumed that the model is multi-phase.
Multi-phase models
Multi-phase conductors can be modeled as symmetrical or asymmetrical components. Similar to OpenDSS, line impedances can be specified via the zero and positive sequence impedances, (r0, x0)
and (r1, x1)
respectively; or via the lower-diagonal portion of the phase-impedance matrix.
Using the Multi-phase models requires specifying phases
(and the zero and positive sequence impedances) like:
Conductor:
- busses:
- b1
- b2
phases:
- 2
- 3
r0: 0.766
x0: 1.944
r1: 0.301
x1: 0.627
length: 100
When the sequence impedances are provided the phase-impedance matrix is determined using the math in Symmetrical Mutliphase Conductors.
Alternatively one can specify the rmatrix
and xmatrix
like:
Conductor:
- busses:
- b1
- b2
phases:
- 1
- 3
rmatrix:
- [0.31]
- [0.15, 0.32]
xmatrix:
- [1.01]
- [0.5, 1.05]
length: 100
The order of the phases
is assumed to match the order of the rmatrix
and xmatrix
. For example using the example just above the 3x3 rmatrix
looks like $[0.31, 0, 0.15; 0, 0, 0; 0.15, 0, 0.32]$
Conductors also have a cmatrix
attribute that is used when parsing OpenDSS models. The cmatrix
is used to define ShuntAdmittance
values for busses.
Load
CommonOPF.Load
— Type@with_kw mutable struct Load <: AbstractBus
A Load input specifier, mapped from YAML, JSON, or manually populated.
The minimum required inputs include several options. All require a bus
to place the load. For single phase models provide one of the following sets of values:
bus
,kws1
bus
,kws1
,kvars1
bus
,kws1
,q_to_p
bus
,csv
where csv
is a path to a two column CSV file with a single line header like "kws1,kvars1". If only bus
and kws1
are provided then the reactive load will be zero in the power flow model.
For unbalanced multiphase models one must provide one of:
bus
, [kws1
,kvars1
], [kws2
,kvars2
], [kws3
,kvars3
] <– brackets imply optional pairs, depending on the phases at the load busbus
,csv
where the csv
has 2, 4, or 6 columns with a single line header like "kws1,kvars1,kws2,kvars2,kws3,kvars3" or "kws2,kvars2,kws3,kvars3".
The kws
and kvars
inputs are plural because we always put the loads in vectors, even with one timestep. We do this so that the modeling packages that build on CommonOPF do not have to account for both scalar values and vector values.
Once the net::Network
is defined a load can be accessed like:
ld_busses = collect(load_busses(net))
lb = ld_busses[1] # bus keys are strings in the network
net[lb, :kws, 1] # last index is phase integer
Base.getindex
— Methodfunction Base.getindex(net::Network, bus::String, kws_kvars::Symbol, phase::Int)
Load getter for Network
. Use like:
net["busname", :kws, 2]
net["busname", :kvars, 3]
The second argument must be one of :kws
or :kvars
. The third arbument must be one of [1,2,3]
. If the "busname"
exists and has a :Load
dict, but the load (e.g. :kvars2
) is not defined then zeros(net.Ntimesteps)
is returned.
Capacitor
CommonOPF.Capacitor
— Typestruct Capacitor <: AbstractBus
Required fields:
bus::String
kvar1::Real
reactive power in kVaR on phase1kvar2::Real
reactive power in kVaR on phase2kvar3::Real
reactive power in kVaR on phase4
Only modeling fixed capacitors so far. Positive kvar values are injected.
ShuntAdmittance
CommonOPF.ShuntAdmittance
— Typestruct ShuntAdmittance <: AbstractBus
Required fields:
bus::String
g::Real
conductance in siemensb::Real
susceptance in siemens
Transformer
CommonOPF.Transformer
— Type@with_kw mutable struct Transformer <: AbstractEdge
# required values
busses::Tuple{String, String}
# optional values
high_kv::Real = 1.0
low_kv::Real = 1.0
phases::Union{Vector{Int}, Missing} = missing
reactance::Real = 0.0
resistance::Real = 0.0
end
For now the high_kv
and low_kv
values are only for reference. Throughout the modules that use CommonOPF we model in per-unit voltage. In the future we may add capability for scaling to absolute voltage in the future (in Results for example).
When phases
are not provided the model is assumed to be single phase.
Series impedance defaults to zero.
VoltageRegulator
CommonOPF.VoltageRegulator
— Typestruct VoltageRegulator <: AbstractEdge
# required values
busses::Tuple{String, String}
# optional values
high_kv::Real = 1.0
low_kv::Real = 1.0
phases::Union{Vector{Int}, Missing} = missing
reactance::Real = 0.0
resistance::Real = 0.0
vreg_pu::Union{Real, AbstractVector{<:Number}, Missing} = missing
turn_ratio::Union{Real, Missing} = missing
end
Required fields:
busses::Tuple{String, String}
- either
vreg_pu::Real
orturn_ratio::Real
If vreg_pu
is specified then the regulator is "perfect" and the second bus in busses
is fixed to the value provided for vreg_pu
.
If turn_ratio
is provided then the voltage across the regulator is scaled by the turn_ratio
.
Examples:
Julia Dict
netdict = Dict(
:network => Dict(:substation_bus => "1", :Sbase => 1),
:conductors => [
...
],
:voltage_regulators => [
Dict(
:busses => ("2", "3")
:vreg_pu => 1.05
)
]
)
YAML file
Network:
substation_bus: 0
Sbase: 1
Conductor:
...
VoltageRegulator:
busses:
- 2
- 3
vreg_pu: 1.05