Skip to content

Commit

Permalink
🔧 Fix tests down to 04-expose_data.jl. Next step: default_model.
Browse files Browse the repository at this point in the history
  • Loading branch information
iago-lito committed Dec 16, 2024
1 parent a59dc79 commit 053855d
Show file tree
Hide file tree
Showing 27 changed files with 203 additions and 210 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@
- Akward plurals like `model.body_masses` and `model.metabolic_classes`
become `model.body_mass` and `model.metabolic_class`.

- Julia allows linear indexing into 2D structures,
but the package chooses instead to consider this a semantic flaw:
```julia-repl
julia> m = Model(
Foodweb([:a => [:b, :c], :b => [:c, :d]]),
Efficiency(:Miele2019; e_herbivorous = .1, e_carnivorous = .2),
);
m.e[5]
ERROR: View error (EcologicalNetworksDynamics.EfficiencyRates):
Edges data are 2-dimensional:
cannot access trophic link data values with 1 index: [5].
```

## New features

Expand Down
1 change: 1 addition & 0 deletions src/EcologicalNetworksDynamics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ 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")
Expand Down
2 changes: 1 addition & 1 deletion src/components/body_mass.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import .EcologicalNetworksDynamics: _Species, Species, _Foodweb, Foodweb
mutable struct Raw <: Blueprint
M::Vector{Float64}
species::Brought(Species)
Raw(M, sp = _Species) = new(Float64.(M), sp)
Raw(M, sp = _Species) = new(@tographdata(M, Vector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.M))
@blueprint Raw "masses values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/carrying_capacity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
K::SparseVector{Float64}
species::Brought(Species)
Raw(K::SparseVector{Float64}, sp = _Species) = new(K, sp)
Raw(K, sp = _Species) = new(SparseVector(Float64.(K)), sp)
Raw(K, sp = _Species) = new(@tographdata(K, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.K))
@blueprint Raw "carrying capacity values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/consumption_rate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
alpha::SparseVector{Float64}
species::Brought(Species)
Raw(alpha::SparseVector{Float64}, sp = _Species) = new(alpha, sp)
Raw(alpha, sp = _Species) = new(SparseVector(Float64.(alpha)), sp)
Raw(alpha, sp = _Species) = new(@tographdata(alpha, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.alpha))
@blueprint Raw "consumption rates"
Expand Down
4 changes: 2 additions & 2 deletions src/components/foodweb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import .EN: _Species, Species
mutable struct Matrix <: Blueprint
A::@GraphData SparseMatrix{:bin}
species::Brought(Species)
Matrix(A, sp = Species) = new((@tographdata A SparseMatrix{:bin}), sp)
Matrix(A, sp = Species) = new(@tographdata(A, SparseMatrix{:bin}), sp)
end
# Infer number of species from matrix size.
F.implied_blueprint_for(bp::Matrix, ::_Species) = Species(size(bp.A, 1))
Expand Down Expand Up @@ -63,7 +63,7 @@ end
mutable struct Adjacency <: Blueprint
A::@GraphData {Adjacency}{:bin} # (refs are either numbers or names)
species::Brought(Species)
Adjacency(A, sp = Species) = new((@tographdata A {Adjacency}{:bin}), sp)
Adjacency(A, sp = Species) = new(@tographdata(A, {Adjacency}{:bin}), sp)
end

# Infer number or names of species from the lists.
Expand Down
2 changes: 1 addition & 1 deletion src/components/growth_rate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mutable struct Raw <: Blueprint
r::SparseVector{Float64}
species::Brought(Species)
Raw(r::SparseVector{Float64}, sp = _Species) = new(r, sp)
Raw(r, sp = _Species) = new(SparseVector(Float64.(r)), sp)
Raw(r, sp = _Species) = new(@tographdata(r, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.r))
@blueprint Raw "growth rate values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/half_saturation_density.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
B0::SparseVector{Float64}
species::Brought(Species)
Raw(B0::SparseVector{Float64}, sp = _Species) = new(B0, sp)
Raw(B0, sp = _Species) = new(SparseVector(Float64.(B0)), sp)
Raw(B0, sp = _Species) = new(@tographdata(B0, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.B0))
@blueprint Raw "half-saturation density values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/intraspecific_interference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
c::SparseVector{Float64}
species::Brought(Species)
Raw(c::SparseVector{Float64}, sp = _Species) = new(c, sp)
Raw(c, sp = _Species) = new(SparseVector(Float64.(c)), sp)
Raw(c, sp = _Species) = new(@tographdata(c, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.c))
@blueprint Raw "intra-specific interference values"
Expand Down
3 changes: 2 additions & 1 deletion src/components/macros_keywords.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ if (false)
Scalar,
V,
Y,
col_index,
dense,
depends,
edges,
Expand All @@ -19,7 +20,7 @@ if (false)
ref,
ref_cached,
requires,
requires,
row_index,
set!,
template,
write!,
Expand Down
29 changes: 0 additions & 29 deletions src/components/main.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,6 @@
# - Sparse (templated) edges data.
# - Behaviour (graph data that actually represents *code* to run the model).

