Skip to content

Commit

Permalink
🚧 Upgrade toplevel simulation utils.
Browse files Browse the repository at this point in the history
  • Loading branch information
iago-lito committed Dec 20, 2024
1 parent 11d944b commit 11e6cb9
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 51 deletions.
11 changes: 5 additions & 6 deletions src/EcologicalNetworksDynamics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ using OrderedCollections
using SparseArrays
using Graphs

imap = Iterators.map
ifilter = Iterators.filter
const imap = Iterators.map
const ifilter = Iterators.filter
iid(it) = imap(identity, it) # Useful to not leak refs.

#-------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -96,13 +96,12 @@ include("./expose_data.jl")
# connecting them to the internals via the framework.
include("./components/main.jl")

# HERE: now that all components have been upgraded, upgrade the following!
# Additional exposed utils built on top of components and methods.
include("./default_model.jl")
include("./nontrophic_layers.jl")
# include("./simulate.jl")
# include("./topology.jl")
# include("./diversity.jl")
include("./simulate.jl")
include("./topology.jl")
include("./diversity.jl")

# Avoid Revise interruptions when redefining methods and properties.
Framework.REVISING = true
Expand Down
40 changes: 20 additions & 20 deletions src/basic_topology_queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function n_live_species(g::Topology)
check_species(g)
U.n_nodes(g, :species)
end
n_live_species(m::InnerParms; kwargs...) = n_live_species(get_topology(m; kwargs...))
n_live_species(raw::Internal; kwargs...) = n_live_species(get_topology(raw; kwargs...))
@method n_live_species depends(Species)
n_live_species(sol::Solution; kwargs...) = n_live_species(get_topology(sol; kwargs...))
export n_live_species
Expand All @@ -30,7 +30,7 @@ function n_live_nutrients(g::Topology)
check_nutrients(g)
U.n_nodes(g, :nutrients)
end
n_live_nutrients(m::InnerParms; kwargs...) = n_live_nutrients(get_topology(m; kwargs...))
n_live_nutrients(raw::Internal; kwargs...) = n_live_nutrients(get_topology(raw; kwargs...))
@method n_live_nutrients depends(Nutrients.Nodes)
n_live_nutrients(sol::Solution; kwargs...) = n_live_nutrients(get_topology(sol; kwargs...))
export n_live_nutrients
Expand All @@ -50,8 +50,8 @@ Number of live producers within the topology after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
n_live_producers(m::InnerParms; kwargs...) =
n_live_producers(get_topology(m; kwargs...), m.producers_indices)
n_live_producers(raw::Internal; kwargs...) =
n_live_producers(get_topology(raw; kwargs...), raw.producers_indices)
@method n_live_producers depends(Foodweb)
n_live_producers(sol::Solution; kwargs...) =
n_live_producers(get_topology(sol; kwargs...), get_model(sol).producers_indices)
Expand All @@ -75,8 +75,8 @@ Number of live consumers within the topology after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
n_live_consumers(m::InnerParms; kwargs...) =
n_live_consumers(get_topology(m; kwargs...), m.consumers_indices)
n_live_consumers(raw::Internal; kwargs...) =
n_live_consumers(get_topology(raw; kwargs...), raw.consumers_indices)
@method n_live_consumers depends(Foodweb)
n_live_consumers(sol::Solution; kwargs...) =
n_live_consumers(get_topology(sol; kwargs...), get_model(sol).consumers_indices)
Expand All @@ -100,8 +100,8 @@ Number of live preys within the topology after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
n_live_preys(m::InnerParms; kwargs...) =
n_live_preys(get_topology(m; kwargs...), m.preys_indices)
n_live_preys(raw::Internal; kwargs...) =
n_live_preys(get_topology(raw; kwargs...), raw.preys_indices)
@method n_live_preys depends(Foodweb)
n_live_preys(sol::Solution; kwargs...) =
n_live_preys(get_topology(sol; kwargs...), get_model(sol).preys_indices)
Expand All @@ -125,8 +125,8 @@ Number of live tops within the topology after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
n_live_tops(m::InnerParms; kwargs...) =
n_live_tops(get_topology(m; kwargs...), m.tops_indices)
n_live_tops(raw::Internal; kwargs...) =
n_live_tops(get_topology(raw; kwargs...), raw.tops_indices)
@method n_live_tops depends(Foodweb)
n_live_tops(sol::Solution; kwargs...) =
n_live_tops(get_topology(sol; kwargs...), get_model(sol).tops_indices)
Expand Down Expand Up @@ -159,7 +159,7 @@ function live_species(g::Topology)
U.node_rel_index(g, abs, sp).rel
end
end
live_species(m::InnerParms; kwargs...) = live_species(get_topology(m; kwargs...))
live_species(raw::Internal; kwargs...) = live_species(get_topology(raw; kwargs...))
@method live_species depends(Species)
live_species(sol::Solution; kwargs...) = live_species(get_topology(sol; kwargs...))
export live_species
Expand All @@ -179,7 +179,7 @@ function live_nutrients(g::Topology)
U.node_rel_index(g, abs, sp).rel
end
end
live_nutrients(m::InnerParms; kwargs...) = live_nutrients(get_topology(m; kwargs...))
live_nutrients(raw::Internal; kwargs...) = live_nutrients(get_topology(raw; kwargs...))
@method live_nutrients depends(Nutrients.Nodes)
live_nutrients(sol::Solution; kwargs...) = live_nutrients(get_topology(sol; kwargs...))
export live_nutrients
Expand All @@ -202,7 +202,7 @@ function trophic_adjacency(g::Topology)
check_trophic(g)
U.outgoing_adjacency_labels(g, :species, :trophic, :species)
end
trophic_adjacency(m::InnerParms; kwargs...) = trophic_adjacency(get_topology(m; kwargs...))
trophic_adjacency(raw::Internal; kwargs...) = trophic_adjacency(get_topology(raw; kwargs...))
@method trophic_adjacency depends(Foodweb)
trophic_adjacency(sol::Solution; kwargs...) =
trophic_adjacency(get_topology(sol; kwargs...))
Expand All @@ -218,8 +218,8 @@ Iterate over relative indices of live producer species after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
live_producers(m::InnerParms; kwargs...) =
live_producers(get_topology(m; kwargs...), m.producers_indices)
live_producers(raw::Internal; kwargs...) =
live_producers(get_topology(raw; kwargs...), raw.producers_indices)
@method live_producers depends(Foodweb)
live_producers(sol::Solution; kwargs...) =
live_producers(get_topology(sol; kwargs...), get_model(sol).producers_indices)
Expand All @@ -244,8 +244,8 @@ Iterate over relative indices of live consumer species after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
live_consumers(m::InnerParms; kwargs...) =
live_consumers(get_topology(m; kwargs...), m.consumers_indices)
live_consumers(raw::Internal; kwargs...) =
live_consumers(get_topology(raw; kwargs...), raw.consumers_indices)
@method live_consumers depends(Foodweb)
live_consumers(sol::Solution; kwargs...) =
live_consumers(get_topology(sol; kwargs...), get_model(sol).consumers_indices)
Expand All @@ -270,8 +270,8 @@ Iterate over relative indices of live prey species after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
live_preys(m::InnerParms; kwargs...) =
live_preys(get_topology(m; kwargs...), m.preys_indices)
live_preys(raw::Internal; kwargs...) =
live_preys(get_topology(raw; kwargs...), raw.preys_indices)
@method live_preys depends(Foodweb)
live_preys(sol::Solution; kwargs...) =
live_preys(get_topology(sol; kwargs...), get_model(sol).preys_indices)
Expand All @@ -296,7 +296,7 @@ Iterate over relative indices of live top species after simulation.
See [`topology`](@ref).
⚠*: Assumes consistent indices from the same model: will be removed in a future version.
"""
live_tops(m::InnerParms; kwargs...) = live_tops(get_topology(m; kwargs...), m.tops_indices)
live_tops(raw::Internal; kwargs...) = live_tops(get_topology(raw; kwargs...), raw.tops_indices)
@method live_tops depends(Foodweb)
live_tops(sol::Solution; kwargs...) =
live_tops(get_topology(sol; kwargs...), get_model(sol).tops_indices)
Expand Down
21 changes: 11 additions & 10 deletions src/simulate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Solution = AbstractODESolution
# because a reference to the original model needs to be forwarded down to the internals
# to save a copy next to the results,
# and the @method macro misses the feature of providing this reference yet.
function _simulate(model::InnerParms, u0, tmax::Real; kwargs...)
function _simulate(raw::Internal, u0, tmax::Real; kwargs...)
# Depart from the legacy Internal defaults.
@kwargs_helpers kwargs

Expand All @@ -28,11 +28,11 @@ function _simulate(model::InnerParms, u0, tmax::Real; kwargs...)
verbose = take_or!(:show_extinction_events, false)

# No TerminateSteadyState.
extc = extinction_callback(model, extinction_threshold; verbose)
extc = extinction_callback(raw, extinction_threshold; verbose)
callback = take_or!(:callbacks, Internals.CallbackSet(extc))

out = Internals.simulate(
model,
raw,
u0;
tmax,
extinction_threshold,
Expand All @@ -42,7 +42,7 @@ function _simulate(model::InnerParms, u0, tmax::Real; kwargs...)
)

deg_top && show_degenerated_biomass_graph_properties(
model,
raw,
out.u[end][get_species_indices(out)],
deg_top_arg,
)
Expand Down Expand Up @@ -79,7 +79,8 @@ export simulate
include("./solution_queries.jl")

# Re-expose from internals so it works with the new API.
extinction_callback(m, thr; verbose = false) = Internals.ExtinctionCallback(thr, m, verbose)
extinction_callback(raw::Internal, thr; verbose = false) =
Internals.ExtinctionCallback(thr, raw, verbose)
export extinction_callback
@method extinction_callback depends(
FunctionalResponse,
Expand All @@ -89,8 +90,8 @@ export extinction_callback
)

# Collect topology diagnostics after simulation and decide whether to display them or not.
function show_degenerated_biomass_graph_properties(model::InnerParms, biomass, arg)
g = get_topology(model; without_species = biomass .<= 0.0)
function show_degenerated_biomass_graph_properties(raw::Internal, biomass, arg)
g = get_topology(raw; without_species = biomass .<= 0.0)
diagnostics = []
# Consume iterator to return lengths without collecting allocated yielded values.
function count(it)
Expand All @@ -100,8 +101,8 @@ function show_degenerated_biomass_graph_properties(model::InnerParms, biomass, a
end
res
end
pi = model.producers_indices
ci = model.consumers_indices
pi = @get raw.producers.indices
ci = @get raw.consumers.indices
for comp in disconnected_components(g)
sp = live_species(comp)
prods = live_producers(comp, pi)
Expand All @@ -126,7 +127,7 @@ function show_degenerated_biomass_graph_properties(model::InnerParms, biomass, a
else
m *= " contains degenerated species nodes:\n"
end
vec(i_species) = "[$(join_elided(model.species_label.(sort(i_species)), ", "))]"
vec(i_species) = "[$(join_elided(raw.species_label.(sort(i_species)), ", "))]"
for (sp, prods, cons, ip, sc) in diagnostics
n_sp, n_prods, n_cons, n_ip, n_sc = length.((sp, prods, cons, ip, sc))
m *= "Connected component with $n_sp species:\n"
Expand Down
4 changes: 2 additions & 2 deletions src/solution_queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Retrieve the correct indices to extract species-related data from simulation out
"""
function get_species_indices(sol::Solution)
m = get_model(sol)
1:(m.n_species)
1:(m.species.number)
end
export get_species_indices

