Skip to content

Commit 7743db8

Browse files
committed
Distinct Blueprints/Components type hierarchies.
This deep refactoring of the Framework addresses and fixes #139. It fixes the semantics of the components library (*e.g.* `OmegaFromRawEdges` and `OmegaFromAllometry` are *not* two separate components) while making it more flexible and future-proof. Take this opportunity to tick the numerous additional Framework `TODO`s, contributing to polishing the whole library API experience. Summarize changes in a fresh `CHANGELOG.md`, suggesting to issue v0.2.x.
1 parent 092eb9c commit 7743db8

164 files changed

Lines changed: 17214 additions & 8482 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,231 @@
1+
# Version 0.2.x
2+
3+
## Breaking changes (minor)
4+
5+
- Components and blueprints are now two separate type hierachies.
6+
```julia-repl
7+
julia> Foodweb # The component.
8+
Foodweb (component for <internals>, expandable from:
9+
Matrix: boolean matrix of trophic links,
10+
Adjacency: adjacency list of trophic links,
11+
)
12+
julia> typeof(Foodweb)
13+
<Foodweb> (component type EcologicalNetworksDynamics._Foodweb)
14+
15+
julia> fw = Foodweb.Adjacency([:a => :b]) # A blueprint for this component.
16+
blueprint for <Foodweb>: Adjacency {
17+
A: {a: {b}},
18+
species: <implied blueprint for <Species>>,
19+
}
20+
julia> typeof(fw)
21+
Foodweb_.Adjacency (blueprint type for System{<internals>})
22+
julia> fw isa Foodweb
23+
false
24+
julia> fw isa Foodweb.Adjacency
25+
true
26+
```
27+
28+
- Components are singletons types
29+
whose fields are blueprint types expanding into themselves.
30+
```julia
31+
Species # The component.
32+
Species.Names # A blueprint to expand from a list of names.
33+
Species.Number # A blueprint to expand from a species count.
34+
```
35+
36+
- Components can be directly called
37+
to transfer input to correct blueprint constructors
38+
```julia-repl
39+
julia> Species(5) isa Species.Number
40+
true
41+
julia> Species(["a", "b", "c"]) isa Species.Names
42+
true
43+
```
44+
45+
This comes with minor incompatible changes
46+
to the available set of blueprint constructor methods.
47+
For instance the redundant form
48+
`BodyMass(M = [1, 2])` is not supported anymore,
49+
but `BodyMass([1, 2])` does the same
50+
and `BodyMass(Z = 1.5)` still works as expected.
51+
52+
- Model properties are now typically namespaced to ease future extensions.
53+
Equivalent `get_*` and `set_*!` methods may still exist
54+
but they are no longer exposed or recommended:
55+
use direct property accesses instead.
56+
```julia-repl
57+
julia> m = Model(Foodweb([:a => [:b, :c]]));
58+
julia> m.species # The namespace.
59+
Property space for '<internals>': .species
60+
.index
61+
.richness
62+
.label
63+
.names
64+
.number
65+
julia> m.species.number # (no more `m.n_species` or `get_n_species(m)`)
66+
3
67+
68+
julia> m.trophic # Another namespace.
69+
Property space for '<internals>': .trophic
70+
.levels
71+
.n_links
72+
.matrix
73+
.herbivory_matrix
74+
.carnivory_matrix
75+
.A
76+
julia> m.trophic.matrix
77+
3×3 EcologicalNetworksDynamics.TrophicMatrix:
78+
0 1 1
79+
0 0 0
80+
0 0 0
81+
```
82+
83+
- Some property names have changed. The following list is not exhaustive,
84+
but new names can easily be discovered using REPL autocompletion
85+
or the `properties(m)` and `properties(m.prop)` methods:
86+
- `model.trophic_links` becomes `model.trophic.matrix`,
87+
because it does yield a matrix and not some collection of "links".
88+
The alias `model.A` is still available.
89+
- Likewise,
90+
`model.herbivorous_links` becomes `model.trophic.herbivory_matrix` *etc.*
91+
- Akward plurals like `model.body_masses` and `model.metabolic_classes`
92+
become `model.body_mass` and `model.metabolic_class`.
93+
94+
- Julia allows linear indexing into 2D structures,
95+
but the package chooses instead to consider this a semantic flaw:
96+
```julia-repl
97+
julia> m = Model(
98+
Foodweb([:a => [:b, :c], :b => [:c, :d]]),
99+
Efficiency(:Miele2019; e_herbivorous = .1, e_carnivorous = .2),
100+
);
101+
m.e[5]
102+
ERROR: View error (EcologicalNetworksDynamics.EfficiencyRates):
103+
Edges data are 2-dimensional:
104+
cannot access trophic link data values with 1 index: [5].
105+
```
106+
107+
## New features
108+
109+
- Colored console display.
110+
```julia-repl
111+
julia> NutrientIntake() # (won't work in a .md file: try in your REPL)
112+
blueprint for <NutrientIntake>: NutrientIntake_ {
113+
r: <embedded blueprint for <GrowthRate>: Allometric {
114+
allometry: Allometry(p: (a: 1.0, b: -0.25), i: (), e: ()),
115+
}>,
116+
nodes: <embedded blueprint for <Nodes>: PerProducer {
117+
n: 1,
118+
}>,
119+
turnover: <embedded blueprint for <Turnover>: Flat {
120+
t: 0.25,
121+
}>,
122+
supply: <embedded blueprint for <Supply>: Flat {
123+
s: 4.0,
124+
}>,
125+
concentration: <embedded blueprint for <Concentration>: Flat {
126+
c: 0.5,
127+
}>,
128+
half_saturation: <embedded blueprint for <HalfSaturation>: Flat {
129+
h: 0.15,
130+
}>,
131+
}
132+
```
133+
134+
- Model properties available with `<tab>`-completion within the REPL.
135+
```julia-repl
136+
julia> m = Model(Foodweb([:a => [:b, :c]]));
137+
julia> m.trop|<tab> # -> m.trophic|
138+
julia> m.trophic.|<tab>
139+
A carnivory_matrix
140+
herbivory_matrix levels
141+
matrix n_links
142+
```
143+
144+
- Every blueprint *brought* by another is available as a brought field
145+
to be either *embedded*, *implied* or *unbrought*:
146+
```julia-repl
147+
julia> fw = Foodweb.Matrix([0 0; 1 0]) # Implied (brought if missing).
148+
blueprint for <Foodweb>: Matrix {
149+
A: 1 trophic link,
150+
species: <implied blueprint for <Species>>,
151+
}
152+
julia> fw.species = [:a, :b]; # Embedded (brought, erroring if already present).
153+
fw
154+
blueprint for <Foodweb>: Matrix {
155+
A: 1 trophic link,
156+
species: <embedded blueprint for <Species>: Names {
157+
names: [:a, :b],
158+
}>,
159+
}
160+
julia> fw.species = nothing; # Unbrought (error if missing).
161+
fw
162+
blueprint for <Foodweb>: Matrix {
163+
A: 1 trophic link,
164+
species: <no blueprint brought>,
165+
}
166+
```
167+
168+
- Every "leaf" "geometrical" model property *i.e.* a property whose futher
169+
model topology does not depend on or is not planned to depend on
170+
is now writeable.
171+
```julia-repl
172+
julia> m = Model(fw, BodyMass(2));
173+
m.M[1] *= 10;
174+
m.M == [20, 2]
175+
true
176+
```
177+
178+
- Values are checked prior to expansion:
179+
```julia-repl
180+
julia> m = Model(fw, Efficiency(1.5))
181+
ERROR: Blueprint value cannot be expanded:
182+
Not a value within [0, 1]: e = 1.5.
183+
```
184+
185+
- Efficiency from a matrix implies a Foodweb.
186+
```julia-repl
187+
julia> e = 0.5;
188+
m = Model(Efficiency([
189+
0 e e
190+
0 0 e
191+
e 0 0
192+
]));
193+
has_component(m, Foodweb)
194+
true
195+
julia> m.A
196+
3×3 EcologicalNetworksDynamics.TrophicMatrix:
197+
0 1 1
198+
0 0 1
199+
1 0 0
200+
```
201+
202+
- Aggregated blueprints expansion is now clever enough
203+
to not error if two brought blueprints would bring the same component:
204+
```julia-repl
205+
julia> base = Model(
206+
Foodweb([:a => :b]),
207+
BodyMass(1),
208+
MetabolicClass(:all_invertebrates),
209+
)
210+
ni = NutrientIntake(nodes = 2; supply = [1, 2], turnover = [1, 2]);
211+
# 3 different specifications of Nutrients.Nodes.
212+
julia> ni.nodes
213+
<embedded blueprint for <Nutrients.Nodes>: Number {
214+
n: 2,
215+
}>
216+
julia> ni.supply.nutrients
217+
<implied blueprint for <Nutrients.Nodes>>
218+
julia> ni.turnover.nutrients
219+
<implied blueprint for <Nutrients.Nodes>>
220+
julia> base + ni; # But this still works fine.
221+
```
222+
223+
- Aggregated blueprints expansion is now clever enough
224+
to correctly figure a correct expansion order among brought blueprints:
225+
```julia-repl
226+
julia> ni = NutrientIntake(; turnover = [1, 2]);
227+
julia> base + ni; # `ni.turnover.nutrients` is expanded before `ni.supply`.
228+
```
1229
# v0.2.1
2230

3231
🚨 Quick patch to fix [#171]:

0 commit comments

Comments
 (0)