# HERE: Now that the framework has been refactored,
# change all the following components with the following design:
#
# module OmegaBlueprints
# # /!\ many redundant imports to factorize here.
# struct Raw <: Blueprint ... end
# struct Random <: Blueprint ... end
# @blueprint Raw
# @blueprint Random
# ...
# end
#
# @component Omega blueprints(Raw::OmegaBlueprints.Raw, Random::OmegaBlueprints.Random, ..)
#
# function (C::_Omega)(args...; kwargs...)
# if ..
# C.Raw(...)
# elseif ...
# C.Random(...)
# else ...
# end
# end
#
# # Use as a blueprint constructor, but also as a blueprint namespace.
# Omega(...)
# Omega.Random(...)
# Omega.Raw(...)
#

# Helpers.
include("./macros_keywords.jl")
include("./allometry.jl")
Expand Down
2 changes: 1 addition & 1 deletion src/components/maximum_consumption.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
y::SparseVector{Float64}
species::Brought(Species)
Raw(y::SparseVector{Float64}, sp = _Species) = new(y, sp)
Raw(y, sp = _Species) = new(SparseVector(Float64.(y)), sp)
Raw(y, sp = _Species) = new(@tographdata(y, SparseVector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.y))
@blueprint Raw "maximum consumption values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/metabolic_class.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ include("./allometry_identifiers.jl")
mutable struct Raw <: Blueprint
classes::Vector{Symbol}
species::Brought(Species)
Raw(classes, sp = _Species) = new(Symbol.(classes), sp)
Raw(classes, sp = _Species) = new(@tographdata(classes, Vector{Symbol}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.classes))
@blueprint Raw "metabolic classes" depends(Foodweb)
Expand Down
2 changes: 1 addition & 1 deletion src/components/metabolism.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
x::Vector{Float64}
species::Brought(Species)
Raw(x::Vector{Float64}, sp = _Species) = new(x, sp)
Raw(x, sp = _Species) = new(Float64.(x), sp)
Raw(x, sp = _Species) = new(@tographdata(x, Vector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.x))
@blueprint Raw "metabolism values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/mortality.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mutable struct Raw <: Blueprint
d::Vector{Float64}
species::Brought(Species)
Raw(d::Vector{Float64}, sp = _Species) = new(d, sp)
Raw(d, sp = _Species) = new(Float64.(d), sp)
Raw(d, sp = _Species) = new(@tographdata(d, Vector{Float64}), sp)
end
F.implied_blueprint_for(bp::Raw, ::_Species) = Species(length(bp.d))
@blueprint Raw "mortality values"
Expand Down
7 changes: 4 additions & 3 deletions src/components/nutrients/concentration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import .EN: Foodweb, Nutrients
mutable struct Raw <: Blueprint
c::Matrix{Float64}
nutrients::Brought(Nutrients.Nodes)
Raw(c, nt = Nutrients._Nodes) = new(Float64.(c), nt)
Raw(c, nt = Nutrients._Nodes) = new(@tographdata(c, Matrix{Float64}), nt)
end
F.implied_blueprint_for(bp::Raw, ::Nutrients._Nodes) = Nutrients.Nodes(size(bp.c)[2])
@blueprint Raw "producers × nutrients concentration matrix"
Expand Down Expand Up @@ -106,9 +106,10 @@ end
@expose_data edges begin
property(nutrients.concentration)
depends(Concentration)
@nutrients_index
row_index(raw -> @ref raw.producers.dense_index)
col_index(raw -> @ref raw.nutrients.index)
ref(raw -> raw._scratch[:nutrients_concentration])
get(Concentations{Float64}, "producer-to-nutrient link")
get(Concentrations{Float64}, "producer-to-nutrient link")
write!((raw, rhs::Real, i, j) -> Concentration_.check(rhs, (i, j)))
end

