diff --git a/src/basins/basins_utilities.jl b/src/basins/basins_utilities.jl index 72889843..33a7b093 100644 --- a/src/basins/basins_utilities.jl +++ b/src/basins/basins_utilities.jl @@ -1,3 +1,46 @@ +# It works for all mappers that define a `basins_fractions` method. +""" + basins_of_attraction(mapper::AttractorMapper, grid::Tuple) → basins, attractors + +Compute the full basins of attraction as identified by the given `mapper`, +which includes a reference to a [`DynamicalSystem`](@ref) and return them +along with (perhaps approximated) found attractors. + +`grid` is a tuple of ranges defining the grid of initial conditions that partition +the state space into boxes with size the step size of each range. +For example, `grid = (xg, yg)` where `xg = yg = range(-5, 5; length = 100)`. +The grid has to be the same dimensionality as the state space expected by the +integrator/system used in `mapper`. E.g., a [`ProjectedDynamicalSystem`](@ref) +could be used for lower dimensional projections, etc. A special case here is +a [`PoincareMap`](@ref) with `plane` being `Tuple{Int, <: Real}`. In this special +scenario the grid can be one dimension smaller than the state space, in which case +the partitioning happens directly on the hyperplane the Poincaré map operates on. + +`basins_of_attraction` function is a convenience 5-lines-of-code wrapper which uses the +`labels` returned by [`basins_fractions`](@ref) and simply assigns them to a full array +corresponding to the state space partitioning indicated by `grid`. + +See also [`convergence_and_basins_of_attraction`](@ref). +""" +function basins_of_attraction(mapper::AttractorMapper, grid::Tuple; kwargs...) + basins = zeros(Int32, map(length, grid)) + I = CartesianIndices(basins) + A = StateSpaceSet([generate_ic_on_grid(grid, i) for i in vec(I)]) + fs, labels = basins_fractions(mapper, A; kwargs...) + attractors = extract_attractors(mapper) + vec(basins) .= vec(labels) + return basins, attractors +end + +# Type-stable generation of an initial condition given a grid array index +@generated function generate_ic_on_grid(grid::NTuple{B, T}, ind) where {B, T} + gens = [:(grid[$k][ind[$k]]) for k=1:B] + quote + Base.@_inline_meta + @inbounds return SVector{$B, Float64}($(gens...)) + end +end + """ basins_fractions(basins::AbstractArray [,ids]) → fs::Dict diff --git a/src/mapping/attractor_mapping.jl b/src/mapping/attractor_mapping.jl index bf04ae5e..77e6d93c 100644 --- a/src/mapping/attractor_mapping.jl +++ b/src/mapping/attractor_mapping.jl @@ -174,52 +174,6 @@ be used instead of [`basins_fractions`](@ref). """ function convergence_time end -######################################################################################### -# Generic basins of attraction method structure definition -######################################################################################### -# It works for all mappers that define a `basins_fractions` method. -""" - basins_of_attraction(mapper::AttractorMapper, grid::Tuple) → basins, attractors - -Compute the full basins of attraction as identified by the given `mapper`, -which includes a reference to a [`DynamicalSystem`](@ref) and return them -along with (perhaps approximated) found attractors. - -`grid` is a tuple of ranges defining the grid of initial conditions that partition -the state space into boxes with size the step size of each range. -For example, `grid = (xg, yg)` where `xg = yg = range(-5, 5; length = 100)`. -The grid has to be the same dimensionality as the state space expected by the -integrator/system used in `mapper`. E.g., a [`ProjectedDynamicalSystem`](@ref) -could be used for lower dimensional projections, etc. A special case here is -a [`PoincareMap`](@ref) with `plane` being `Tuple{Int, <: Real}`. In this special -scenario the grid can be one dimension smaller than the state space, in which case -the partitioning happens directly on the hyperplane the Poincaré map operates on. - -`basins_of_attraction` function is a convenience 5-lines-of-code wrapper which uses the -`labels` returned by [`basins_fractions`](@ref) and simply assigns them to a full array -corresponding to the state space partitioning indicated by `grid`. - -See also [`convergence_and_basins_of_attraction`](@ref). -""" -function basins_of_attraction(mapper::AttractorMapper, grid::Tuple; kwargs...) - basins = zeros(Int32, map(length, grid)) - I = CartesianIndices(basins) - A = StateSpaceSet([generate_ic_on_grid(grid, i) for i in vec(I)]) - fs, labels = basins_fractions(mapper, A; kwargs...) - attractors = extract_attractors(mapper) - vec(basins) .= vec(labels) - return basins, attractors -end - -# Type-stable generation of an initial condition given a grid array index -@generated function generate_ic_on_grid(grid::NTuple{B, T}, ind) where {B, T} - gens = [:(grid[$k][ind[$k]]) for k=1:B] - quote - Base.@_inline_meta - @inbounds return SVector{$B, Float64}($(gens...)) - end -end - ######################################################################################### # Includes #########################################################################################