Skip to content

Commit 005287b

Browse files
authored
Merge pull request #177 from JuliaDynamics/hw/updocs
update docs
2 parents 22e7aa0 + 3ea5952 commit 005287b

16 files changed

+404
-36
lines changed

NEWS.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# NetworkDynamics Release Notes
2+
3+
## v0.9 Changelog
4+
### Main changes in this release
5+
NetworkDynamics v0.9 is a complete overhaul of the previous releases of NetworkDynamics.
6+
Users of the package should probably read the new documentation carefully.
7+
8+
The most important changes are:
9+
10+
- Explicit split in `f` and `g` function: There is no split into `ODE` and
11+
`Static` components anymore, verything is unified in component functions with
12+
internal function `f` and output function `g`.
13+
- Parameters handling: Parameters are allways stored in a flat array. The
14+
Symbolic Indexing Interfaces helps to set and retrieve parameters.
15+
- Automatic aggregation: vertices no longer receive a list of all connected
16+
edges. This lead to inhomogeneous call signatures and was a performance
17+
bottleneck. Now, each `Network` has a `aggregation` function attached to it.
18+
The backaned will perform a reduction over all connected edges to calculate
19+
the input for a certain vertex. In practice, for typical flow networks you'll
20+
allways receive the sum of all flows rather than the individual flows.
21+
- Symbolic Indexing: the order of the states in the state vector changed in
22+
non-trivial ways. But the old `idx_containing` and `syms_containing` functions
23+
have been replaced with a much more capable symbolic indexing framework.
24+
25+
### Limitations
26+
- We dropped support for delay differential equations. If you've been using that
27+
feature please reach out to us.
28+
- Due to the built aggregation, the vertices cannot explicitly handle the inputs
29+
from edges differently anymore. If you've been relying on those features reach
30+
out to us.

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1-
# NetworkDynamics
1+
# NetworkDynamics.jl
22

33
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliadynamics.github.io/NetworkDynamics.jl/dev/)
44
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadynamics.github.io/NetworkDynamics.jl/stable)
55