Expand Down
5 changes: 3 additions & 2 deletions src/components/nutrients/half_saturation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import .EN: Foodweb, Nutrients
mutable struct Raw <: Blueprint
h::Matrix{Float64}
nutrients::Brought(Nutrients.Nodes)
Raw(h, nt = Nutrients._Nodes) = new(Float64.(h), nt)
Raw(h, nt = Nutrients._Nodes) = new(@tographdata(h, Matrix{Float64}), nt)
end
F.implied_blueprint_for(bp::Raw, ::Nutrients._Nodes) = Nutrients.Nodes(size(bp.h)[2])
@blueprint Raw "producers × nutrients half-saturation matrix"
Expand Down Expand Up @@ -98,7 +98,8 @@ end
@expose_data edges begin
property(nutrients.half_saturation)
depends(HalfSaturation)
@nutrients_index
row_index(raw -> @ref raw.producers.dense_index)
col_index(raw -> @ref raw.nutrients.index)
ref(raw -> raw._scratch[:nutrients_half_saturation])
get(HalfSaturations{Float64}, "producer-to-nutrient link")
write!((raw, rhs::Real, i, j) -> HalfSaturation_.check(rhs, (i, j)))
Expand Down
2 changes: 1 addition & 1 deletion src/components/nutrients/nodes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mutable struct Names <: Blueprint
names::Vector{Symbol}

# Convert anything to symbols.
Names(names) = new(Symbol.(names))
Names(names) = new(@tographdata(names, Vector{Symbol}))
Names(names...) = new(Symbol.(collect(names)))

# From an index (useful when implied).
Expand Down
2 changes: 1 addition & 1 deletion src/components/nutrients/supply.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import .EN: Nutrients
mutable struct Raw <: Blueprint
s::Vector{Float64}
nutrients::Brought(Nutrients.Nodes)
Raw(s, nt = Nutrients._Nodes) = new(Float64.(s), nt)
Raw(s, nt = Nutrients._Nodes) = new(@tographdata(s, Vector{Float64}), nt)
end
F.implied_blueprint_for(bp::Raw, ::Nutrients._Nodes) = Nutrients.Nodes(length(bp.s))
@blueprint Raw "supply values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/nutrients/turnover.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import .EN: Nutrients
mutable struct Raw <: Blueprint
t::Vector{Float64}
nutrients::Brought(Nutrients.Nodes)
Raw(t, nt = Nutrients._Nodes) = new(Float64.(t), nt)
Raw(t, nt = Nutrients._Nodes) = new(@tographdata(t, Vector{Float64}), nt)
end
F.implied_blueprint_for(bp::Raw, ::Nutrients._Nodes) = Nutrients.Nodes(length(bp.t))
@blueprint Raw "turnover values"
Expand Down
2 changes: 1 addition & 1 deletion src/components/species.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mutable struct Names <: Blueprint
names::Vector{Symbol}

# Convert anything to symbols.
Names(names) = new(Symbol.(names))
Names(names) = new(@tographdata names Vector{Symbol})
Names(names...) = new(Symbol.(collect(names)))

