Skip to content

Commit 606a043

Browse files
Merge pull request #3519 from AayushSabharwal/as/latexify-ap
feat: add latexify recipe for `AnalysisPoint`
2 parents 3986d82 + b96c611 commit 606a043

File tree

5 files changed

+59
-12
lines changed

5 files changed

+59
-12
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ StochasticDelayDiffEq = "1.8.1"
151151
StochasticDiffEq = "6.72.1"
152152
SymbolicIndexingInterface = "0.3.37"
153153
SymbolicUtils = "3.14"
154-
Symbolics = "6.29.2"
154+
Symbolics = "6.36"
155155
URIs = "1"
156156
UnPack = "0.1, 1.0"
157157
Unitful = "1.1"

docs/src/tutorials/attractors.md

+15-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Hence the "nonlocal-" component.
1414
More differences and pros & cons are discussed in the documentation of Attractors.jl.
1515

1616
!!! note "Attractors and basins"
17+
1718
This tutorial assumes that you have some familiarity with dynamical systems,
1819
specifically what are attractors and basins of attraction. If you don't have
1920
this yet, we recommend Chapter 1 of the textbook
@@ -27,13 +28,13 @@ Let's showcase this framework by modelling a chaotic bistable dynamical system t
2728
using ModelingToolkit
2829
using ModelingToolkit: t_nounits as t, D_nounits as D
2930
30-
@variables x(t) = -4.0 y(t) = 5.0 z(t) = 0.0
31-
@parameters a = 5.0 b = 0.1
31+
@variables x(t)=-4.0 y(t)=5.0 z(t)=0.0
32+
@parameters a=5.0 b=0.1
3233
3334
eqs = [
3435
D(x) ~ y - x,
35-
D(y) ~ - x*z + b*abs(z),
36-
D(z) ~ x*y - a,
36+
D(y) ~ -x * z + b * abs(z),
37+
D(z) ~ x * y - a
3738
]
3839
```
3940

@@ -74,7 +75,7 @@ To use this technique, we first need to create a tessellation of the state space
7475
grid = (
7576
range(-15.0, 15.0; length = 150), # x
7677
range(-20.0, 20.0; length = 150), # y
77-
range(-20.0, 20.0; length = 150), # z
78+
range(-20.0, 20.0; length = 150) # z
7879
)
7980
```
8081

@@ -83,9 +84,10 @@ which we then give as input to the `AttractorsViaRecurrences` mapper along with
8384
```@example Attractors
8485
mapper = AttractorsViaRecurrences(ds, grid;
8586
consecutive_recurrences = 1000,
86-
consecutive_lost_steps = 100,
87+
consecutive_lost_steps = 100
8788
)
8889
```
90+
8991
to learn about the metaparameters of the algorithm visit the documentation of Attractors.jl.
9092

9193
This `mapper` object is incredibly powerful! It can be used to map initial conditions to attractor they converge to, while ensuring that initial conditions that converge to the same attractor are given the same label.
@@ -120,7 +122,7 @@ This is a dictionary that maps attractor IDs to the attractor sets themselves.
120122
```@example Attractors
121123
using CairoMakie
122124
fig = Figure()
123-
ax = Axis(fig[1,1])
125+
ax = Axis(fig[1, 1])
124126
colors = ["#7143E0", "#191E44"]
125127
for (id, A) in attractors
126128
scatter!(ax, A[:, [1, 3]]; color = colors[id])
@@ -130,8 +132,8 @@ fig
130132

131133
## Basins of attraction
132134

133-
Estimating the basins of attraction of these attractors is a matter of a couple lines of code.
134-
First we define the state space are to estimate the basins for.
135+
Estimating the basins of attraction of these attractors is a matter of a couple lines of code.
136+
First we define the state space are to estimate the basins for.
135137
Here we can re-use the `grid` we defined above. Then we only have to call
136138

137139
```julia
@@ -141,8 +143,9 @@ basins = basins_of_attraction(mapper, grid)
141143
We won't run this in this tutorial because it is a length computation (150×150×150).
142144
We will however estimate a slice of the 3D basins of attraction.
143145
DynamicalSystems.jl allows for a rather straightforward setting of initial conditions:
146+
144147
```@example Attractors
145-
ics = [Dict(:x => x, :y => 0, :z=>z) for x in grid[1] for z in grid[3]]
148+
ics = [Dict(:x => x, :y => 0, :z => z) for x in grid[1] for z in grid[3]]
146149
```
147150