Expand All @@ -32,7 +32,7 @@ Retrieve the correct indices to extract nutrients-related data from simulation o
function get_nutrients_indices(sol::Solution)
m = get_model(sol)
N = m.n_nutrients
S = m.n_species
S = m.species.number
(S+1):(S+N)
end
export get_nutrients_indices
Expand Down
20 changes: 9 additions & 11 deletions src/topology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
# Convenience local aliases.
const T = Topologies
const U = Topologies.Unchecked
const imap = Iterators.map
const ifilter = Iterators.filter

"""
get_topology(model::Model; without_species = [], without_nutrients = [])
Expand All @@ -17,20 +15,20 @@ When called on a static model, nodes can be explicitly removed during extraction
When called on a simulation result, extinct nodes are automatically removed
with extra arguments passed to [`extinctions`](@ref).
"""
function get_topology(model::InnerParms; without_species = [], without_nutrients = [])
function get_topology(raw::Internal; without_species = [], without_nutrients = [])
@tographdata! without_species K{:bin}
@tographdata! without_nutrients K{:bin}
g = deepcopy(model._topology)
g = deepcopy(raw._topology)
removes = []
if !isempty(without_species)
check_species(g)
spi = model.species_index
spi = @ref raw.species.index
@check_refs_if_list without_species "species" spi
push!(removes, (:species, without_species, spi))
end
if !isempty(without_nutrients)
check_nutrients(g)
nti = model.nutrients_index
nti = raw.nutrients_index
@check_refs_if_list without_nutrients "nutrients" nti
push!(removes, (:nutrients, without_nutrients, nti))
end
Expand All @@ -45,7 +43,7 @@ function get_topology(model::InnerParms; without_species = [], without_nutrients
end
g
end
@method get_topology depends() read_as(topology)
@method get_topology{Internal} depends() read_as(topology)

function get_topology(sol::Solution; kwargs...)
m = get_model(sol)
Expand Down Expand Up @@ -96,8 +94,8 @@ See [`topology`](@ref).
- ⚠ : Assumes consistent indices from the same model: will be removed in a future version.
"""
isolated_producers(m::InnerParms; kwargs...) =
isolated_producers(get_topology(m; kwargs...), m.producers_indices)
isolated_producers(raw::Internal; kwargs...) =
isolated_producers(get_topology(raw; kwargs...), raw.producers_indices)
@method isolated_producers depends(Foodweb)

isolated_producers(sol::Solution; kwargs...) =
Expand Down Expand Up @@ -132,8 +130,8 @@ See [`topology`](@ref).
- ⚠ : Assumes consistent indices from the same model: will be removed in a future version.
"""
starving_consumers(m::InnerParms; kwargs...) =
starving_consumers(get_topology(m; kwargs...), m.producers_indices, m.consumers_indices)
starving_consumers(raw::Internal; kwargs...) =
starving_consumers(get_topology(raw; kwargs...), raw.producers_indices, raw.consumers_indices)
@method starving_consumers depends(Foodweb)

function starving_consumers(sol::Solution; kwargs...)
Expand Down
2 changes: 1 addition & 1 deletion test/user/06-basic_pipelines.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ end
m = default_model(
Foodweb([1 => 2, 2 => 3]),
# Add one facilitation interaction randomly.
FacilitationLayer(; A = (L = 1,)),
Facilitation.Layer(; A = (L = 1,)),
)

sol = simulate(m, 0.5, 500)
Expand Down
3 changes: 2 additions & 1 deletion test/user/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ only = [
# "./02-graphviews.jl"
# "./03-components.jl"
# "./04-exposed_data.jl"
"./05-default_model.jl"
# "./05-default_model.jl"
"06-basic_pipelines.jl"
] # Unless some files are specified here, in which case only run these.
if isempty(only)
folder = dirname(@__FILE__)
Expand Down

0 comments on commit 11e6cb9

Please sign in to comment.