# From an index (useful when implied).
Expand Down
2 changes: 1 addition & 1 deletion src/expose_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ macro expose_data(
rhs = convert($rhs_type, rhs)
catch
Framework.properr(
typeof(raw),
System{typeof(raw)},
$sfirst_path,
"Cannot set with a value of type $(typeof(rhs)): $(repr(rhs)).",
)
Expand Down
33 changes: 22 additions & 11 deletions src/graph_views.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Base.getindex(v::AbstractGraphDataView) = check_access_dim(v) # (trigger correct
Base.setindex!(v::AbstractGraphDataReadWriteView, rhs, access::Ref...) =
setindex!(v, rhs, access)
Base.setindex!(v::AbstractGraphDataReadOnlyView, args...) =
throw(ViewError(typeof(v), "This view into graph edges data is read-only."))
throw(ViewError(typeof(v), "This view into graph $(level_name(v))s data is read-only."))

function setindex!(v::AbstractGraphDataReadWriteView, rhs, access)
check_access_dim(v, access...)
Expand All @@ -124,6 +124,8 @@ inline_(access::Tuple) = join(repr.(access), ", ")
inline(access::Tuple) = "[$(inline_(access))]"
inline(access::Tuple, original) = "$(inline(access)) (=$(inline(original)))"
inline(access::Tuple, ::Tuple{Vararg{Int}}) = inline(access)
inline_size(access::Tuple) = "($(inline_(access)))"
inline_size(access::Tuple{Int64}) = "$(inline_(access))"

function to_checked_index(v::AbstractGraphDataView, index::Int...)
check_access(v, nothing, index)
Expand Down Expand Up @@ -160,14 +162,15 @@ level_name(v::AbstractGraphDataView) = level_name(typeof(v))
# Basic bound checks for dense views.

function check_dense_access(v::AbstractGraphDataView, ::Any, index::Tuple{Vararg{Int}})
all(0 .< index .<= length(v)) && return
all(0 .< index .<= size(v)) && return
item = uppercasefirst(item_name(v))
level = level_name(v)
s = plural(length(v))
z = size(v)
throw(ViewError(
typeof(v),
"$item index $(inline(index)) is off-bounds \
for a view into $(inline_(size(v))) $(level)$s data.",
for a view into $(inline_size(z)) $(level)$s data.",
))
end
plural(n) = n > 1 ? "s" : ""
Expand All @@ -192,7 +195,7 @@ function check_sparse_access(
refs = if isnothing(labels)
"index $(inline(index))"
else
"label$(n > 1 : "s" : "") $labels ($index)"
"label$(n > 1 ? "s" : "") $(inline(labels)) ($(inline(index)))"
end
throw(
ViewError(
Expand All @@ -204,7 +207,7 @@ function check_sparse_access(
end

function valid_refs_phrase(v, template, labels)
valids = collect(valid_refs(v, template, labels))
valids = sort!(collect(valid_refs(v, template, labels)))
if isempty(valids)
"There is no valid $(vref(labels)) for this template."
elseif length(valids) == 1
Expand All @@ -215,7 +218,7 @@ function valid_refs_phrase(v, template, labels)
are $(join_elided(valids, ", ", " and "; max))."
end
end
valid_refs_phrase(_, template::AbstractMatrix, ::Nothing) =
valid_refs_phrase(_, template::AbstractMatrix, ::Any) =
"Valid indices must comply to the following template:\n\
$(repr(MIME("text/plain"), template))"
vref(::Nothing) = "index"
Expand All @@ -234,6 +237,10 @@ end
# Convert labels to indexes (a mapping is available as `._index`).

function to_index(v::AbstractNodesView, s::Label)
if !hasfield(typeof(v), :_index)
item = item_name(v)
throw(ViewError(typeof(v), "No index to interpret $item node label $(repr(s))."))
end
map = v._index
y = Symbol(s)
if !haskey(map, y)
Expand Down Expand Up @@ -262,6 +269,7 @@ function to_index(v::AbstractEdgesView, s::Label, t::Label)
end
if !haskey(cols, z)
cols = sort(collect(keys(cols)))
item = item_name(v)
verr("Invalid $item edge target label: $(repr(z)). \
Expected $(either(cols)), got instead: $(repr(t)).")
end
Expand All @@ -281,20 +289,23 @@ function dimerr(reftype, v, level, exp, labs)
ViewError(
typeof(v),
"$level data are $exp-dimensional: \
cannot access $(item_name(v)) data values with $n $(reftype(n)): $labs.",
cannot access $(item_name(v)) data values with $n $(reftype(n)): \
$(inline(labs)).",
),
)
end
laberr(args...) = dimerr(n -> n > 1 ? "labels" : "label", args...)
inderr(args...) = dimerr(n -> n > 1 ? "indices" : "index", args...)
check_access_dim(v::AbstractNodesView) = inderr(v, "Nodes", 1, ())
check_access_dim(v::AbstractEdgesView) = inderr(v, "Edges", 2, ())
check_access_dim(::AbstractNodesView, _::Int) = nothing
check_access_dim(::AbstractEdgesView, _::Int, _::Int) = nothing
check_access_dim(::AbstractNodesView, _::Label) = nothing
check_access_dim(::AbstractEdgesView, _::Label, _::Label) = nothing
check_access_dim(v::AbstractNodesView, i::Int...) = inderr(v, "Nodes", 1, i)
check_access_dim(v::AbstractEdgesView, i::Int...) = inderr(v, "Edges", 2, i)
check_access_dim(::AbstractNodesView, ::Int) = nothing
check_access_dim(::AbstractEdgesView, ::Int, ::Int) = nothing
check_access_dim(v::AbstractNodesView, labels::Label...) = laberr(v, "Nodes", 1, labels)
check_access_dim(v::AbstractEdgesView, labels::Label...) = laberr(v, "Edges", 2, labels)
check_access_dim(::AbstractNodesView, ::Label) = nothing
check_access_dim(::AbstractEdgesView, ::Label, ::Label) = nothing
# Requesting vector[1, 1, 1, 1] is actuall valid in julia.
# Only trigger the error out of this very strict 1-situation.
check_access_dim(v::AbstractNodesView, i::Int, index::Int...) =
Expand Down
Loading

0 comments on commit 053855d

Please sign in to comment.