Skip to content

Commit 82f04d4

Browse files
committed
extend for vector valued obsex
also add docs
1 parent 99c1577 commit 82f04d4

File tree

5 files changed

+49
-11
lines changed

5 files changed

+49
-11
lines changed

docs/src/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ VIndex
8282
EIndex
8383
VPIndex
8484
EPIndex
85+
@obsex
8586
```
8687

8788
### Index generators

docs/src/symbolic_indexing.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,20 @@ Observables can be accessed like any other state, for example, the flows in the
114114
```@example si
115115
plot(sol; idxs=eidxs(nw, :, :flow))
116116
```
117+
118+
## Derived `ObservableExpressions` using `@obsex`
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.
122+
123+
For example, we can directly plot the storage difference with respect to storage of node 1.
124+
125+
```@example si
126+
plot(sol; idxs=@obsex(vidxs(nw,:,:storage) .- VIndex(1,:storage)))
127+
```
128+
129+
Other examples are the calculation of magnitude and argument of complex values which are modeld in real and imaginary part.
130+
```
131+
@obsex mag = sqrt(VIndex(1, :u_r)^2 + VIndex(2, :u_i)^2)
132+
```
133+

ext/SymbolicsExt.jl

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,38 @@ function NetworkDynamics.generate_observable_expression(ex::Expr)
1515
# manually hygen on "mapping", otherwise we cannot escape x
1616
mapping_sym = gensym("mapping")
1717
symbolic_expr = postwalk(content) do x
18-
:(NetworkDynamics.collect_symbol!($mapping_sym, $x))
18+
if x (:+, :-, :^, :/, :.+, :.-, :.^, :./, Symbol(":")) || x isa QuoteNode
19+
x
20+
else
21+
:(NetworkDynamics.collect_symbol!($mapping_sym, $x))
22+
end
1923
end
2024
quote
2125
$(esc(mapping_sym)) = Dict()
2226
expr = $(esc(symbolic_expr))
23-
ObservableExpression($(esc(mapping_sym)), expr, $(Meta.quot(name)))
27+
NetworkDynamics.ObservableExpression($(esc(mapping_sym)), expr, $(Meta.quot(name)))
2428
end
2529
end
2630

31+
function NetworkDynamics.ObservableExpression(mapping, expr::Vector, names)
32+
if names isa Symbol
33+
names = [Symbol(names, NetworkDynamics.subscript(i)) for i in 1:length(expr)]
34+
elseif isnothing(names)
35+
names = Iterators.repeated(nothing, length(expr))
36+
end
37+
[NetworkDynamics.ObservableExpression(mapping, e, n) for (e, n) in zip(expr, names)]
38+
end
39+
2740
function NetworkDynamics.ObservableExpression(mapping, expr, name)
2841
nwidx = collect(keys(mapping))
2942
syms = collect(values(mapping))
3043
f = Symbolics.build_function(expr, syms; expression=Val(false))
31-
ObservableExpression(nwidx, f, expr, name)
44+
NetworkDynamics.ObservableExpression(nwidx, f, expr, name)
3245
end
3346

3447
NetworkDynamics.collect_symbol!(_, x) = x
35-
function NetworkDynamics.collect_symbol!(mapping, x::AbstractVector)
36-
if length(x) == 1 && only(x) isa Union{SymbolicVertexIndex,SymbolicEdgeIndex}
37-
return NetworkDynamics.collect_symbol!(mapping, only(x))
38-
elseif any(el -> el isa Union{SymbolicVertexIndex,SymbolicEdgeIndex}, x)
39-
throw(ArgumentError("Cannot handle vector expressions in @obsex! Encountered $x."))
40-
else
41-
x
42-
end
48+
function NetworkDynamics.collect_symbol!(mapping, x::Union{AbstractVector, Tuple})
49+
map(el -> NetworkDynamics.collect_symbol!(mapping, el), x)
4350
end
4451
function NetworkDynamics.collect_symbol!(mapping, nwindex::Union{SymbolicVertexIndex,SymbolicEdgeIndex})
4552
if haskey(mapping, nwindex)

src/symbolicindexing.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,15 @@ function SII.observed(nw::Network, obsex::ObservableExpression)
11481148
obsex.f(input)
11491149
end
11501150
end
1151+
function SII.observed(nw::Network, obsexs::AbstractVector{<:ObservableExpression})
1152+
inputfs = map(obsex -> SII.observed(nw, obsex.inputs), obsexs)
1153+
(u, p, t) -> begin
1154+
map(obsexs, inputfs) do obsex, inputf
1155+
input = inputf(u, p, t)
1156+
obsex.f(input)
1157+
end
1158+
end
1159+
end
11511160

11521161
Base.getindex(s::NWState, idx::ObservableExpression) = SII.getu(s, idx)(s)
11531162
Base.getindex(s::NWParameter, idx::ObservableExpression) = SII.getp(s, idx)(s)

test/symbolicindexing_test.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,4 +505,8 @@ end
505505

506506
@test SII.getname(@obsex(VIndex(1,) + VIndex(2,))) == Symbol("v1₊δ+v2₊δ")
507507
@test SII.getname(@obsex(δ²=VIndex(1,)^2)) == :δ²
508+
509+
@test s[@obsex(vidxs(s, :, ) .- VIndex(1, ))] == [0, s[VIndex(2,)] - s[VIndex(1,)], s[VIndex(3,)] - s[VIndex(1,)]]
510+
511+
obsex = @obsex(δ_rel = vidxs(s, :, ) .- VIndex(1, ))
508512
end

0 commit comments

Comments
 (0)