148151
now we can estimate the basins of attraction on a slice on the x-z grid
@@ -186,6 +189,7 @@ params(θ) = [:a => 5 + 0.5cos(θ), :b => 0.1 + 0.01sin(θ)]
186189
θs = range(0, 2π; length = 101)
187190
pcurve = params.(θs)
188191
```
192+
189193
which makes an ellipsis over the parameter space.
190194

191195
We put these three ingredients together to call the global continuation
@@ -198,7 +202,7 @@ The output of the continuation is how the attractors and their basins fractions
198202

199203
```@example Attractors
200204
fig = plot_basins_attractors_curves(
201-
fractions_cont, attractors_cont, A -> minimum(A[:, 1]), θs,
205+
fractions_cont, attractors_cont, A -> minimum(A[:, 1]), θs
202206
)
203207
```
204208

src/systems/analysis_points.jl

+13
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ function Base.show(io::IO, ::MIME"text/plain", ap::AnalysisPoint)
140140
end
141141
end
142142

143+
@latexrecipe function f(ap::AnalysisPoint)
144+
index --> :subscript
145+
snakecase --> true
146+
ap.input === nothing && return 0
147+
outs = Expr(:vect)
148+
append!(outs.args, ap_var.(ap.outputs))
149+
return Expr(:call, :AnalysisPoint, ap_var(ap.input), ap.name, outs)
150+
end
151+
152+
function Base.show(io::IO, ::MIME"text/latex", ap::AnalysisPoint)
153+
print(io, latexify(ap))
154+
end
155+
143156
"""
144157
$(TYPEDSIGNATURES)
145158

test/latexify.jl

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ using Latexify
33
using ModelingToolkit
44
using ReferenceTests
55
using ModelingToolkit: t_nounits as t, D_nounits as D
6+
using ModelingToolkitStandardLibrary.Blocks
67

78
### Tips for generating latex tests:
89
### Latexify has an unexported macro:
@@ -47,3 +48,13 @@ eqs = [D(u[1]) ~ p[3] * (u[2] - u[1]),
4748
eqs = [D(x) ~ (1 + cos(t)) / (1 + 2 * x)]
4849

4950
@test_reference "latexify/40.tex" latexify(eqs)
51+
52+
@named P = FirstOrder(k = 1, T = 1)
53+
@named C = Gain(; k = -1)
54+
55+
ap = AnalysisPoint(:plant_input)
56+
eqs = [connect(P.output, C.input)
57+
connect(C.output, ap, P.input)]
58+
sys_ap = ODESystem(eqs, t, systems = [P, C], name = :hej)
59+
60+
@test_reference "latexify/50.tex" latexify(sys_ap)

test/latexify/50.tex

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
\begin{equation}
2+
\left[
3+
\begin{array}{c}
4+
\mathrm{connect}\left( P_{+}output, C_{+}input \right) \\
5+
AnalysisPoint\left( \mathtt{C.output.u}\left( t \right), plant\_input, \left[
6+
\begin{array}{c}
7+
\mathtt{P.input.u}\left( t \right) \\
8+
\end{array}
9+
\right] \right) \\
10+
\mathtt{P.u}\left( t \right) = \mathtt{P.input.u}\left( t \right) \\
11+
\mathtt{P.y}\left( t \right) = \mathtt{P.output.u}\left( t \right) \\
12+
\mathtt{P.y}\left( t \right) = \mathtt{P.x}\left( t \right) \\
13+
\frac{\mathrm{d} \mathtt{P.x}\left( t \right)}{\mathrm{d}t} = \frac{ - \mathtt{P.x}\left( t \right) + \mathtt{P.k} \mathtt{P.u}\left( t \right)}{\mathtt{P.T}} \\
14+
\mathtt{C.u}\left( t \right) = \mathtt{C.input.u}\left( t \right) \\
15+
\mathtt{C.y}\left( t \right) = \mathtt{C.output.u}\left( t \right) \\
16+
\mathtt{C.y}\left( t \right) = \mathtt{C.k} \mathtt{C.u}\left( t \right) \\
17+
\end{array}
18+
\right]
19+
\end{equation}

0 commit comments

Comments
 (0)