# \[ANN\] Attractors.jl

**URL:** <https://discourse.julialang.org/t/ann-attractors-jl/97961>\
**Category:** Package Announcements\
**Tags:** nonlinear\
**Created:** [April 26, 2023, 6:21pm UTC](https://discourse.julialang.org/t/ann-attractors-jl/97961 "2023-04-26T18:21:49Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [April 26, 2023, 6:21pm UTC](https://discourse.julialang.org/t/ann-attractors-jl/97961/1 "2023-04-26T18:21:49Z")

</div>

Hello people,

I am super proud to announce [Attractors.jl](https://juliadynamics.github.io/Attractors.jl/dev/) and the publication that accompanies the bulk of the package, which just appeared on [arXiv](https://arxiv.org/abs/2304.12786). As eluded to in the [DynamicalSystems.jl v3 announcement](https://discourse.julialang.org/t/dynamicalsystems-jl-v3/95266), Attractors.jl is a submodule of the DynamicalSystems.jl library that offers:

- finding attractors of arbitrary dynamical systems
- finding their basins of attraction or the state space fractions of the basins
- “continuing” the attractors and their basins over a parameter range
- finding the basin boundaries and analyzing their fractal properties
- tipping points related functionality for systems with known dynamic rule
- and more!

Arguably the most novel part is the third bullet point, that offers a completely new approach to ``continuation’', which means trying to figure out how the stability of the attractors of a dynamical system changes as a system parameter changes. We (the authors @Datseris @KalelR @awage ) believe that our new approach to continuation will become an essential tool in the analysis of stability of dynamical systems.

As an example of the capabilities of the framework, I am attaching here the code snippet that we use in our publication to illustrate framework usage:

```julia

using DynamicalSystems # includes Attractors.jl
using OrdinaryDiffEq # high-accuracy ODE solvers

# initialize Lorenz84 as a `DynamicalSystem`
function lorenz84_rule(u, p, t)
    F, G, a, b = p
    x, y, z = u
    dx = -y^2 -z^2 -a*x + a*F
    dy = x*y - y - b*x*z + G
    dz = b*x*y + x*z - z
    return SVector(dx, dy, dz)
end
p0 = [6.886, 1.347, 0.255, 4.0]
diffeq = (alg = Vern9(), reltol = 1e-9, abstol = 1e-9)
ds = CoupledODEs(lorenz84_rule, ones(3), p0; diffeq)

# Provide state space box to search in
xg = yg = zg = range(-3, 3; length = 600)
grid = (xg, yg, zg)
# initialize recurrences-based algorithm
# and choose its metaparameters
mapper = AttractorsViaRecurrences(ds, grid;
    mx_chk_fnd_att = 1000, mx_chk_loc_att = 2000,
    mx_chk_lost = 100, mx_chk_safety = 1e8,
    Dt = 0.05, force_non_adaptive = true,
)

# find and continue attractors across a given
# parameter range for the `pidx`-th parameter
prange = range(1.34, 1.37; length = 101)
pidx = 2 # index of parameter
sampler = statespace_sampler(grid)[1]
rsc = RecurrencesFindAndMatch(mapper)

fractions_curves, attractors_info = continuation(
    rsc, prange, pidx, sampler
)

# Estimate Lyapunov spectra for all attractors
# by looping over the parameter range
lyapunovs_curves = map(eachindex(prange)) do index
    set_parameter!(ds, pidx, prange[index])
    attractor_dict = attractors_info[index]
    exponents = Dict(
        k => lyapunovspectrum(ds, 10000; u0 = A[1])
        for (k, A) in attractor_dict
    )
end

```

In these 50 lines of code an incredible amount of information and automation is achieved. A dynamical system is defined from scratch. Then, the system attractors are found with the `mapper = AttractorsViaRecurences(...)` using no prior knowledge about the system besides a state space box that may contain the attractors. This `mapper` is used to construct a special “continuation” method `rsc = RecurrecesFindAndMatch(...)`, that, when given to `continuation`, it provides how the attractors of the system, and their relative fractions of attraction, behave versus a parameter range. At the very end of the code snippet we highlight the importance of such tools being part of a large and coherent framework (here DynamicalSystems.jl): the same input that is used to find attractors (`ds = CoupledODEs(...)`) is used to compute the Lyapunov exponents of the attractors.

We can animate the central output of `continuation` using some of the pre-defined plotting functions offered by the framework. For example,

```julia
animate_attractors_continuation(
    ds, attractors_info, fractions_curves, prange, pidx;
    savename = "lorenz84.mp4", access = [1,3],
    limits = (-1,3,-2,2),
    markersize = 10,
)

```

[https://global.discourse-cdn.com/julialang/original/3X/1/2/121e97c88c396fc9b3678ff9cd27ac77037c18dd.mp4](https://global.discourse-cdn.com/julialang/original/3X/1/2/121e97c88c396fc9b3678ff9cd27ac77037c18dd.mp4)

or to make a nice plot of the basin fractions (global stability measure) and Lyapunov exponents:

```julia
fig = basins_curves_plot(fractions_curves, prange;
    axislegend_kwargs = (position = :lb,)
)
axl = Axis(fig[0,1])
axl.ylabel = "λ₁ + λ₂"
hidexdecorations!(axl; grid = false)

lyap_to_real(L) = L[1]+L[2]
attractors_curves_plot!(axl, lyapunovs_curves, lyap_to_real, prange;
    axislegend_kwargs = (position = :cb,)
)

fig

```

 ![lorenz84_lyap](https://global.discourse-cdn.com/julialang/original/3X/a/8/a88379539d258accc2836229c538fb69f91bd97e.png)
