Skip to content

Commit 5dda53f

Browse files
author
unknown
committed
improved readability
1 parent 95d809e commit 5dda53f

File tree

1 file changed

+98
-72
lines changed

1 file changed

+98
-72
lines changed

docs/src/mathematical_model.md

Lines changed: 98 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@
22

33
The core of the `NetworkDynamics.jl` package is the [`Network`](@ref) function. It accepts the functions describing the
44
local dynamics on the edges and nodes of the graph `g` as inputs, and returns a composite function compatible with the
5-
DifferentialEquations.jl syntax.
5+
DifferentialEquations.jl syntax as output.
66

77
```julia
88
nd = Network(g, vertex_dynamics, edge_dynamics)
99
nd(dx, x, p, t)
1010
```
1111

12-
The local dynamics on the edges and nodes of the graph can be described through the use of (a) algebraic equations,
13-
(b) differential algebraic equation (DAEs) in mass matrix form or (c) ordinary differential equations (ODE).
14-
12+
In general the local dynamics on the edges and nodes of a graph can be described through the use of (a) algebraic
13+
equations, (b) differential algebraic equation (DAEs) in mass matrix form or (c) ordinary differential equations (ODE).
1514
The `NetworkDynamics.jl` package uses
16-
[Differential-Algebraic-Equation (DAE)](https://mathworld.wolfram.com/Differential-AlgebraicEquation.html)
17-
to express the overall network dynamics:
15+
[Differential-Algebraic-Equation (DAE)](https://mathworld.wolfram.com/Differential-AlgebraicEquation.html) to express
16+
the overall network dynamics:
1817
```math
1918
M\,\frac{\mathrm{d}}{\mathrm{d}t}u = f^{\mathrm{nw}}(u, p, t)
2019
```
2120
where $M$ is a (possibly singular) mass matrix, $u$ is the internal state vector of the system, $p$ are the parameters
2221
and $t$ is the time. To make this compatible with the solvers used in `OrdinaryDiffEq.jl`, the generated
23-
[`Network`](@ref) object is a callable object:
22+
[`Network`](@ref) object is callable
2423
```
2524
nw(du, u, p, t) # mutates du as an "output"
2625
```
27-
which represents the right-hand-side (RHS) of the equation above. The mass-matrix $m$ is stored in the `Network` object
26+
and represents the right-hand-side (RHS) of the equation above. The mass-matrix $m$ is stored in the `Network` object
2827
as well.
2928

29+
## Modelling the Dynamics of the System
3030
Each component model $\mathrm c$ is modeled as a general input-output-system:
3131
```math
3232
\begin{aligned}
@@ -40,8 +40,8 @@ $\mathrm{dim}(x^{\mathrm{c}}) = 0$, the number of internal states is 0.
4040

4141
The mathematical model of `NetworkDynamics.jl` splits the network system in two parts: the vertex and
4242
the edge components (the nodes and edges, respectively). Instead of defining the $f^{\mathrm{nw}}$ by hand, `ND.jl`
43-
builds it automatically based on a list of decentralized nodal and edge dynamics that the user provides (
44-
the so-called `VertexModel` and `EdgeModel` objects).
43+
builds it automatically based on a list of decentralized nodal and edge dynamics that the user provides (the
44+
`VertexModel` and `EdgeModel` objects).
4545

4646
In the context of the network, the **output of the edges are flow variables** and the **outputs of vertices are
4747
potential variables**. When the node and edge models are placed on a graph, the inputs and outputs are connected:
@@ -50,35 +50,27 @@ inputs. Thus, the *flow* on the edges depends on the *potentials* at both ends a
5050
depend on the incoming *flows* from all connected edges as an input. (Here, flow and potentials are meant in a
5151
conceptional and not necessarily physical way.)
5252

53+
In this graphical representation of a partial network graph
5354
```@raw html
5455
<img src="../assets/mathmodel.svg" width="100% height="100%"/>
5556
```
56-
Figure 2: Here part of a network is shown. Three nodes are visible (node1, node 2 and node3) as well as the edges
57-
connecting node1 and node2 ($e_12$, $e_21$). Above the network, the mass matrix equations on node1 and node2
58-
($M_{\mathrm{c}}x^{\mathrm c}$), the equations on the connecting edges ($e_12$, $e_21$), as well as the internal
59-
state vector equations of node1 and node2($u_1$ and $u_2$) are also shown.
60-
(@Hans: this graphic looks black with dark letter for the most part in some browsers. It may be a better idea to add
61-
a white background to it)
57+
three nodes are visible (node 1, node 2 and node 3) as well as the edges connecting node 1 and node 2 ($e_{\mathrm 12}$,
58+
$e_{\mathrm 21}$). Above the network, the mass matrix equations on node 1 and node 2 ($M_{\mathrm{c}} x_{\mathrm c}$),
59+
the equations on the connecting edges ($e_{\mathrm 12}$, $e_{\mathrm 21}$), as well as the internal state vector
60+
equations of node1 and node2 ($u_1$ and $u_2$) are also shown.
6261

63-
## Vertex Models
64-
A (single-layer) vertex model has one input, and one output.
65-
The input is an aggregation/reduction over all of the *incident edge outputs*:
66-
```math
67-
i^{\mathrm v} = \mathop{\mathrm{agg}}\limits_k^{\text{incident}} y^{\mathrm e}_k \qquad\text{often}\qquad
68-
i^{\mathrm v} = \sum_k^{\text{incident}} y^{\mathrm e}_k
69-
```
70-
```@raw html
71-
<img src="../assets/nodemodel.svg" width="100% style="red"/>
72-
```
62+
(@Hans: the .svg graphics in this page looks black with dark letters for the most part in some browsers (e.g. firefox,
63+
duckduckgo). I tried to add a white background to them, but it does not seem to have worked)
7364

74-
The full vertex model
65+
### Vertex Models
66+
The equations of a (single-layer) full vertex model are:
7567
```math
7668
\begin{aligned}
7769
M^{\mathrm v}\,\frac{\mathrm{d}}{\mathrm{d}t}x^{\mathrm v} &= f^{\mathrm v}(x^{\mathrm v}, i^{\mathrm v}, p^{\mathrm v}, t)\\
7870
y^{\mathrm v} &= g^{\mathrm v}(x^{\mathrm v}, i^{\mathrm v}, p^{\mathrm v}, t)
7971
\end{aligned}
8072
```
81-
corresponds to the Julia functions
73+
and they correspond to the Julia functions:
8274
```julia
8375
function fᵥ(dxᵥ, xᵥ, e_aggr, pᵥ, t)
8476
# mutate dxᵥ
@@ -91,36 +83,44 @@ end
9183
vertf = VertexModel(; f=fᵥ, g=gᵥ, mass_matrix=Mᵥ, ...)
9284
```
9385

94-
## Edge Models
95-
In contrast to vertex models, edge models in general have *two* inputs and *two* outputs, for both the source and the
96-
destination end of the edge. We commonly use `src` and `dst` to describe the source and destination end of an edge,
97-
respectively.
86+
A (single-layer) full vertex model has one input, and one output. Its input is an aggregation/reduction over all the
87+
*incident edge outputs* which is calculated using:
88+
```math
89+
i^{\mathrm v} = \mathop{\mathrm{agg}}\limits_k^{\text{incident}} y^{\mathrm e}_k \qquad\text{often}\qquad
90+
i^{\mathrm v} = \sum_k^{\text{incident}} y^{\mathrm e}_k
91+
```
9892

99-
The *inputs* of the edge are the outputs of the two nodes at both their ends. The output is split into two parts:
100-
the `dst` output goes to the input of the vertex at the destination end, the `src` output goes to the input of the
101-
vertex at the `src` end.
93+
The graphical representation of such a model is:
94+
```@raw html
95+
<img src="../assets/nodemodel.svg" width="70% height="70%"/>
96+
```
97+
where $y^e_i$ and $y^e_j$ are two of the $n$ incident edge outputs that are aggregated to produce the model input
98+
$i^u$ and the model output $y^v$ (the vertex model output).
10299

103-
For undirected graphs, `Graphs.jl` chooses the direction of an edge `v1->v2` such that `v1 < v2`, i.e. the edge between
104-
vertices 16 and 12 will be always an edge with source `src=12` and destination `dst=16`.
100+
101+
### Edge Models
102+
In contrast to the vertex models, edge models in general have *two* inputs and *two* outputs, for both the source and
103+
the destination end of the edge. We commonly use `src` and `dst` to describe the source and destination end of an edge,
104+
respectively.
105105

106-
!!! note "On the directionality of edges"
107-
Mathematically, in a system defined on an undirected graph there is no difference between edge $(1,2)$ and
108-
edge $(2,1)$, because the edge has no direction. However, from an implementation point of view we always need to have
109-
some kind of ordering, which is why we introduce the source and destination terminology.
106+
!!! note "Source and Destination definitions "
107+
A source node (`src`) is the node from which the flow exits.
108+
A destination node (`dst`) is the node into which the flow enters.
110109

111-
```@raw html
112-
<img src="../assets/edgemodel.svg" width="100%"/>
113-
```
110+
!!! note "On the directionality of edges"
111+
Mathematically, in a system defined on an undirected graph there is no difference between edge $(1,2)$ and
112+
edge $(2,1)$, because the edge has no direction. However, from an implementation point of view we always need to
113+
have some kind of ordering, which is why we introduce the source (`src`) and destination (`dst`) terminology.
114114

115-
The full model of an edge
115+
The full edge model equations are:
116116
```math
117117
\begin{aligned}
118118
M^{\mathrm e}\,\frac{\mathrm{d}}{\mathrm{d}t}x^{\mathrm e} &= f^{\mathrm e}(u^{\mathrm e}, y^{\mathrm v}_{\mathrm{src}}, y^{\mathrm v}_{\mathrm{dst}}, p^{\mathrm e}, t)\\
119119
y^{\mathrm e}_{\mathrm{dst}} &= g_\mathrm{dst}^{\mathrm e}(u^{\mathrm e}, y^{\mathrm v}_{\mathrm{src}}, y^{\mathrm v}_{\mathrm{dst}}, p^{\mathrm e}, t)\\
120120
y^{\mathrm e}_{\mathrm{src}} &= g_\mathrm{src}^{\mathrm e}(u^{\mathrm e}, y^{\mathrm v}_{\mathrm{src}}, y^{\mathrm v}_{\mathrm{dst}}, p^{\mathrm e}, t)
121121
\end{aligned}
122122
```
123-
which corresponds to the Julia functions:
123+
and they correspond to the Julia functions:
124124
```julia
125125
function fₑ(dxₑ, xₑ, v_src, v_dst, pₑ, t)
126126
# mutate dxᵥ
@@ -133,40 +133,68 @@ end
133133
vertf = EdgeModel(; f=fₑ, g=gₑ, mass_matrix=Mₑ, ...)
134134
```
135135

136-
The sign convention for both outputs of an edge must be identical, so typically, a positive flow represents a flow
137-
*into* the connected vertex. This is important, because the vertex only receives the flows, it does not know whether
138-
the flow was produced by the source or the destination end of an edge.
139-
```
140-
y_src y_dst
141-
V_src o───←─────────→───o V_dst
136+
The *inputs* of an edge connecting two nodes are the *outputs* of the nodes at both their ends. The output of each node
137+
is split into two parts:
138+
1. the *`dst`* output which is used as the input of the vertex at the destination end
139+
2. the `src` output which is used as the input of the vertex at the `src` end.
140+
141+
Because a Vertex only receives flows from the edges connected to it, it does not know whether the flow it
142+
received was produced by the source or the destination end of an edge. To solve this problem a sign convention has been
143+
introduced. A positive flow represents a flow *into* the connected vertex, while a negative flow represents a flow *out*
144+
of the connected vertex.
142145

146+
When we consider $n_1$ as the source and $n_2$ as the destination, flows out of $n_1$ and into $n_2$ are negative,
147+
so $y_dst < 0$. Whereas flows out of $n_2$ and into $n_1$ are positive, so $y_src > 0$.
143148
```
149+
y_dst < 0
150+
n_1 (src) o───────→────────o n_2 (dst)
151+
y_src > 0
152+
n_1 (src) o───────←────────o n_2 (dst)
153+
```
154+
But when we consider $n_2$ as the source and $n_1$ as the destination, flows out of $n_2$ and into $n_1$ are negative,
155+
so $y_dst < 0$. Whereas flows out of $n_1$ and into $n_2$ are positive, so $y_src > 0$.
156+
```
157+
y_src > 0
158+
$n_1$ (dst) o───────→────────o $n_2$ (src)
159+
y_dst < 0
160+
$n_1$ (dst) o───────→────────o $n_2$ (src)
161+
```
162+
163+
For undirected graphs, `Graphs.jl` chooses the direction of an edge (so which node is the `src` and which the `dst`)
164+
$v_1->v_2$ such that $v_1 < v_2$, so the edge between vertices 16 and 12 will always be an edge with source
165+
`src=12` and destination `dst=16`.
166+
144167

145168

146169
### Single Sided Edge Outputs
147-
Often, edge outputs will possess some symmetry. This makes it more convenient to define
148-
"single sided" edge output functions:
170+
To simplify the calculations, we split the output flows of edges into "single sided" edge output functions. That way we
171+
can split the output flows of edges into "single sided" edge output functions which simplifies the calculations:
149172
```julia
150173
function g_single(y, xᵥ, v_src, v_dst, pₑ, t)
151174
# mutate y
152175
nothing
153176
end
154177
```
155-
There are multiple wrappers available to automatically convert them into double-sided edge
156-
output functions:
157178

179+
There are multiple wrappers available to automatically convert them into double-sided edge output functions:
158180
- `Directed(g_single)` builds a double-sided function *which only couples* to the destination side.
159181
- `Symmetric(g_single)` builds a double-sided function in which both ends receive `y`.
160182
- `AntiSymmetric(g_single)` builds a double-sided function where the destination receives `y` and the source receives `-y`.
161183
- `Fiducial(g_single_src, g_singl_dst)` builds a double-sided edge output function based on two single sided functions.
162184

185+
163186
## Feed Forward Behavior
164-
Component models can show have so-called feed forward behavior. Feed forward means, that there is a direct link from input to output.
187+
!!! warning "Feed Forward Vertices"
188+
As of 11/2024, vertices with feed forward behaviour (FF) are not supported at all. Use [`ff_to_constraint`](@ref) to
189+
transform them into vertex models without FF.
165190

166-
The most generic version of the component models can contain direct feed forwards from the input to the output.
167-
This means, the output function depends $g$ directly depends on the component inputs $i$ and not only on the component state $x$.
191+
Component models can have a so-called Feed Forward behaviour, which provides a direct link between the input and the
192+
output.
168193

169-
Whenever possible, you should define output functions without feed forwards, i.e.
194+
The most generic version of the component models can contain direct FFs from the input to the output. This means that
195+
the output function $g$ depends directly on the component inputs $i$ rather than just on the component state $x$.
196+
197+
Whenever possible, you should define output functions without FFs in the following way:
170198
```julia
171199
gᵥ_noff(yᵥ, xᵥ, pᵥ, t)
172200
gₑ_noff([y_src,] y_dst, xᵥ, pₑ, t)
@@ -177,20 +205,17 @@ gᵥ(yᵥ, xᵥ, e_aggr, pᵥ, t)
177205
gₑ([y_src], y_dst, xᵥ, v_src, v_dst, pₑ, t)
178206
```
179207

180-
NetworkDynamics cannot couple two components with feed forward to each other.
181-
But, it is always possible to transform feed forward behavior to an internal state `x` with mass matrix entry zero to
182-
circumvent this problem. This transformation can be performed automatically by using [`ff_to_constraint`](@ref).
183-
208+
NetworkDynamics cannot couple two components with FFs to each other. But, it is always possible to transform
209+
feed forward behaviour to an internal state `x` with mass matrix entry zero to circumvent this problem. This
210+
transformation can be performed automatically using [`ff_to_constraint`](@ref).
184211

185-
!!! warning "Feed Forward Vertices"
186-
As of 11/2024, vertices with feed forward are not supported at all. Use [`ff_to_constraint`](@ref) to transform them
187-
into vertex model without FF.
188-
189-
Concretely, NetworkDynamics distinguishes between 4 types of feed forward behaviors of `g` functions based on the
212+
Concretely, NetworkDynamics distinguishes between 4 types of feed forward behaviours of `g` functions based on the
190213
[`FeedForwardType`](@ref) trait.
191-
The feed forward type is inferred automatically based on the provided function `g`, more concretely it is determined by the signature of that method / the number of arguments it takes.
214+
The feed forward type is inferred automatically based on the provided function `g` (by calculating the signature of the
215+
methods used over the number of arguments it is given.)
216+
217+
The code bloke below presents the different `g` signatures for the different feed forward types:
192218

193-
The code blow shows the different `g` signatures for the different feed forward types
194219
**[`PureFeedForward()`](@ref)**
195220
```julia
196221
g!(outs..., ins..., p, t) # abstractly
@@ -220,4 +245,5 @@ g!(out_src, out_dst, x) # double-sided edge
220245
g!(v_out, x) # single layer vertex
221246
```
222247

223-
If the automatic inference of feed forward type fails, the user may specify it explicitly using the `ff` keyword argument of the Edge/VertexModel constructor.
248+
If the automatic inference of feed forward type fails, the user may specify it explicitly using the `ff` keyword
249+
argument of the Edge/VertexModel constructor.

0 commit comments

Comments
 (0)