Skip to content

Commit 9126221

Browse files
authored
Add examples to the docs (#166)
* add two examples for construction * add complexe xample * better badges * pate docs
1 parent 1d86da1 commit 9126221

File tree

10 files changed

+219
-88
lines changed

10 files changed

+219
-88
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
docs/build
55
deps/build.log
66
Manifest.toml
7+
*style.jl
8+
*.scss
9+
*.css

CHANGELOG.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# v3.0
22

3-
Complete rewrite of the package. The DynamicalSystems.jl v3 changelog summarizes the highlights. Here we will try to list all changes, but it will be difficult to provide a changelog given that everything was changed.
3+
Complete rewrite of the package. The DynamicalSystems.jl v3 changelog summarizes the highlights. Here we will list all changes to _this specific package_.
4+
5+
## Majorly Breaking
6+
- The `Discrete/ContinuousDynamicalSystem` constructors no longer accept a Jacobian. Use the dedicated `TangentDynamicalSystem` for something that represents the tangent space and can be given to downstream functions such as `lyapunovspectrum`. As a result, none of the predefined systems come with a hand coded Jacobian. The function is still available for manual use nevertheless.
7+
- The keyword `diffeq` does not exist anymore and is not given to any downstream functions such as `lyapunovspectrum`. The only struct that cares about DifferentialEquations.jl arguments is `CoupledODEs` so it is the only one that accepts `diffeq` keyword.
8+
- `trajectory` now returns the actual trajectory _and_ the time vector: `X, t = trajectory(ds, ...)`.
49

510
## Enhancements
611
- `DynamicalSystem` now defines a proper, well-thought-out interface that is implemented from all its concrete subtypes. See its docstring for details.
@@ -16,10 +21,6 @@ Complete rewrite of the package. The DynamicalSystems.jl v3 changelog summarizes
1621
- `stroboscopicmap -> StroboscopicMap`
1722
- `poincaremap -> PoincareMap`
1823

19-
## Majorly Breaking
20-
- The `Discrete/ContinuousDynamicalSystem` constructors no longer accept a Jacobian. Use the dedicated `TangentDynamicalSystem` for something that represents the tangent space and can be given to downstream functions such as `lyapunovspectrum`. As a result, none of the predefined systems come with a hand coded Jacobian. The function is still available for manual use nevertheless.
21-
- The keyword `diffeq` does not exist anymore and is not given to any downstream functions such as `lyapunovspectrum`. The only struct that cares about DifferentialEquations.jl arguments is `CoupledODEs` so it is the only one that accepts `diffeq` keyword.
22-
- `trajectory` now returns the actual trajectory _and_ the time vector: `X, t = trajectory(ds, ...)`
2324

2425
# v2.9
2526
- All code related to the poincare map integrator have been moved here from ChaosTools.jl.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# DynamicalSystemsBase.jl
22

3-
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaDynamics.github.io/DynamicalSystemsBase.jl/dev)
4-
[![](https://img.shields.io/badge/DOI-10.1007/978-3-030-91032-7-purple)](https://link.springer.com/book/10.1007/978-3-030-91032-7)
3+
[![](https://img.shields.io/badge/docs-dev-lightblue.svg)](https://JuliaDynamics.github.io/DynamicalSystemsBase.jl/dev)
4+
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaDynamics.github.io/DynamicalSystemsBase.jl/stable)
5+
[![](https://img.shields.io/badge/DOI-10.1007%2F978--3--030--91032--7-purple)](https://link.springer.com/book/10.1007/978-3-030-91032-7)
56
[![CI](https://github.com/JuliaDynamics/DynamicalSystemsBase.jl/workflows/CI/badge.svg)](https://github.com/JuliaDynamics/DynamicalSystemsBase.jl/actions?query=workflow%3ACI)
67
[![codecov](https://codecov.io/gh/JuliaDynamics/DynamicalSystemsBase.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaDynamics/DynamicalSystemsBase.jl)
78
[![Package Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/DynamicalSystemsBase)](https://pkgs.genieframework.com?packages=DynamicalSystemsBase)

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
33
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
44
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"
55
DynamicalSystemsBase = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
6+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
67
StateSpaceSets = "40b095a5-5852-4c12-98c7-d43bf788e795"

docs/make.jl

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,26 @@
11
cd(@__DIR__)
2-
CI = get(ENV, "CI", nothing) == "true" || get(ENV, "GITHUB_TOKEN", nothing) !== nothing
3-
using DynamicalSystemsBase # comes from global environment in CI
4-
using Documenter
5-
using DocumenterTools: Themes
6-
ENV["JULIA_DEBUG"] = "Documenter"
7-
using CairoMakie
82

9-
# %% JuliaDynamics theme
10-
# It includes themeing for the HTML build
11-
# and themeing for the Makie plotting
12-
13-
using DocumenterTools: Themes
14-
for file in ("juliadynamics-lightdefs.scss", "juliadynamics-darkdefs.scss", "juliadynamics-style.scss")
15-
filepath = joinpath(@__DIR__, file)
16-
if !isfile(filepath)
17-
download("https://raw.githubusercontent.com/JuliaDynamics/doctheme/master/$file", joinpath(@__DIR__, file))
18-
end
19-
end
20-
# create the themes
21-
for w in ("light", "dark")
22-
header = read(joinpath(@__DIR__, "juliadynamics-style.scss"), String)
23-
theme = read(joinpath(@__DIR__, "juliadynamics-$(w)defs.scss"), String)
24-
write(joinpath(@__DIR__, "juliadynamics-$(w).scss"), header*"\n"*theme)
25-
end
26-
# compile the themes
27-
Themes.compile(joinpath(@__DIR__, "juliadynamics-light.scss"), joinpath(@__DIR__, "src/assets/themes/documenter-light.css"))
28-
Themes.compile(joinpath(@__DIR__, "juliadynamics-dark.scss"), joinpath(@__DIR__, "src/assets/themes/documenter-dark.css"))
3+
import Downloads
4+
Downloads.download(
5+
"https://raw.githubusercontent.com/JuliaDynamics/doctheme/master/apply_style.jl",
6+
joinpath(@__DIR__, "apply_style.jl")
7+
)
8+
include("apply_style.jl")
299

30-
# %% Build docs
31-
ENV["JULIA_DEBUG"] = "Documenter"
10+
using DynamicalSystemsBase
3211

3312
DYNAMICALSYSTEMSBASE_PAGES = [
3413
"index.md",
3514
]
3615
using DynamicalSystemsBase.SciMLBase
3716

38-
include("style.jl")
39-
4017
makedocs(
4118
modules = [DynamicalSystemsBase, SciMLBase, StateSpaceSets],
4219
format = Documenter.HTML(
4320
prettyurls = CI,
4421
assets = [
4522
asset("https://fonts.googleapis.com/css?family=Montserrat|Source+Code+Pro&display=swap", class=:css),
4623
],
47-
collapselevel = 3,
4824
),
4925
sitename = "DynamicalSystemsBase.jl",
5026
authors = "George Datseris",

docs/src/index.md

Lines changed: 196 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ current_crossing_time
5959
poincaresos
6060
```
6161

62+
## `TangentDynamicalSystem`
63+
```@docs
64+
CoreDynamicalSystem
65+
TangentDynamicalSystem
66+
current_deviations
67+
set_deviations!
68+
orthonormal
69+
```
70+
6271
## `ProjectedDynamicalSystem`
6372
```@docs
6473
ProjectedDynamicalSystem
@@ -71,21 +80,17 @@ initial_states
7180
current_states
7281
```
7382

74-
## `TangentDynamicalSystem`
83+
## `ArbitrarySteppable`
7584
```@docs
76-
CoreDynamicalSystem
77-
TangentDynamicalSystem
78-
current_deviations
79-
set_deviations!
80-
orthonormal
85+
ArbitrarySteppable
8186
```
8287

8388
## Parallelization
8489

85-
Since `DynamicalSystem`s are mutable, one needs to copy them before parallelizing, to avoid having to deal with complicated race conditions etc. The simplest way is with `deepcopy`. Here is an example block that shows how to parallelize calling some expensive function (e.g., calculating the Lyapunov exponent) over a parameter range:
90+
Since `DynamicalSystem`s are mutable, one needs to copy them before parallelizing, to avoid having to deal with complicated race conditions etc. The simplest way is with `deepcopy`. Here is an example block that shows how to parallelize calling some expensive function (e.g., calculating the Lyapunov exponent) over a parameter range using `Threads`:
8691

8792
```julia
88-
ds = DynamicalSystem(f, u, p)
93+
ds = DynamicalSystem(f, u, p) # some concrete implementation
8994
parameters = 0:0.01:1
9095
outputs = zeros(length(parameters))
9196

@@ -99,3 +104,186 @@ Threads.@threads for i in eachindex(parameters)
99104
outputs[i] = expensive_function(system, args...)
100105
end
101106
```
107+
108+
## Examples
109+
110+
### Iterated map, out of place
111+
112+
Let's make the [Hénon map](https://en.wikipedia.org/wiki/H%C3%A9non_map) as an example.
113+
114+
```@example MAIN
115+
using DynamicalSystemsBase
116+
117+
henon_rule(x, p, n) = SVector(1.0 - p[1]*x[1]^2 + x[2], p[2]*x[1])
118+
u0 = zeros(2)
119+
p0 = [1.4, 0.3]
120+
121+
henon = DeterministicIteratedMap(henon_rule, u0, p0)
122+
```
123+
124+
and get a trajectory
125+
126+
```@example MAIN
127+
X, t = trajectory(henon, 10000; Ttr = 100)
128+
X
129+
```
130+
131+
### Coupled ODEs, in place
132+
133+
Let's make the Lorenz system
134+
[Hénon map](https://en.wikipedia.org/wiki/H%C3%A9non_map) as an example.
135+
The system is small, and therefore should utilize the out of place syntax, but for the case of example, we will use the in-place syntax.
136+
We'll also use a high accuracy solver from OrdinaryDiffEq.jl.
137+
138+
```@example MAIN
139+
using DynamicalSystemsBase
140+
using OrdinaryDiffEq: Vern9
141+
142+
@inbounds function lorenz_rule!(du, u, p, t)
143+
σ = p[1]; ρ = p[2]; β = p[3]
144+
du[1] = σ*(u[2]-u[1])
145+
du[2] = u[1]*(ρ-u[3]) - u[2]
146+
du[3] = u[1]*u[2] - β*u[3]
147+
return nothing
148+
end
149+
150+
u0 = [0, 10.0, 0]
151+
p0 = [10, 28, 8/3]
152+
diffeq = (alg = Vern9(), abstol = 1e-9, reltol = 1e-9)
153+
154+
lorenz = CoupledODEs(lorenz_rule!, u0, p0; diffeq)
155+
```
156+
157+
and get a trajectory
158+
159+
```@example MAIN
160+
X, t = trajectory(lorenz, 1000; Δt = 0.05, Ttr = 10)
161+
X
162+
```
163+
164+
165+
### Advanced example
166+
This is an advanced example of making an in-place implementation of coupled [standard maps](https://en.wikipedia.org/wiki/Standard_map). It will utilize a handcoded Jacobian, a sparse matrix for the Jacobinan, a default initial Jacobian matrix, as well as function-like-objects as the dynamic rule.
167+
168+
Coupled standard maps is a deterministic iterated map that can have arbitrary number of equations of motion, since you can couple `N` standard maps which are 2D maps, like so:
169+
170+
```math
171+
\theta_{i}' = \theta_i + p_{i}' \\
172+
p_{i}' = p_i + k_i\sin(\theta_i) - \Gamma \left[\sin(\theta_{i+1} - \theta_{i}) + \sin(\theta_{i-1} - \theta_{i}) \right]
173+
```
174+
175+
To model this, we will make a dedicated `struct`, which is parameterized on the
176+
number of coupled maps:
177+
178+
```@example MAIN
179+
struct CoupledStandardMaps{N}
180+
idxs::SVector{N, Int}
181+
idxsm1::SVector{N, Int}
182+
idxsp1::SVector{N, Int}
183+
end
184+
```
185+
186+
(what these fields are will become apparent later)
187+
188+
We initialize the struct with the amount of standard maps we want to couple,
189+
and we also define appropriate parameters:
190+
191+
```@example MAIN
192+
M = 5 # couple number
193+
u0 = 0.001rand(2M) #initial state
194+
ks = 0.9ones(M) # nonlinearity parameters
195+
Γ = 1.0 # coupling strength
196+
p = (ks, Γ) # parameter container
197+
198+
# Create struct:
199+
SV = SVector{M, Int}
200+
idxs = SV(1:M...) # indexes of thetas
201+
idxsm1 = SV(circshift(idxs, +1)...) #indexes of thetas - 1
202+
idxsp1 = SV(circshift(idxs, -1)...) #indexes of thetas + 1
203+
# So that:
204+
# x[i] ≡ θᵢ
205+
# x[[idxsp1[i]]] ≡ θᵢ+₁
206+
# x[[idxsm1[i]]] ≡ θᵢ-₁
207+
csm = CoupledStandardMaps{M}(idxs, idxsm1, idxsp1)
208+
```
209+
210+
We will now use this struct to define a [function-like-object](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects), a Type that also acts as a function
211+
212+
```@example MAIN
213+
function (f::CoupledStandardMaps{N})(xnew::AbstractVector, x, p, n) where {N}
214+
ks, Γ = p
215+
@inbounds for i in f.idxs
216+
217+
xnew[i+N] = mod2pi(
218+
x[i+N] + ks[i]*sin(x[i]) -
219+
Γ*(sin(x[f.idxsp1[i]] - x[i]) + sin(x[f.idxsm1[i]] - x[i]))
220+
)
221+
222+
xnew[i] = mod2pi(x[i] + xnew[i+N])
223+
end
224+
return nothing
225+
end
226+
```
227+
228+
We will use *the same* `struct` to create a function for the Jacobian:
229+
230+
```@example MAIN
231+
function (f::CoupledStandardMaps{M})(
232+
J::AbstractMatrix, x, p, n) where {M}
233+
234+
ks, Γ = p
235+
# x[i] ≡ θᵢ
236+
# x[[idxsp1[i]]] ≡ θᵢ+₁
237+
# x[[idxsm1[i]]] ≡ θᵢ-₁
238+
@inbounds for i in f.idxs
239+
cosθ = cos(x[i])
240+
cosθp= cos(x[f.idxsp1[i]] - x[i])
241+
cosθm= cos(x[f.idxsm1[i]] - x[i])
242+
J[i+M, i] = ks[i]*cosθ + Γ*(cosθp + cosθm)
243+
J[i+M, f.idxsm1[i]] = - Γ*cosθm
244+
J[i+M, f.idxsp1[i]] = - Γ*cosθp
245+
J[i, i] = 1 + J[i+M, i]
246+
J[i, f.idxsm1[i]] = J[i+M, f.idxsm1[i]]
247+
J[i, f.idxsp1[i]] = J[i+M, f.idxsp1[i]]
248+
end
249+
return nothing
250+
end
251+
```
252+
253+
This is possible because the system state is a `Vector` while the Jacobian is a `Matrix`, so multiple dispatch can differentiate between the two.
254+
255+
Notice in addition, that the Jacobian function accesses *only half the elements of the matrix*. This is intentional, and takes advantage of the fact that the
256+
other half is constant. We can leverage this further, by making the Jacobian a sparse matrix. Because the `DynamicalSystem` constructors allow us to give in a pre-initialized Jacobian matrix, we take advantage of that and create:
257+
```@example MAIN
258+
using SparseArrays
259+
J = zeros(eltype(u0), 2M, 2M)
260+
# Set ∂/∂p entries (they are eye(M,M))
261+
# And they dont change they are constants
262+
for i in idxs
263+
J[i, i+M] = 1
264+
J[i+M, i+M] = 1
265+
end
266+
sparseJ = sparse(J)
267+
268+
csm(sparseJ, u0, p, 0) # apply Jacobian to initial state
269+
sparseJ
270+
```
271+
272+
Now we are ready to create our dynamical system
273+
274+
```@example MAIN
275+
ds = DeterministicIteratedMap(csm, u0, p)
276+
```
277+
278+
Of course, the reason we went through all this trouble was to make a [`TangentDynamicalSystem`](@ref), that can actually use the Jacobian function.
279+
280+
```@example MAIN
281+
tands = TangentDynamicalSystem(ds; J = csm, J0 = sparseJ, k = M)
282+
```
283+
284+
```@example MAIN
285+
step!(tands, 5)
286+
current_deviations(tands)
287+
```
288+
289+
(the deviation vectors will increase in magnitude rapidly because the dynamical system is chaotic)

docs/style.jl

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/core/dynamicalsystem_interface.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Concrete subtypes typically also contain more information than the above 3 items
4343
4444
In this scope dynamical systems have a known dynamic rule `f` defined as a
4545
standard Julia function. _Observed_ or _measured_ data from a dynamical system
46-
are represented using `AbstractStateSpaceSet` and are finite.
46+
are represented using `StateSpaceSet` and are finite.
4747
Such data are obtained from the [`trajectory`](@ref) function or
4848
from an experimental measurement of a dynamical system with an unknown dynamic rule.
4949

src/derived_systems/poincare/poincaremap.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ A discrete time dynamical system that produces iterations over the Poincaré map
1717
of the given continuous time `ds`. This map is defined as the sequence of points on the
1818
Poincaré surface of section, which is defined by the `plane` argument.
1919
20-
See also [`StroboscopicMap`](@ref), [`poincaresos`](@ref), [`produce_orbitdiagram`](@ref).
20+
See also [`StroboscopicMap`](@ref), [`poincaresos`](@ref).
2121
2222
## Keyword arguments
2323

0 commit comments

Comments
 (0)