diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index ea756b1..a254ae4 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.0-rc4","generation_timestamp":"2024-10-07T15:27:39","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-21T09:58:48","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/dev/ModelingConcepts/9f7f38f1.png b/dev/ModelingConcepts/9f7f38f1.png new file mode 100644 index 0000000..70dd024 Binary files /dev/null and b/dev/ModelingConcepts/9f7f38f1.png differ diff --git a/dev/ModelingConcepts/f579f9a4.png b/dev/ModelingConcepts/f579f9a4.png deleted file mode 100644 index 071f6a7..0000000 Binary files a/dev/ModelingConcepts/f579f9a4.png and /dev/null differ diff --git a/dev/ModelingConcepts/index.html b/dev/ModelingConcepts/index.html index 28aaa74..1a5265b 100644 --- a/dev/ModelingConcepts/index.html +++ b/dev/ModelingConcepts/index.html @@ -3,7 +3,8 @@ (t) │ │ o←───┤ Injector │ │ │ - └───────────┘
The current for injectors is always in injector convention, i.e. positive currents flow out of the injector towards the terminal.
Model "classes" are nothing formalized. In this document, a model class is just a description for some ODESystem
from ModelingToolkit.jl
, which satisfies certain requirements. For example, any ODESystem
is considered an "Injector" if it contains a connector Terminal()
called :terminal
.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+ └───────────┘
The current for injectors is always in injector convention, i.e. positive currents flow out of the injector towards the terminal.
Model "classes" are nothing formalized. In this document, a model class is just a description for some ODESystem
from ModelingToolkit.jl
, which satisfies certain requirements. For example, any ODESystem
is considered an "Injector" if it contains a connector Terminal()
called :terminal
.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+using ModelingToolkit: D_nounits as Dt, t_nounits as t
@mtkmodel MyPQLoad begin
@components begin
terminal = Terminal()
@@ -23,7 +24,7 @@
terminal.i_r ~ (Pset*terminal.u_r + Qset*terminal.u_i)/(terminal.u_r^2 + terminal.u_i^2)
terminal.i_i ~ (Pset*terminal.u_i - Qset*terminal.u_r)/(terminal.u_r^2 + terminal.u_i^2)
end
-end
MTKBus
A MTKBus
isa class of models, which are used to describe the dynamic behavior of a full bus in a power grid. Each MTKBus
musst contain a predefined model of type BusBar()
(named :busbar
). This busbar represents the connection point to the grid. Optionally, it may contain various injectors.
┌───────────────────────────────────┐
+end
MTKBus
A MTKBus
isa class of models, which are used to describe the dynamic behavior of a full bus in a power grid. Each MTKBus
musst contain a predefined model of type BusBar()
(named :busbar
). This busbar represents the connection point to the grid. Optionally, it may contain various injectors.
┌───────────────────────────────────┐
│ MTKBus ┌───────────┐ │
│ ┌──────────┐ ┌──┤ Generator │ │
│ │ │ │ └───────────┘ │
@@ -31,7 +32,7 @@
│ │ │ │ ┌───────────┐ │
│ └──────────┘ └──┤ Load │ │
│ └───────────┘ │
- └───────────────────────────────────┘
Sometimes it is not possible to connect all injectors directly but instead one needs or wants Branches
between the busbar and injector terminal. As long as the :busbar
is present at the toplevel, there are few limitations on the overall model complexity.
For simple models (direct connections of a few injectors) it is possible to use the convenience method MTKBus(injectors...)
to create the composite model based on provide injector models.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+ └───────────────────────────────────┘
Sometimes it is not possible to connect all injectors directly but instead one needs or wants Branches
between the busbar and injector terminal. As long as the :busbar
is present at the toplevel, there are few limitations on the overall model complexity.
For simple models (direct connections of a few injectors) it is possible to use the convenience method MTKBus(injectors...)
to create the composite model based on provide injector models.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
@mtkmodel MyMTKBus begin
@components begin
busbar = BusBar()
@@ -42,11 +43,11 @@
connect(busbar.terminal, swing.terminal)
connect(busbar.terminal, load.terminal)
end
-end
Alternativly, for that system you could have just called
mybus = MTKBus(Swing(;name=:swing), PQLoad(;name=:load))
to get an instance of a model which is structually aquivalent to MyMTKBus
.
Branch
A branch is the two-port equivalent to an injector. I needs to have two Terminal()
s, one is called :src
, the other :dst
.
Examples for branches are: PI─Model branches, dynamic RL branches or transformers.
┌───────────┐
+end
Alternativly, for that system you could have just called
mybus = MTKBus(Swing(;name=:swing), PQLoad(;name=:load))
to get an instance of a model which is structually aquivalent to MyMTKBus
.
Branch
A branch is the two-port equivalent to an injector. I needs to have two Terminal()
s, one is called :src
, the other :dst
.
Examples for branches are: PI─Model branches, dynamic RL branches or transformers.
┌───────────┐
(src) │ │ (dst)
o←──┤ Branch ├──→o
│ │
- └───────────┘
Both ends follow the injector interface, i.e. current leaving the device towards the terminals is always positive.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+ └───────────┘
Both ends follow the injector interface, i.e. current leaving the device towards the terminals is always positive.
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
@mtkmodel MyRLine begin
@components begin
src = Terminal()
@@ -61,7 +62,7 @@
src.i_r ~ -dst.i_r
src.i_i ~ -dst.i_i
end
-end
MTKLine
Similar to the MTKBus
, a MTKLine
is a model class which represents a transmission line in the network.
It musst contain two LineEnd()
instances, one called :src
, one called :dst
.
┌────────────────────────────────────────────────┐
+end
MTKLine
Similar to the MTKBus
, a MTKLine
is a model class which represents a transmission line in the network.
It musst contain two LineEnd()
instances, one called :src
, one called :dst
.
┌────────────────────────────────────────────────┐
│ MTKLine ┌──────────┐ │
│ ┌─────────┐ ┌──┤ Branch A │──┐ ┌─────────┐ │
│ │ LineEnd │ │ └──────────┘ │ │ LineEnd │ │
@@ -69,7 +70,7 @@
│ │ │ │ ┌──────────┐ │ │ │ │
│ └─────────┘ └──┤ Branch B │──┘ └─────────┘ │
│ └──────────┘ │
- └────────────────────────────────────────────────┘
Simple line models, which consist only of valid Branch
models can be instantiated using the MTKLine(branches...)
constructor.
More complex models can be created manually. For example if you want to chain multiple branches between the LineEnds
, for example something like
LineEnd(:src) ──o── Transformer ──o── Pi─Line ──o── LineEnd(:dst)
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+ └────────────────────────────────────────────────┘
Simple line models, which consist only of valid Branch
models can be instantiated using the MTKLine(branches...)
constructor.
More complex models can be created manually. For example if you want to chain multiple branches between the LineEnds
, for example something like
LineEnd(:src) ──o── Transformer ──o── Pi─Line ──o── LineEnd(:dst)
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
@mtkmodel MyMTKLine begin
@components begin
src = LineEnd()
@@ -83,26 +84,31 @@
connect(dst.terminal, branch1.dst)
connect(dst.terminal, branch2.dst)
end
-end
Alternatively, an equivalent model with multiple valid branch models in parallel could be created and instantiated with the convenience constructor
line = MTKLine(DynawoPiLine(;name=:branch1), DynawoPiLine(;name=:branch2))
Valid MTKLine
and MTKBus
can be transformed into so called Line
and Bus
objects.
Line
and Bus
structs are no MTK models anymore, but rather containers. Currently, they mainly contain a NetworkDynamics component function (ODEVertex
, StaticEdge
).
Eventually, those models will contain more metadata. For example
The exact structure here is not clear yet!
The result would look something like that:
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
+end
Alternatively, an equivalent model with multiple valid branch models in parallel could be created and instantiated with the convenience constructor
line = MTKLine(DynawoPiLine(;name=:branch1), DynawoPiLine(;name=:branch2))
Valid MTKLine
and MTKBus
can be transformed into so called Line
and Bus
objects.
Line
and Bus
structs are no MTK models anymore, but rather containers. Currently, they mainly contain a NetworkDynamics component function (VertexModel
, EdgeModel
).
Eventually, those models will contain more metadata. For example
The exact structure here is not clear yet!
The result would look something like that:
using OpPoDyn, OpPoDyn.Library, ModelingToolkit
using Graphs, NetworkDynamics
using OrdinaryDiffEqRosenbrock, OrdinaryDiffEqNonlinearSolve
using CairoMakie
Define a swing bus with load
# define injectors
@named swing = Swing(; Pm=1, V=1, D=0.1)
@named load = PQLoad(; Pset=-.5, Qset=0)
bus1mtk = MTKBus(swing, load; name=:swingbus)
-vertex1f = Bus(bus1mtk) # extract component function
NetworkDynamics.ODEVertex :swingbus with depth 2
- ├─ 4 states: [busbar₊u_r=1.0, busbar₊u_i=0.0, swing₊θ, swing₊ω]
- | with diagonal mass matrix [0, 0, 1, 1]
- └─ 7 params: [load₊Qset=0.0, swing₊D=0.1, swing₊M=0.005, swing₊ω_ref=1.0, swing₊Pm=1.0, swing₊V=1.0, load₊Pset=-0.5]
Define a second bus as a slack
bus2mtk = SlackDifferential(; name=:slackbus)
-vertex2f = Bus(bus2mtk) # extract component function
NetworkDynamics.ODEVertex :slackbus with depth 2
- └─ 2 states: [busbar₊u_r=1.0, busbar₊u_i=0.0]
Define the powerline connecting both nodes
@named branch1 = DynawoPiLine()
+vertex1f = Bus(bus1mtk) # extract component function
NetworkDynamics.VertexModel :swingbus NetworkDynamics.NoFeedForward()
+ ├─ 2 inputs: [busbar₊i_r, busbar₊i_i]
+ ├─ 2 states: [swing₊θ≈0, swing₊ω≈0]
+ ├─ 2 outputs: [busbar₊u_r=1, busbar₊u_i=0]
+ └─ 7 params: [load₊Qset=0, swing₊D=0.1, swing₊M=0.005, swing₊ω_ref=1, swing₊Pm=1, swing₊V=1, load₊Pset=-0.5]
Define a second bus as a slack
bus2mtk = SlackDifferential(; name=:slackbus)
+vertex2f = Bus(bus2mtk) # extract component function
NetworkDynamics.VertexModel :slackbus NetworkDynamics.PureStateMap()
+ ├─ 2 inputs: [busbar₊i_r, busbar₊i_i]
+ ├─ 2 states: [busbar₊u_r=1, busbar₊u_i=0]
+ └─ 2 outputs: [busbar₊u_r=1, busbar₊u_i=0]
Define the powerline connecting both nodes
@named branch1 = DynawoPiLine()
@named branch2 = DynawoPiLine()
linemtk = MTKLine(branch1, branch2; name=:powerline)
-edgef = Line(linemtk) # extract component function
NetworkDynamics.StaticEdge :powerline with Fiducial coupling of depth 2
- ├─ 4 states: [dst₊i_r, dst₊i_i, src₊i_r, src₊i_i]
- └─ 8 params: [branch1₊GPu=0.0, branch2₊BPu=0.0, branch2₊GPu=0.0, branch1₊RPu=0.0, branch2₊XPu=0.022522, branch1₊XPu=0.022522, branch2₊RPu=0.0, branch1₊BPu=0.0]
Define the graph, the network and extract initial conditions
g = complete_graph(2)
+edgef = Line(linemtk) # extract component function
NetworkDynamics.EdgeModel :powerline NetworkDynamics.PureFeedForward()
+ ├─ 2/2 inputs: src=[src₊u_r, src₊u_i] dst=[dst₊u_r, dst₊u_i]
+ ├─ 0 states: []
+ ├─ 2/2 outputs: src=[src₊i_r, src₊i_i] dst=[dst₊i_r, dst₊i_i]
+ └─ 8 params: [branch1₊GPu=0, branch2₊BPu=0, branch2₊GPu=0, branch1₊RPu=0, branch2₊XPu=0.022522, branch1₊XPu=0.022522, branch2₊RPu=0, branch1₊BPu=0]
Define the graph, the network and extract initial conditions
g = complete_graph(2)
nw = Network(g, [vertex1f, vertex2f], edgef)
-u0 = NWState(nw) # extract parameters and state from modesl
+u0 = NWState(nw) # extract parameters and state from models
u0.v[1, :swing₊θ] = 0 # set missing initial conditions
u0.v[1, :swing₊ω] = 1
1
Then we can solve the problem
prob = ODEProblem(nw, uflat(u0), (0,1), pflat(u0))
sol = solve(prob, Rodas5P())
And finally we can plot the solution:
fig = Figure();
@@ -115,7 +121,7 @@
ax = Axis(fig[2,1])
lines!(ax, sol; idxs=VIndex(1,:busbar₊u_arg), label="swing bus voltage angle", color=Cycled(1))
lines!(ax, sol; idxs=VIndex(2,:busbar₊u_arg), label="slack bus voltage angle", color=Cycled(2))
-axislegend(ax)
Internally, we use different input/output conventions for bus and line models. The predefined models BusBar()
and LineEnd()
are defined in the following way:
BusBar()
A busbar is a concrete model used in bus modeling. It represents the physical connection within a bus, the thing where all injectors and lines attach.
┌──────────┐
+axislegend(ax)
Internally, we use different input/output conventions for bus and line models. The predefined models BusBar()
and LineEnd()
are defined in the following way:
BusBar()
A busbar is a concrete model used in bus modeling. It represents the physical connection within a bus, the thing where all injectors and lines attach.
┌──────────┐
i_lines ──→│ │ (t)
│ Busbar ├───o
u_bus ←──│ │
@@ -123,4 +129,4 @@
u_bus ──→│ │ (t)
│ LineEnd ├───o
i_line ←──│ │
- └───────────┘
It has special input/output connectors which handle the network interconnection. The main difference beeing the different input/output conventions for the network interface.
Settings
This document was generated with Documenter.jl version 1.7.0 on Monday 7 October 2024. Using Julia version 1.11.0-rc4.