From d5b316c608764d849f26eb9bbd6bf845f57a39d2 Mon Sep 17 00:00:00 2001 From: Iago-lito Date: Tue, 18 Apr 2023 14:37:02 +0200 Subject: [PATCH] Minor style nitpicks. - Vertical whitespace. - Multiline strings. - `; arg = arg` elisions. - .. --- src/measures/functioning.jl | 34 ++------ src/measures/stability.jl | 19 ++--- src/measures/utils.jl | 104 ++++++++++++------------ test/measures/test-functioning.jl | 18 ++--- test/measures/test-stability.jl | 2 - test/measures/test-utils.jl | 128 +++++++++++++++--------------- 6 files changed, 135 insertions(+), 170 deletions(-) diff --git a/src/measures/functioning.jl b/src/measures/functioning.jl index 783599439..3a16d319f 100644 --- a/src/measures/functioning.jl +++ b/src/measures/functioning.jl @@ -1,6 +1,5 @@ #= -Quantifying functions -Adapted from BioenergeticFoodWeb.jl +Quantifying functions. =# """ @@ -167,14 +166,12 @@ https://en.wikipedia.org/wiki/Diversity_index#Shannon_index """ function shannon_diversity(solution; threshold = 0, kwargs...) measure_on = extract_last_timesteps(solution; kwargs...) - shan = shannon_diversity.(eachcol(measure_on); threshold) mean(shan) end function shannon_diversity(n::AbstractVector; threshold = 0) x = filter(>(threshold), n) - if length(x) >= 1 p = x ./ sum(x) p_ln_p = p .* log.(p) @@ -203,14 +200,12 @@ https://en.wikipedia.org/wiki/Diversity_index#Simpson_index """ function simpson(solution; threshold = 0, kwargs...) measure_on = extract_last_timesteps(solution; kwargs...) - simp = simpson.(eachcol(measure_on); threshold) mean(simp) end function simpson(n::AbstractVector; threshold = 0) x = filter(>(threshold), n) - if length(x) >= 1 p = x ./ sum(x) p2 = 2 .^ p @@ -237,7 +232,6 @@ https://en.wikipedia.org/wiki/Species_evenness """ function evenness(solution; threshold = 0, kwargs...) measure_on = extract_last_timesteps(solution; kwargs...) - piel = evenness.(eachcol(measure_on); threshold) mean(piel) end @@ -371,10 +365,10 @@ julia> foodweb = FoodWeb([0 0 0; 0 1 0; 1 1 0]; quiet = true); """ function trophic_structure(solution; threshold = 0, idxs = nothing, kwargs...) - isnothing(idxs) || throw(ArgumentError("`trophic_structure()` operates at the whole \ - network level, so it makes no sense to ask for \ - particular species with anything other than \ - `idxs = nothing`.")) + isnothing(idxs) || + throw(ArgumentError("`trophic_structure()` operates at the whole network level, \ + so it makes no sense to ask for particular species \ + with anything other than `idxs = nothing`.")) # Measure trophic structure over last timesteps @@ -388,7 +382,6 @@ function trophic_structure(solution; threshold = 0, idxs = nothing, kwargs...) alive = alive_trophic_network(measure_on[:, i], net; threshold) tlvl = alive.trophic_level bm = alive.species_biomass - push!(maxl, max_trophic_level(tlvl)) push!(avgl, mean_trophic_level(tlvl)) push!(wavg, weighted_average_trophic_level(bm, tlvl)) @@ -568,12 +561,7 @@ end """ - living_species( - solution::Solution; - threshold = 0, - idxs = nothing, - kwargs..., - ) + living_species(solution::Solution; threshold = 0, idxs = nothing, kwargs...) Returns the vectors of alive species and their indices in the original network. Living species are the ones having, in average, a biomass above `threshold` over @@ -600,17 +588,10 @@ julia> B0 = [0, 0.5, 0.5]; (species = ["s2", "s3"], idxs = [2, 3]) ``` """ -function living_species( - solution::Solution; - threshold = 0, - idxs = nothing, - kwargs..., -) +function living_species(solution::Solution; threshold = 0, idxs = nothing, kwargs...) measure_on = extract_last_timesteps(solution; idxs, kwargs...) - alive_sp = living_species(measure_on; threshold) - sp = get_parameters(solution).network.species tmp_idxs = process_idxs(solution; idxs) @@ -622,7 +603,6 @@ end living_species(mat::AbstractMatrix; threshold = 0) = findall(>(threshold), biomass(mat).species) - living_species(n::AbstractVector; threshold = 0) = findall(>(threshold), n) """ diff --git a/src/measures/stability.jl b/src/measures/stability.jl index f4fa474ef..71b28fb9a 100644 --- a/src/measures/stability.jl +++ b/src/measures/stability.jl @@ -1,5 +1,5 @@ #= -Various measures of stability +Various measures of stability. =# """ @@ -11,6 +11,7 @@ See [`coefficient_of_variation`](@ref) for the details. """ function species_cv(solution::Solution; threshold = 0, last = "10%", kwargs...) measure_on = extract_last_timesteps(solution; last, kwargs...) + # Fetch species that are alive, whose avg biomass is > threshold living_sp = living_species(measure_on; threshold) @@ -21,7 +22,6 @@ function species_cv(solution::Solution; threshold = 0, last = "10%", kwargs...) end function species_cv(mat::AbstractMatrix; corrected = true) - if any(size(mat) .== 0) average = NaN species = NaN @@ -65,8 +65,8 @@ function synchrony( corrected = true, kwargs..., ) - measure_on = extract_last_timesteps(solution; last, kwargs...) + # Fetch species that are alive, whose avg biomass is > threshold living_sp = living_species(measure_on; threshold) @@ -74,10 +74,9 @@ function synchrony( mat = transpose(measure_on[living_sp, :]) synchrony(mat; corrected = corrected) - end -function synchrony(mat::AbstractMatrix; corrected = true) +function synchrony(mat::AbstractMatrix; corrected = true) if any(size(mat) .== 0) phi = NaN else @@ -88,9 +87,7 @@ function synchrony(mat::AbstractMatrix; corrected = true) phi = com_var / std_sp^2 end - phi - end """ @@ -113,19 +110,18 @@ function community_cv( corrected = true, kwargs..., ) + measure_on = extract_last_timesteps(solution; last, kwargs...) - measure_on = extract_last_timesteps(solution; last = last, kwargs...) # Fetch species that are alive, whose avg biomass is > threshold - living_sp = living_species(measure_on; threshold = threshold, kwargs...) + living_sp = living_species(measure_on; threshold, kwargs...) # Transpose to get the time x species matrix mat = transpose(measure_on[living_sp, :]) community_cv(mat; corrected) - end -function community_cv(mat::AbstractMatrix; corrected = true) +function community_cv(mat::AbstractMatrix; corrected = true) if any(size(mat) .== 0) cv_com = NaN else @@ -187,7 +183,6 @@ function coefficient_of_variation( corrected = true, kwargs..., ) - measure_on = extract_last_timesteps(solution; last, kwargs...) # Fetch species that are alive, whose avg biomass is > threshold alive_sp = living_species(measure_on; threshold) diff --git a/src/measures/utils.jl b/src/measures/utils.jl index 281b834c8..59248e602 100644 --- a/src/measures/utils.jl +++ b/src/measures/utils.jl @@ -29,10 +29,9 @@ julia> fw = FoodWeb([0 0; 1 0]); [0.219659439; 0.188980349;;] true -julia> sim = extract_last_timesteps(m; last = 1, idxs = [1, 2]); - sim == - extract_last_timesteps(m; last = 1, idxs = ["s1", "s2"]) ≈ - [0.188980349; 0.219659439;;] +julia> sim1 = extract_last_timesteps(m; last = 1, idxs = [1, 2]); + sim2 = extract_last_timesteps(m; last = 1, idxs = ["s1", "s2"]); + sim1 ≈ sim2 ≈ [0.188980349; 0.219659439;;] true julia> sim = extract_last_timesteps(m; last = 1, idxs = [2]); @@ -41,17 +40,13 @@ true ``` """ function extract_last_timesteps(solution; idxs = nothing, quiet = false, kwargs...) - - last = process_last_timesteps(solution; quiet = quiet, kwargs...) - - + last = process_last_timesteps(solution; quiet, kwargs...) out = solution[:, end-(last-1):end] - idxs = process_idxs(solution; idxs) # Extract species indices: + idxs = process_idxs(solution; idxs) out = out[idxs, :] - - quiet || check_last_extinction(solution; idxs = idxs, last = last) + quiet || check_last_extinction(solution; idxs, last) deepcopy(out) end @@ -78,24 +73,27 @@ function process_idxs(solution; idxs = nothing) idxs_in = indexin(idxs, sp) # Handle missing species absent_sp = isnothing.(idxs_in) - any(absent_sp) && throw(ArgumentError("Species $(idxs[absent_sp]) are not \ - found in the network. Any mispelling?")) - + any(absent_sp) && throw( + ArgumentError("Species $(idxs[absent_sp]) are not found in the network. \ + Any mispelling?"), + ) # Get the index of the species names in solution matrix idxs = idxs_in[.!absent_sp] # remove Union{nothing, ...} idxs = something.(idxs) - elseif eltype(idxs) <: Integer check_bound_idxs = 1 .<= idxs .<= length(sp) absent_sp = idxs[findall(.!check_bound_idxs)] - all(check_bound_idxs) || throw(ArgumentError("Cannot extract idxs $(absent_sp) \ - when there are $(length(sp)) species.")) - + all(check_bound_idxs) || throw( + ArgumentError( + "Cannot extract idxs $(absent_sp) when there are $(length(sp)) species.", + ), + ) else - throw(ArgumentError("`idxs` should be a vector of Integer (species indices) or \ - String (species names)")) + throw(ArgumentError("`idxs` should be a vector of integers (species indices) \ + or strings (species names)")) end + idxs end @@ -104,66 +102,67 @@ function process_last_timesteps(solution; last = 1, quiet = false) n_timesteps = length(solution.t) if last isa AbstractString - endswith(last, "%") || throw(ArgumentError("The `last` argument, when given as a \ - string, should end with character '%'")) - + endswith(last, "%") || + throw(ArgumentError("The `last` argument, when given as a string, \ + should end with character '%'")) perc = parse(Float64, last[1:(end-1)]) is_valid_perc = 0.0 < perc <= 100.0 - is_valid_perc || throw(ArgumentError("Cannot extract $(perc)% of the solution's \ - timesteps: 0% < `last` <= 100% must hold.")) + is_valid_perc || + throw(ArgumentError("Cannot extract $(perc)% of the solution's timesteps: \ + 0% < `last` <= 100% must hold.")) last = round(Int, n_timesteps * perc / 100) - last > 0 || quiet || @warn "$perc% of $n_timesteps \ - timesteps correspond to $last output lines: an empty table has been extracted." + (last > 0 || quiet) || + @warn("$perc% of $n_timesteps timesteps correspond to $last output lines: \ + an empty table has been extracted.") elseif last isa Integer - last > 0 || throw(ArgumentError("Cannot extract $last timesteps. `last` should be \ - a positive integer.")) + last > 0 || throw(ArgumentError("Cannot extract $last timesteps. \ + `last` should be a positive integer.")) elseif last isa Float64 throw(ArgumentError("Cannot extract `last` from a floating point number. \ - Did you mean \"$last%\"?")) + Did you mean \"$last%\"?")) else throw(ArgumentError("Cannot extract timesteps with `last=$last` \ - of type $(typeof(last)). \ - `last` should be a positive integer \ - or a string representing a percentage.")) + of type $(typeof(last)). \ + `last` should be a positive integer \ + or a string representing a percentage.")) end - last > n_timesteps && throw(ArgumentError("Cannot extract $last timesteps from a \ - trajectory solution with only \ - $(n_timesteps) timesteps. \ - Consider decreasing the `last` argument value \ - and/or specifying it as a percentage instead \ - (e.g. `\"10%\"`).")) + last > n_timesteps && throw( + ArgumentError("Cannot extract $last timesteps from a trajectory solution \ + with only $(n_timesteps) timesteps. \ + Consider decreasing the `last` argument value \ + and/or specifying it as a percentage instead (e.g. `\"10%\"`)."), + ) + last end function check_last_extinction(solution; idxs = nothing, last = 1) ext = get_extinction_timesteps(solution; idxs) ext_t = ext.extinction_timestep - n_timesteps = length(solution.t) - - check_last_extinction(n_timesteps; t = ext_t, species = ext.species, last = last) + check_last_extinction(n_timesteps; t = ext_t, species = ext.species, last) end function check_last_extinction(n_timesteps::Integer; t, species, last) extinct = t .!== nothing if any(extinct) check_last = findall(>(n_timesteps - (last - 1)), t[extinct]) - - isempty(check_last) || @warn "With `last` = $last, a table has been extracted with \ - the species $(species[extinct][check_last]), \ - that went extinct at timesteps = $(t[extinct][check_last]). Set `last` <= \ - $(n_timesteps - (maximum(t[extinct]) - 1)) to get rid of them." + sp = species[extinct][check_last] + ts = t[extinct][check_last] + max = n_timesteps - (maximum(t[extinct]) - 1) + isempty(check_last) || + @warn("With `last` = $last, a table has been extracted with the species $sp, \ + that went extinct at timesteps = $ts. \ + Set `last` <= $max to get rid of them.") end end function get_extinction_timesteps(solution; idxs = nothing) idxs = process_idxs(solution; idxs) sp = get_parameters(solution).network.species[idxs] - ext_t = findfirst.(isequal(0), eachrow(solution[idxs, :])) extinct = ext_t .!== nothing - ( species = sp[extinct], idxs = idxs[extinct], @@ -205,12 +204,9 @@ julia> sim = simulate(params, [0, 0]; tmax = 20); function get_alive_species(solution; idxs = nothing, threshold = 0) idxs = process_idxs(solution; idxs) sp = get_parameters(solution).network.species[idxs] - - alive_idxs = get_alive_species(solution[idxs, end]; threshold = threshold) - - (species = sp[alive_idxs], idxs = idxs[alive_idxs]) + alive = get_alive_species(solution[idxs, end]; threshold = threshold) + (species = sp[alive], idxs = idxs[alive]) end get_extinct_species(m::AbstractVector; threshold = 0) = findall(<=(threshold), m) - get_alive_species(m::AbstractVector; threshold = 0) = findall(>(threshold), m) diff --git a/test/measures/test-functioning.jl b/test/measures/test-functioning.jl index d872deecb..43dda1045 100644 --- a/test/measures/test-functioning.jl +++ b/test/measures/test-functioning.jl @@ -4,7 +4,6 @@ params = ModelParameters(foodweb) sol = simulates(params, [0.5, 0.5]) - @test living_species(sol) == (species = ["s1", "s2"], idxs = [1, 2]) @test living_species(sol; idxs = 1) == living_species(sol; idxs = [1]) == @@ -26,8 +25,8 @@ end @testset "Trophic structure" begin + # With trophic levels - # net = [0 0; 1 0] tlvl = trophic_levels(net) @test max_trophic_level(tlvl) == 2.0 @@ -93,13 +92,11 @@ end sim_zero = simulates(params, [0, 0, 0]; verbose = true) sim_three = simulates(params, [0.5, 0.5, 0.5]; verbose = true) - @test_throws ArgumentError("`trophic_structure()` operates at the whole \ - network level, so it makes no sense to ask for \ - particular species with anything other than \ - `idxs = nothing`.") trophic_structure( - sim_zero; - last = 10, - idxs = 2, + @test_throws( + ArgumentError("`trophic_structure()` operates at the whole network level, \ + so it makes no sense to ask for particular species \ + with anything other than `idxs = nothing`."), + trophic_structure(sim_zero; last = 10, idxs = 2) ) troph_zero = trophic_structure(sim_zero; quiet = true) @@ -154,8 +151,8 @@ end # Test structure: @test length(normal_growth.mean) == length(normal_growth.std) == 1 -end +end @testset "Total biomass, species persistence, Hill numbers" begin @@ -208,7 +205,6 @@ end shannon_diversity(m1; last = 1) == 0.0 - shannan(m; kwargs...) = isnan(shannon_diversity(m; kwargs...)) shannan_check = [ # Not defined for 0 species diff --git a/test/measures/test-stability.jl b/test/measures/test-stability.jl index fc84438e9..afec8ea53 100644 --- a/test/measures/test-stability.jl +++ b/test/measures/test-stability.jl @@ -36,7 +36,6 @@ sqrt(synchrony(mat; corrected = false)) @test community_cv(mat) ≈ species_cv(mat).average * sqrt(synchrony(mat)) - @test all(isnan.(community_cv.(([0 0; 0 0], mc, mr)))) foodweb = FoodWeb([0 0; 1 0]; Z = 1) # Two producers and one consumer @@ -85,5 +84,4 @@ cv_one_sp2 = coefficient_of_variation(one_sp; idxs = 2, last = 10) @test all(isnan.(values(cv_one_sp2))) - end diff --git a/test/measures/test-utils.jl b/test/measures/test-utils.jl index 45bec95a6..f2fb05602 100644 --- a/test/measures/test-utils.jl +++ b/test/measures/test-utils.jl @@ -9,49 +9,60 @@ @test round.(extract_last_timesteps(sim; last = "20.5%")) == [0.0 0.0; 1.0 1.0] # Test errors on sugar - @test_throws ArgumentError("The `last` argument, when given as a \ - string, should end with character '%'") extract_last_timesteps( - sim, - last = "15%5", + @test_throws( + ArgumentError("The `last` argument, when given as a string, \ + should end with character '%'"), + extract_last_timesteps(sim; last = "15%5") ) - @test_throws ArgumentError("Cannot extract -100.1% of the solution's timesteps: 0% < \ - `last` <= 100% must hold.") extract_last_timesteps( - sim, - last = "-100.1%", + @test_throws( + ArgumentError("Cannot extract -100.1% of the solution's timesteps: \ + 0% < `last` <= 100% must hold."), + extract_last_timesteps(sim, last = "-100.1%") ) - @test_throws ArgumentError("Cannot extract 0.0% of the solution's timesteps: 0% < \ - `last` <= 100% must hold.") extract_last_timesteps( - sim, - last = "0%", + @test_throws( + ArgumentError("Cannot extract 0.0% of the solution's timesteps: \ + 0% < `last` <= 100% must hold."), + extract_last_timesteps(sim, last = "0%") ) # Test last as integer - @test_throws ArgumentError( - "Cannot extract 100 timesteps from a trajectory solution \ - with only 12 timesteps. Consider decreasing the `last` \ - argument value and/or specifying it as a percentage instead \ - (e.g. `\"10%\"`).", - ) extract_last_timesteps(sim, last = 100) - @test_throws ArgumentError("Cannot extract 0 timesteps. `last` should be \ - a positive integer.") extract_last_timesteps(sim, last = 0) - @test_throws ArgumentError("Cannot extract -10 timesteps. `last` should be \ - a positive integer.") extract_last_timesteps(sim, last = -10) - - @test_throws ArgumentError("Cannot extract `last` from a floating point number. \ - Did you mean \"4.5%\"?") extract_last_timesteps(sim, last = 4.5) - - @test_throws ArgumentError("Cannot extract timesteps with `last=Any[]` \ - of type Vector{Any}. `last` should be a positive integer \ - or a string representing a percentage.") extract_last_timesteps( - sim, - last = [], + @test_throws( + ArgumentError("Cannot extract 100 timesteps \ + from a trajectory solution with only 12 timesteps. \ + Consider decreasing the `last` argument value \ + and/or specifying it as a percentage instead (e.g. `\"10%\"`)."), + extract_last_timesteps(sim, last = 100) ) - warn_empty_table = "0.001% of 12 timesteps correspond to 0 output lines: \ - an empty table has been extracted." - @test_warn warn_empty_table extract_last_timesteps(sim, last = ".001%") + @test_throws( + ArgumentError("Cannot extract 0 timesteps. `last` should be a positive integer."), + extract_last_timesteps(sim, last = 0) + ) + @test_throws( + ArgumentError("Cannot extract -10 timesteps. `last` should be a positive integer."), + extract_last_timesteps(sim, last = -10) + ) + + @test_throws( + ArgumentError("Cannot extract `last` from a floating point number. \ + Did you mean \"4.5%\"?"), + extract_last_timesteps(sim, last = 4.5) + ) + + @test_throws( + ArgumentError("Cannot extract timesteps with `last=Any[]` of type Vector{Any}. \ + `last` should be a positive integer \ + or a string representing a percentage."), + extract_last_timesteps(sim, last = []) + ) + + @test_warn( + "0.001% of 12 timesteps correspond to 0 output lines: \ + an empty table has been extracted.", + extract_last_timesteps(sim, last = ".001%") + ) @test_nowarn extract_last_timesteps(sim, last = ".001%", quiet = true) # Test species selection @@ -60,31 +71,26 @@ [0.0;;] err_sp_msg = "Species [\"s3\"] are not found in the network. Any mispelling?" - @test_throws ArgumentError(err_sp_msg) extract_last_timesteps( - sim; - last = "10%", - idxs = "s3", + @test_throws( + ArgumentError(err_sp_msg), + extract_last_timesteps(sim; last = "10%", idxs = "s3") ) - @test_throws ArgumentError(err_sp_msg) extract_last_timesteps( - sim; - last = "10%", - idxs = ["s3"], + @test_throws( + ArgumentError(err_sp_msg), + extract_last_timesteps(sim; last = "10%", idxs = ["s3"]) ) err_id_msg = "Cannot extract idxs [4] when there are 2 species." - @test_throws ArgumentError(err_id_msg) extract_last_timesteps( - sim; - last = "10%", - idxs = 4, + @test_throws( + ArgumentError(err_id_msg), + extract_last_timesteps(sim; last = "10%", idxs = 4) ) - @test_throws ArgumentError(err_id_msg) extract_last_timesteps( - sim; - last = "10%", - idxs = [2, 4], + @test_throws( + ArgumentError(err_id_msg), + extract_last_timesteps(sim; last = "10%", idxs = [2, 4]) ) - @test size(extract_last_timesteps(sim; last = 1), 2) == 1 @test size(extract_last_timesteps(sim; last = 10), 2) == 10 @test extract_last_timesteps(sim; last = 10) isa AbstractMatrix @@ -92,19 +98,13 @@ end @testset "check extinction" begin - @test EcologicalNetworksDynamics.check_last_extinction( - 100; - t = [100], - species = ["s2"], - last = 1, - ) == true - warn_msg = "With `last` = 2, a table has been extracted with the species [\"s2\"], \ - that went extinct at timesteps = [100]. Set `last` <= 1 to get rid of them." - @test_warn warn_msg EcologicalNetworksDynamics.check_last_extinction( - 100, - t = [100], - species = ["s2"], - last = 2, + check_last = EcologicalNetworksDynamics.check_last_extinction + @test check_last(100; t = [100], species = ["s2"], last = 1) == true + + @test_warn( + "With `last` = 2, a table has been extracted with the species [\"s2\"], \ + that went extinct at timesteps = [100]. Set `last` <= 1 to get rid of them.", + check_last(100, t = [100], species = ["s2"], last = 2) ) foodweb = FoodWeb([0 0; 1 0]; Z = 1) # Two producers and one co