1
1
# Symbolic Indexing
2
2
3
- Using SciML's [ ` SymblicIndexingInterface .jl` ] ( https://github.com/SciML/SymbolicIndexingInterface.jl ) , ` ND.jl ` provides lots of methods to access and change variables and Parameters .
3
+ Using SciML's [ ` SymbolicIndexingInterface .jl` ] ( https://github.com/SciML/SymbolicIndexingInterface.jl ) , ` ND.jl ` provides numerous methods to access and change variables and parameters .
4
4
5
5
!!! details "Setup code to make following examples work"
6
6
```@example si
@@ -11,7 +11,7 @@ Using SciML's [`SymblicIndexingInterface.jl`](https://github.com/SciML/SymbolicI
11
11
```
12
12
13
13
## Provide Symbol Names
14
- When construction component models, you can pass symbolic names using the ` sym ` and ` psym ` keywords.
14
+ When constructing component models, you can pass symbolic names using the ` sym ` and ` psym ` keywords.
15
15
``` @example si
16
16
function _edgef!(e, v_s, v_d, (K,), t)
17
17
e .= K * (v_s[1] .- v_d[1])
@@ -28,9 +28,9 @@ vertexf = VertexModel(f=_vertexf!, g=1, sym=[:storage])
28
28
```
29
29
30
30
31
- ## Fundamental Symblic Indices
31
+ ## Fundamental Symbolic Indices
32
32
The default types for this access are the types [ ` VIndex ` ] ( @ref ) , [ ` EIndex ` ] ( @ref ) , [ ` VPIndex ` ] ( @ref ) and [ ` EPIndex ` ] ( @ref ) .
33
- Each of those symbolic indices consists of 2 elements: a reference to the network componen and a reference to the symbol within that component.
33
+ Each of those symbolic indices consists of 2 elements: a reference to the network component and a reference to the symbol within that component.
34
34
As such, ` VIndex(2, :x) ` refers to variable with symbolic name ` :x ` in vertex number 2.
35
35
` EPIndex(4, 2) ` would refer to the * second* parameter of the edge component for the 4th edge.
36
36
@@ -56,7 +56,7 @@ Often, you need many individual symbolic indices. For that there are the helper
56
56
With the help of those methods you can generate arrays of symbolic indices:
57
57
58
58
``` @example si
59
- vidxs(nw, :, :storage) # get variable "storage" for all nodes
59
+ vidxs(nw, :, :storage) # get variable "storage" for all vertices
60
60
```
61
61
``` @example si
62
62
plot(sol; idxs=vidxs(nw, :, :storage))
@@ -70,7 +70,7 @@ p = NWParameter(nw)
70
70
```
71
71
creates a ` NWParameter ` object for the network ` nw ` .
72
72
It essentially creates a new flat parameter array and fills it with the default parameter values define in the component.
73
- The parameters in the ` NWParameter ` object can be accessed using the symbolic indices.
73
+ The parameters in the ` NWParameter ` object can be accessed using symbolic indices.
74
74
``` @example si
75
75
p[EPIndex(5, :K)] = 2.0 # change the parameter K of the 5th edge
76
76
nothing #hide
@@ -79,20 +79,20 @@ Similarly, you can create a `NWState` object for the network `nw` using
79
79
``` @example si
80
80
s = NWState(nw)
81
81
```
82
- No default values were provided in the network components, so the state array is filled with ` NaN ` s .
82
+ No default values were provided in the network components, so the state array is filled with ` NaN ` values .
83
83
``` @example si
84
- s[VIndex(:, :storage)] .= randn(5) # set the (initial) storage for alle nodes
84
+ s[VIndex(:, :storage)] .= randn(5) # set the (initial) storage for all vertices
85
85
s #hide
86
86
```
87
- For both ` NWState ` and ` NWParameter ` objects, the there is a more convenient way to access the variables and parameters.
87
+ For both ` NWState ` and ` NWParameter ` objects, there is a more convenient way to access the variables and parameters.
88
88
``` @example si
89
89
@assert s.v[1, :storage] == s[VIndex(1, :storage)] # s.v -> access vertex states
90
90
@assert s.e[1, :flow] == s[EIndex(1, :flow)] # s.e -> access edge states
91
91
@assert s.p.e[1,:K] == p[EPIndex(1, :K)] # s.p -> access parameters
92
92
```
93
93
94
94
The ` NWState ` and ` NWParameter ` objects are mutable, thus changing them will also change the underlying wrapped flat arrays.
95
- You can allways access the flat representations by calling [ ` uflat ` ] ( @ref ) and [ ` pflat ` ] ( @ref ) .
95
+ You can always access the flat representations by calling [ ` uflat ` ] ( @ref ) and [ ` pflat ` ] ( @ref ) .
96
96
97
97
!!! note
98
98
The ` NWState ` and ` NWParameter ` wrappers can be constructed from various objects.
@@ -101,8 +101,8 @@ You can allways access the flat representations by calling [`uflat`](@ref) and [
101
101
102
102
## Observables
103
103
Sometimes, the "states" you're interested in aren't really states in the DAE sense but rather
104
- algebraic derivations from DAE states, parameters and time -- in accordance with the naming in
105
- the ` SciML ` - ecosystem those states are called Observables.
104
+ algebraic derivations from DAE states, parameters, and time -- in accordance with the naming in
105
+ the ` SciML ` ecosystem, these values are called Observables.
106
106
107
107
A prime example of Observables are edge/vertex-outputs, such as the ` flow ` in the edge model defined above.
108
108
It is also possible to define additional Observables manually by using the ` obssym ` and ` obsf ` keyword
@@ -117,17 +117,43 @@ plot(sol; idxs=eidxs(nw, :, :flow))
117
117
118
118
## Derived ` ObservableExpressions ` using ` @obsex `
119
119
120
- Sometimes it is usefull to plot or observe some simple derived quantity. For that,
121
- one can used the [ ` @obsex ` ] ( @ref ) macro, to define simple derived quantities.
120
+ Sometimes it is useful to plot or observe simple derived quantities. For that,
121
+ one can use the [ ` @obsex ` ] ( @ref ) macro to define simple derived quantities.
122
122
123
123
For example, we can directly plot the storage difference with respect to storage of node 1.
124
124
125
125
``` @example si
126
126
plot(sol; idxs=@obsex(vidxs(nw,:,:storage) .- VIndex(1,:storage)))
127
127
```
128
128
129
- Other examples are the calculation of magnitude and argument of complex values which are modeld in real and imaginary part .
129
+ Other examples include calculating the magnitude and argument of complex values that are modeled using real and imaginary parts .
130
130
```
131
131
@obsex mag = sqrt(VIndex(1, :u_r)^2 + VIndex(2, :u_i)^2)
132
132
```
133
133
134
+ ## Low-level accessors for flat array indices
135
+ Sometimes, you want to know the indices of your states in the flat arrays.
136
+ For that, you can use the low-level methods defined in ` SymbolicIndexingInterface.jl ` :
137
+
138
+ ``` @example si
139
+ using NetworkDynamics: SII # SII = SymbolicIndexingInterface
140
+ idxs = SII.variable_index(nw, vidxs(1:2, :storage))
141
+ ```
142
+ ``` @example si
143
+ uflat(s)[idxs] == s.v[1:2, :storage]
144
+ ```
145
+ Analogous with parmeters:
146
+ ``` @example si
147
+ idxs = SII.parameter_index(nw, eidxs(1:2, :K))
148
+ pflat(s)[idxs] == s.p.e[1:2, :K]
149
+ ```
150
+
151
+ If you need the symbols of all the states/parameters in order, you can use
152
+ ``` @example si
153
+ SII.variable_symbols(nw)
154
+ ```
155
+ and
156
+ ``` @example si
157
+ SII.parameter_symbols(nw)
158
+ ```
159
+ All above examples also work on other "symbolic containers", e.g. ` SII.variable_symbols(::NWState) ` .
0 commit comments