From 11e6cb95c6f5e46423340532fe49acfb6684b224 Mon Sep 17 00:00:00 2001 From: Iago Bonnici Date: Thu, 19 Dec 2024 17:03:06 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Upgrade=20toplevel=20simulation?= =?UTF-8?q?=20utils.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/EcologicalNetworksDynamics.jl | 11 ++++----- src/basic_topology_queries.jl | 40 +++++++++++++++---------------- src/simulate.jl | 21 ++++++++-------- src/solution_queries.jl | 4 ++-- src/topology.jl | 20 +++++++--------- test/user/06-basic_pipelines.jl | 2 +- test/user/runtests.jl | 3 ++- 7 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/EcologicalNetworksDynamics.jl b/src/EcologicalNetworksDynamics.jl index 69c10c605..f4baac0e7 100644 --- a/src/EcologicalNetworksDynamics.jl +++ b/src/EcologicalNetworksDynamics.jl @@ -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. #------------------------------------------------------------------------------------------- @@ -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 diff --git a/src/basic_topology_queries.jl b/src/basic_topology_queries.jl index cdb104814..9db68d81d 100644 --- a/src/basic_topology_queries.jl +++ b/src/basic_topology_queries.jl @@ -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 @@ -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 @@ -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) @@ -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) @@ -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) @@ -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) @@ -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 @@ -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 @@ -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...)) @@ -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) @@ -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) @@ -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) @@ -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) diff --git a/src/simulate.jl b/src/simulate.jl index 797579a5d..d1796c95b 100644 --- a/src/simulate.jl +++ b/src/simulate.jl @@ -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 @@ -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, @@ -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, ) @@ -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, @@ -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) @@ -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) @@ -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" diff --git a/src/solution_queries.jl b/src/solution_queries.jl index 70a80096f..46db34e45 100644 --- a/src/solution_queries.jl +++ b/src/solution_queries.jl @@ -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 @@ -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 diff --git a/src/topology.jl b/src/topology.jl index bb3f09e58..ad028470a 100644 --- a/src/topology.jl +++ b/src/topology.jl @@ -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 = []) @@ -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 @@ -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) @@ -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...) = @@ -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...) diff --git a/test/user/06-basic_pipelines.jl b/test/user/06-basic_pipelines.jl index f4f18bfeb..b8eaba3b6 100644 --- a/test/user/06-basic_pipelines.jl +++ b/test/user/06-basic_pipelines.jl @@ -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) diff --git a/test/user/runtests.jl b/test/user/runtests.jl index b24466315..9688b446f 100644 --- a/test/user/runtests.jl +++ b/test/user/runtests.jl @@ -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__)