6-
A package for working with dynamical systems on complex networks. NetworkDynamics.jl provides an interface between [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl) and [DifferentialEquations.jl](https://github.com/JuliaDiffEq/DifferentialEquations.jl). It allows to define several types of dynamic and static nodes and edges and to link them up in order to create complex network dynamics.
6+
A package for working with dynamical systems on complex networks. NetworkDynamics.jl provides an interface between [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl) and [DifferentialEquations.jl](https://github.com/JuliaDiffEq/DifferentialEquations.jl).
7+
It allows modeling of dynamical processes on networks using a *modular* approach: meaning that the overall network dynamics are composed based on dynamical models for the *nodes* and the *edges*.
8+
The dynamical behavior of those components are described by differential algebraic equations with inputs and outputs.
79

8-
The behavior of a node or an edge can be described by algebraic equations, by differential algebraic equation (DAEs) in mass matrix form or by ordinary differential equations (ODE). Stochastic ordinary differential equations (SDE) can be implemented as a [two-layer network](https://juliadynamics.github.io/NetworkDynamics.jl/dev/generated/StochasticSystem/). For details see the [docs](https://juliadynamics.github.io/NetworkDynamics.jl/dev/).
10+
Typical usecases for this modeling appraoch are diffusion processes, oscillator networks or power grids.
911

1012
## Getting started
1113

12-
Check out the [getting started](https://juliadynamics.github.io/NetworkDynamics.jl/dev/generated/getting_started_with_network_dynamics/) example in our docs.
14+
Check out our [documentation](https://juliadynamics.github.io/NetworkDynamics.jl/dev/).
15+
A good place to start is the page on the [mathematical model](https://juliadynamics.github.io/NetworkDynamics.jl/dev/mathematical_model/). For a more hands-on approach check out the [getting started example](https://juliadynamics.github.io/NetworkDynamics.jl/dev/generated/getting_started_with_network_dynamics/).
1316

14-
An [introductory talk](https://www.youtube.com/watch?v=GrmnbDYr6mM) was recorded at JuliaCon2020.
17+
An [introductory talk](https://www.youtube.com/watch?v=GrmnbDYr6mM) for an older version of this package was recorded for JuliaCon2020. Be aware that the API change significantly since then, but it can still give some insights into usecases of the package.
1518

1619
## Benchmarks
1720

1821
In our benchmark on the Kuramoto model NetworkDynamics.jl + DifferentialEquations.jl proved to be an especially performant solution, see https://github.com/PIK-ICoNe/NetworkDynamicsBenchmarks.
1922

20-
## PowerDynamics
23+
## PowerDynamics.jl
24+
25+
> [!IMPORTANT]
26+
> As of 11/2024, the currently available version of PowerDynamics.jl is quite outdated and builds on an old version of NetworkDynamics. However, PowerDynamics will receive an Substantial update as part of an ongoing project. We expect a pre-release of that in the first half of 2025!
2127
2228
[PowerDynamics.jl](https://juliaenergy.github.io/PowerDynamics.jl/stable/) is an open-source framework for dynamic power grid modeling and analysis build on top of NetworkDynamics.jl.
2329

30+
2431
## Citations
2532

2633
If you use NetworkDynamics.jl in your research publications, please cite our [paper](https://aip.scitation.org/doi/10.1063/5.0051387).

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
55
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
66
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
77
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
8-
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
98
DynamicQuantities = "06fc5a27-2a28-4c7c-a15d-362465fb6821"
9+
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
1010
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1111
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
1212
LinearInterpolations = "b20c7882-2490-4592-a606-fbbfe9e745e8"

docs/examples/gas_network.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ nothing #hide
234234
To bild the Network we first need to define the components. This is a two step process:
235235
236236
- first create the symbolic `ODESystem` using ModelingToolkit
237-
- secondly build a NetworkDynamics component function ([`VertexFunction`](@ref)/[`EdgeFunsction`](@ref)) based on the symbolic system.
237+
- secondly build a NetworkDynamics component function ([`VertexFunction`](@ref)/[`EdgeFunction`](@ref)) based on the symbolic system.
238238
239239
In the first step we can use the keyword arguments to pass "default" values for our parameters and states.
240240
Those values will be automaticially transfered to the metadata of the component function the second step.

docs/make.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using Documenter
44
using NetworkDynamics
55
using SciMLBase
66
using Literate
7+
using ModelingToolkit
78

89
# generate examples
910
example_dir = joinpath(@__DIR__, "examples")
@@ -19,10 +20,11 @@ end
1920
# TODO: doc on steady state solve https://docs.sciml.ai/NonlinearSolve/stable/native/steadystatediffeq/#SteadyStateDiffEq.SSRootfind
2021
# TODO: doc on parameter & state handling? -> symbolic indexing
2122

23+
mtkext = Base.get_extension(NetworkDynamics, :MTKExt)
2224
makedocs(;
2325
root=joinpath(pkgdir(NetworkDynamics), "docs"),
2426
sitename="NetworkDynamics",
25-
modules=[NetworkDynamics],
27+
modules=[NetworkDynamics, mtkext],
2628
linkcheck=true, # checks if external links resolve
2729
pagesonly=true,
2830
pages=[
@@ -33,6 +35,7 @@ makedocs(;
3335
"symbolic_indexing.md",
3436
"metadata.md",
3537
"initialization.md",
38+
"mtk_integration.md",
3639
],
3740
"API.md",
3841
"Tutorials" => [

docs/src/API.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@ pdim(::Network)
1111

1212
## Component Functions
1313
```@docs
14-
VertexFunction
15-
EdgeFunction
14+
VertexFunction()
15+
EdgeFunction()
16+
```
17+
18+
## Component Functions with MTK
19+
```@docs
20+
VertexFunction(::ModelingToolkit.ODESystem, ::Any, ::Any)
21+
EdgeFunction(::ModelingToolkit.ODESystem, ::Any, ::Any, ::Any, ::Any)
22+
EdgeFunction(::ModelingToolkit.ODESystem, ::Any, ::Any, ::Any)
1623
```
1724

1825
### Output Function Helpers/Wrappers
@@ -123,6 +130,25 @@ initialize_component!
123130
init_residual
124131
```
125132

133+
## Execution Types
134+
```@docs
135+
ExecutionStyle
136+
SequentialExecution
137+
PolyesterExecution
138+
ThreadedExecution
139+
KAExecution
140+
```
141+
142+
## Aggregators
143+
```@docs
144+
Aggregator
145+
SequentialAggregator
146+
SparseAggregator
147+
ThreadedAggregator
148+
PolyesterAggregator
149+
KAAggregator
150+
```
151+
126152
## Utils
127153
```@docs
128154
save_parameters!

docs/src/mathematical_model.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,43 @@ gᵥ(yᵥ, xᵥ, e_aggr, pᵥ, t)
126126
gₑ([y_src], y_dst, xᵥ, v_src, v_dst, pₑ, t)
127127
```
128128

129-
NetworkDyanmics cannot couple two components with feed forward to each other.
129+
NetworkDynamics cannot couple two components with feed forward to each other.
130130
It is always possible to transform feed forward behavior to an internal state `x` with mass matrix entry zero to circumvent this problem. This transformation can be performed automatically by using [`ff_to_constraint`](@ref).
131131

132132
!!! warning "Feed Forward Vertices"
133133
As of 11/2024, vertices with feed forward are not supported at all. Use [`ff_to_constraint`](@ref) to transform them into vertex functions without FF.
134134

135+
Concretely, NetworkDynamics distinguishes between 4 types of feed forward behaviors of `g` functions based on the [`FeedForwardType`](@ref) trait.
136+
The different types the signature of provided function `g`.
137+
Based on the signatures avaialable, ND.jl will try to find the correct type automaticially. Using the `ff`
138+
keyword in the constructors, the user can enforce a specific type.
139+
140+
**[`PureFeedForward()`](@ref)**
141+
```julia
142+
g!(outs..., ins..., p, t) # abstractly
143+
g!(out_dst, v_src, v_dst, p, t) # single-sided edge function
144+
g!(out_src, out_dst, v_src, v_dst, p, t) # double-sided edge function
145+
g!(v_out, e_aggr, p, t) # single layer vertex function
146+
```
147+
**[`FeedForward()`](@ref)**
148+
```julia
149+
g!(outs..., x, ins..., p, t) # abstractly
150+
g!(out_dst, x, v_src, v_dst, p, t) # single-sided edge function
151+
g!(out_src, out_dst, x, v_src, v_dst, p, t) # double-sided edge function
152+
g!(v_out, x, e_aggr, p, t) # single layer vertex function
153+
```
154+
**[`NoFeedForward()`](@ref)**
155+
```julia
156+
g!(outs..., x, p, t) # abstractly
157+
g!(out_dst, x, p, t) # single-sided edge function
158+
g!(out_src, out_dst, x, p, t) # double-sided edge function
159+
g!(v_out, x, p, t) # single layer vertex function
160+
```
161+
**[`PureStateMap()`](@ref)**
162+
```julia
163+
g!(outs..., x) # abstractly
164+
g!(out_dst, x) # single-sided edge function
165+
g!(out_src, out_dst, x) # double-sided edge function
166+
g!(v_out, x) # single layer vertex function
167+
```
168+

docs/src/mtk_integration.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# ModelingToolkit Integration
2+
3+
NetworkDynamics.jl is compatible with [`ModelingTookit.jl`](https://github.com/SciML/ModelingToolkit.jl) (MTK).
4+
The general idea is to use MTK to define *component models* (i.e. edge and vertex dynamics)
5+
which are then connected on network scale using NetworkDynamics.
6+
7+
The main entry point for this interop are the constructors
8+
```julia
9+
VertexFunction(::ODESystem, inputs, outputs)
10+
EdgeFunction(::ODESystem, srcin, dstin, [srscout], dstout)
11+
```
12+
whose docstrings can be found in the [Component Functions with MTK](@ref) section in the API.
13+
14+
These constructors will:
15+
- transforming the states marked as input to parameters and `structural_simplify`ing the system,
16+
- generating the `f` and `g` functions,
17+
- generate code for observables,
18+
- port all supported [Metadata](@ref) from MTK symbols to component symbols and
19+
- output a `Vertex-`/`EdgeFunction` function compatible with NetworkDynamics.jl.
20+
21+
The main usecase for this feature is when you want to build relatively complex
22+
component models but interconnect them in a very homogeneous way (i.e. having the
23+
same output/input pairings in the whole system).
24+
25+
In theory, you can achieve everything you want to do with plain MTK. The idea of
26+
combining the two is, that NetworkDynamics offers *far less flexibility* when in
27+
comes to interconnection of subsystems on the network level. This might allow ND
28+
to exploit more knowledge of the structure without very expensive operations such
29+
as tearing of thousands of equations.
30+
31+
!!! warning
32+
ModelingToolkit is a fast paced library with lots of functionality and ever
33+
growing complexity. As such the provided interface is kinda experimental.
34+
Some features of MTK are straight up unsupported, for example events within
35+
models or delay differential equations.
36+
37+
## RC-Circuit Example
38+
In good [MTK tradition](https://docs.sciml.ai/ModelingToolkit/stable/tutorials/acausal_components/), this feature will be explained along a simple RC circuit example.
39+
The [Dynamic Flow in simple Gas Network](@ref) example is another showcase of the MTK constructors.
40+
41+
The system to model is 2 node, 1 edge network. The node output states are the voltage (to ground), the edge output sates are the currents at both ends.
42+
```
43+
44+
ideal v source Resistor Capacitor
45+
v1 o─←────MMM────→─o v2
46+
│ ┴
47+
(↗) ┬
48+
│ │
49+
⏚ ⏚
50+
```
51+
Obviously there is no need in modeling such a small system using NetworkDynamics, however
52+
the method extends quite easily to construct large electrical networks reusing the same
53+
fundamental building blocks.
54+
55+
```@example mtk
56+
using NetworkDynamics
57+
using ModelingToolkit
58+
using ModelingToolkit: t_nounits as t, D_nounits as D
59+
using OrdinaryDiffEqTsit5
60+
using CairoMakie
61+
```
62+
63+
All our components have "terminals", which have a voltage and current. We don't use the `@connector` from MTK here because our pins mark the interface towards the network and do not follow the MTK connector semantics.
64+
65+
```@example mtk
66+
@mtkmodel NWTerminal begin
67+
@variables begin
68+
v(t), [description="Voltage at node"]
69+
i(t), [description="Current flowing into node"]
70+
end
71+
end
72+
nothing #hide
73+
```
74+
75+
An ideal voltage source is just a model which pins its output voltage to a fixed parameter.
76+
The source ejects whatever current is necessary. We introduce another variable `i(t)`
77+
to "capture" this current. This variable will be removed during structural simplify, but will
78+
be available for plotting through the [Observables](@ref) mechanism.
79+
The `VertexFunction` can be generated from an `ODESystem` by providing names of the input and output states:
80+
81+
```@example mtk
82+
@mtkmodel VoltageSource begin
83+
@components begin
84+
p = NWTerminal()
85+
end
86+
@parameters begin
87+
V = 1.0
88+
end
89+
@variables begin
90+
i(t), [description="produced current by ideal voltage source (observable)"]
91+
end
92+
@equations begin
93+
i ~ -p.i
94+
p.v ~ V
95+
end
96+
end
97+
@named vs = VoltageSource()
98+
vs_vertex = VertexFunction(vs, [:p₊i], [:p₊v]; vidx=1)
99+
```
100+
101+
A capacitor is a slightly more complicated model. Its voltage is defined as an differential
102+
equation based on the inflowing current.
103+
104+
```@example mtk
105+
@mtkmodel Capacitor begin
106+
@components begin
107+
p = NWTerminal(;v=0)
108+
end
109+
@parameters begin
110+
C = 1.0
111+
end
112+
@equations begin
113+
D(p.v) ~ p.i / C
114+
end
115+
end
116+
@named cap = Capacitor()
117+
cap_vertex = VertexFunction(cap, [:p₊i], [:p₊v], vidx=2)
118+
```
119+
120+
For the resistor we need two pins, one for the `src` and one for the `dst` side.
121+
The equations are straight forward.
122+
123+
```@example mtk
124+
@mtkmodel Resistor begin
125+
@components begin
126+
src = NWTerminal()
127+
dst = NWTerminal()
128+
end
129+
@parameters begin
130+
R = 1.0
131+
end
132+
@equations begin
133+
dst.i ~ (src.v - dst.v)/R
134+
src.i ~ -dst.i
135+
end
136+
end
137+
@named resistor = Resistor()
138+
resistor_edge = EdgeFunction(resistor, [:src₊v], [:dst₊v], [:src₊i], [:dst₊i]; src=:vs, dst=:cap)
139+
```
140+
141+
Having all those components defined, we can build the network. We don't need to provide a graph
142+
object here because we specified the placement in the graph on a per component basis.
143+
144+
```@example mtk
145+
nw = Network([vs_vertex, cap_vertex], [resistor_edge])
146+
```
147+
148+
We can see, that NetworkDynamics internally is able to reduce all of the "output" states. We end up with a plain ODE of a single state.
149+
150+
Now we can simulate the system. For that we generate the `u0` object. Since the metadata (such as default values) was automatically transferred, we can straight away construct the `ODEProblem`
151+
and solve the system.
152+
153+
```@example mtk
154+
u0 = NWState(nw) # generate state based on default values
155+
prob = ODEProblem(nw, uflat(u0), (0, 10.0), pflat(u0))
156+
sol = solve(prob, Tsit5())
157+
158+
# plot the solution
159+
fig, ax1, p = plot(sol; idxs=VIndex(:cap, :p₊v), label="Capacitor Voltage");
160+
axislegend(ax1)
161+
ax2 = Axis(fig[2,1])
162+
plot!(ax2, sol; idxs=VIndex(:vs, :i), label="Current produced by ideal v source")
163+
axislegend(ax2)
164+
fig # hide
165+
```
166+

0 commit comments

Comments
 (0)