Skip to content

Commit cbfa3b0

Browse files
authored
Merge pull request #13 from VirtualPlantLab/ana-Intro_org_tutorials
Issues #2 and #9 fixed
2 parents 79e346a + f2b74d4 commit cbfa3b0

10 files changed

Lines changed: 156 additions & 76 deletions

File tree

docs/make.jl

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ makedocs(;
1313
edit_link="master",
1414
assets=String[],
1515
collapselevel = 1,
16-
footer = nothing
16+
footer = nothing,
17+
size_threshold = nothing
1718
),
1819
pages=[
1920
"Virtual Plant Laboratory" => "index.md",
@@ -25,15 +26,18 @@ makedocs(;
2526
"Ray tracing" => "manual/Raytracer.md",
2627
"3D visualization" => "manual/Visualization.md"
2728
],
28-
"Tutorials" => [
29-
"Algae growth" => "tutorials/algae.md",
30-
"The Koch snowflake" => "tutorials/snowflakes.md",
31-
"Tree" => "tutorials/tree.md",
32-
"Forest" => "tutorials/forest.md",
33-
"Growth forest" => "tutorials/growthforest.md",
34-
"Ray-traced forest" => "tutorials/raytracedforest.md",
35-
"Context sensitive rules" => "tutorials/context.md",
36-
"Relational queries" => "tutorials/relationalqueries.md"
29+
"Tutorials" => ["Intro" => "tutorials/intro_tut.md",
30+
"Getting started with VPL" =>
31+
["Algae growth" => "tutorials/getting_started/algae.md",
32+
"The Koch snowflake" => "tutorials/getting_started/snowflakes.md"],
33+
"From tree to forest" =>
34+
["Tree" => "tutorials/from_tree_forest/tree.md",
35+
"Forest" => "tutorials/from_tree_forest/forest.md",
36+
"Growth forest" => "tutorials/from_tree_forest/growthforest.md",
37+
"Ray-traced forest" => "tutorials/from_tree_forest/raytracedforest.md"],
38+
"More on rules and queries" =>
39+
["Context sensitive rules" => "tutorials/more_rules_queries/context.md",
40+
"Relational queries" => "tutorials/more_rules_queries/relationalqueries.md"]
3741
],
3842
"How-to guides" => [
3943
"Setting up a grid cloner" => "howto/GridCloner.md"

docs/src/tutorials/forest.md renamed to docs/src/tutorials/from_tree_forest/forest.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Alejandro Morales
44

55
Centre for Crop Systems Analysis - Wageningen University
66

7+
> ## TL;DR
8+
> Similar in functionality to [Tree]() tutorial with separate graphs for each tree
9+
> - Modify tree parameters for each tree
10+
> - Multithreaded simulation (grow trees in parallel)
11+
> - Scene customization (e.g., add soil)
12+
> - Export Scenes
13+
714
In this example we extend the tree example into a forest, where
815
each tree is described by a separate graph object and parameters driving the
916
growth of these trees vary across individuals following a predefined distribution.
@@ -47,7 +54,7 @@ end
4754
import .TreeTypes
4855
````
4956

50-
Create geometry + color for the internodes
57+
Create geometry and color for the *internodes*:
5158

5259
````julia
5360
function VirtualPlantLab.feed!(turtle::Turtle, i::TreeTypes.Internode, data)
@@ -59,7 +66,7 @@ function VirtualPlantLab.feed!(turtle::Turtle, i::TreeTypes.Internode, data)
5966
end
6067
````
6168

62-
Create geometry + color for the leaves
69+
Create geometry and color for the *leaves*:
6370

6471
````julia
6572
function VirtualPlantLab.feed!(turtle::Turtle, l::TreeTypes.Leaf, data)
@@ -74,7 +81,7 @@ function VirtualPlantLab.feed!(turtle::Turtle, l::TreeTypes.Leaf, data)
7481
end
7582
````
7683

77-
Insertion angle for the bud nodes
84+
Insertion angle for the bud nodes:
7885

7986
````julia
8087
function VirtualPlantLab.feed!(turtle::Turtle, b::TreeTypes.BudNode, data)
@@ -83,7 +90,7 @@ function VirtualPlantLab.feed!(turtle::Turtle, b::TreeTypes.BudNode, data)
8390
end
8491
````
8592

86-
Rules
93+
Rules for meristem and branches:
8794

8895
````julia
8996
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.Node() +
@@ -198,7 +205,7 @@ forest = vec(create_tree.(origins, growths, budbreaks, orientations));
198205

199206
By vectorizing `create_tree()` over the different arrays, we end up with an array
200207
of trees. Each tree is a different Graph, with its own nodes, rewriting rules
201-
and variables. This avoids having to create a large graphs to include all the
208+
and variables. This avoids having to create large graphs to include all the
202209
plants in a simulation. Below we will run a simulation, first using a sequential
203210
approach (i.e. using one core) and then using multiple cores in our computers (please check
204211
https://docs.julialang.org/en/v1/manual/multi-threading/ if the different cores are not being used
@@ -234,7 +241,7 @@ In the previous section, the simulation of growth was done sequentially, one tre
234241
after another (since the growth of a tree only depends on its own parameters). However,
235242
this can also be executed in multiple threads. In this case we use an explicit loop
236243
and execute the iterations of the loop in multiple threads using the macro `@threads`.
237-
Note that the rendering function can also be ran in parallel (i.e. the geometry will be
244+
Note that the rendering function can also be run in parallel (i.e. the geometry will be
238245
generated separately for each plant and the merge together):
239246

240247
````julia
@@ -260,7 +267,7 @@ render(Scene(newforest), parallel = true)
260267

261268
# Customizing the scene
262269

263-
Here we are going to customize the scene of our simulation by adding a horizontal tile represting soil and
270+
Here we are going to customize the scene of our simulation by adding a horizontal tile representing soil and
264271
tweaking the 3D representation. When we want to combine plants generated from graphs with any other
265272
geometric element it is best to combine all these geometries in a `GLScene` object. We can start the scene
266273
with the `newforest` generated in the above:
@@ -273,7 +280,7 @@ We can create the soil tile directly, without having to create a graph. The simp
273280
a special constructor `Rectangle` where one species a corner of the rectangle and two vectors defining the
274281
two sides of the vectors. Both the sides and the corner need to be specified with `Vec` just like in the
275282
above when we determined the origin of each plant. VPL offers some shortcuts: `O()` returns the origin
276-
(`Vec(0.0, 0.0, 0.0)`), whereas `X`, `Y` and `Z` returns the corresponding axes and you can scale them by
283+
(`Vec(0.0, 0.0, 0.0)`), whereas `X`, `Y` and `Z` returns the corresponding axes, and you can scale them by
277284
passing the desired length as input. Below, a rectangle is created on the XY plane with the origin as a
278285
corner and each side being 11 units long:
279286

@@ -291,8 +298,8 @@ VirtualPlantLab.add!(scene, mesh = soil, color = RGB(1,1,0))
291298

292299
We can now render the scene that combines the random forest of binary trees and a yellow soil. Notice that
293300
in all previous figures, a coordinate system with grids was being depicted. This is helpful for debugging
294-
your code but also to help setup the scene (e.g. if you are not sure how big the soil tile should be).
295-
Howver, it may be distracting for the visualization. It turns out that we can turn that off with
301+
your code but also to help set up the scene (e.g. if you are not sure how big the soil tile should be).
302+
However, it may be distracting for the visualization. It turns out that we can turn that off with
296303
`show_axes = false`:
297304

298305
````julia

docs/src/tutorials/growthforest.md renamed to docs/src/tutorials/from_tree_forest/growthforest.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ Alejandro Morales
44

55
Centre for Crop Systems Analysis - Wageningen University
66

7+
> ## TL;DR
8+
> Now we want to implement a more extended functionality of our [Forest]()!
9+
> - Growth rules, based on information stored in organs (dimensions, carbon assimilation)
10+
> - Update dimensions in function of assimilation
11+
> - Compute sink strength
12+
> - Merge Scenes
13+
> - Generate forest on grid and retrieve canopy-level data (e.g., LAI)
14+
>
715
816
In this example we extend the binary forest example to have more complex, time-
917
dependent development and growth based on carbon allocation. For simplicity, the
@@ -129,7 +137,7 @@ end
129137
### Development
130138

131139
The meristem rule is now parameterized by the initial states of the leaves and
132-
internodes and will only be triggered every X days where X is the plastochron.
140+
internodes and will only be triggered every X days, where X is the plastochron.
133141

134142
````julia
135143
# Create right side of the growth rule (parameterized by the initial states

docs/src/tutorials/raytracedforest.md renamed to docs/src/tutorials/from_tree_forest/raytracedforest.md

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@ Alejandro Morales
44

55
Centre for Crop Systems Analysis - Wageningen University
66

7-
8-
In this example we extend the forest growth model to include PAR interception a
7+
> ## TL;DR
8+
> Now we want to forest growth model that PAR interception and introduces user to the ray-tracer.
9+
> - Include material as a property for each object
10+
> - Create sky for specific conditions and locations
11+
> - Layer different types of radiation in sky domes (e.g., direct and diffuse)
12+
> - Combine graph and sky with a ray-tracer
13+
> - Compute growth and biomass production according to PAR interception and RUE
14+
>
15+
16+
In this example we extend the forest growth model to include PAR interception and
917
radiation use efficiency to compute the daily growth rate.
1018

1119
The following packages are needed:
@@ -27,9 +35,9 @@ Random.seed!(123456789)
2735
### Node types
2836

2937
The data types needed to simulate the trees are given in the following
30-
module. The difference with respec to the previous model is that Internodes and
38+
module. The difference with respect to the previous model is that Internodes and
3139
Leaves have optical properties needed for ray tracing (they are defined as
32-
Lambertian surfaces).
40+
[Lambertian surfaces](https://doi.org/10.1016/j.ecolmodel.2006.04.010)).
3341

3442
````julia
3543
# Data types
@@ -126,7 +134,7 @@ end
126134
### Development
127135

128136
The meristem rule is now parameterized by the initial states of the leaves and
129-
internodes and will only be triggered every X days where X is the plastochron.
137+
internodes and will only be triggered every X days, where X is the plastochron.
130138

131139
````julia
132140
# Create right side of the growth rule (parameterized by the initial states
@@ -227,7 +235,7 @@ end
227235

228236
Given the scene, we can create the light sources that can approximate the solar
229237
irradiance on a given day, location and time of the day using the functions from
230-
the package (see package documentation for details). Given the latitude,
238+
the package (see package documentation for details). Given the latitude,
231239
day of year and fraction of the day (`f = 0` being sunrise and `f = 1` being sunset),
232240
the function `clear_sky()` computes the direct and diffuse solar radiation assuming
233241
a clear sky. These values may be converted to different wavebands and units using
@@ -273,19 +281,18 @@ end
273281
The 3D scene and the light sources are then combined into a `RayTracer` object,
274282
together with general settings for the ray tracing simulation chosen via `RTSettings()`.
275283
The most important settings refer to the Russian roulette system and the grid
276-
cloner (see section on Ray Tracing for details). The settings for the Russian
284+
cloner (see section on [Ray tracing](https://virtualplantlab.com/dev/manual/Raytracer/)). The settings for the Russian
277285
roulette system include the number of times a ray will be traced
278286
deterministically (`maxiter`) and the probability that a ray that exceeds `maxiter`
279287
is terminated (`pkill`). The grid cloner is used to approximate an infinite canopy
280288
by replicating the scene in the different directions (`nx` and `ny` being the
281289
number of replicates in each direction along the x and y axes, respectively). It
282290
is also possible to turn on parallelization of the ray tracing simulation by
283-
setting `parallel = true` (currently this uses Julia's builtin multithreading
291+
setting `parallel = true` (currently this uses Julia's built-in multithreading
284292
capabilities).
285293

286-
In addition `RTSettings()`, an acceleration structure and a splitting rule can
287-
be defined when creating the `RayTracer` object (see ray tracing documentation
288-
for details). The acceleration structure allows speeding up the ray tracing
294+
In addition, `RTSettings()`, an acceleration structure and a splitting rule can
295+
be defined when creating the `RayTracer` object. The acceleration structure allows speeding up the ray tracing
289296
by avoiding testing all rays against all objects in the scene.
290297

291298
````julia
@@ -317,7 +324,7 @@ the `power()` function returns three different values, one for each waveband,
317324
but they are added together as RUE is defined for total PAR.
318325

319326
Run the ray tracer, calculate PAR absorbed per tree and add it to the daily
320-
total using general weighted quadrature formula
327+
total using general weighted quadrature formula:
321328

322329
````julia
323330
function calculate_PAR!(forest; DOY = 182)
@@ -335,7 +342,7 @@ function calculate_PAR!(forest; DOY = 182)
335342
end
336343
````
337344

338-
Reset PAR absorbed by the tree (at the start of a new day)
345+
Reset PAR absorbed by the tree (at the start of a new day):
339346

340347
````julia
341348
function reset_PAR!(forest)
@@ -349,7 +356,7 @@ end
349356
### Growth
350357

351358
We need some functions to compute the length and width of a leaf or internode
352-
from its biomass
359+
from its biomass.
353360

354361
````julia
355362
function leaf_dims(biomass, vars)
@@ -445,7 +452,7 @@ function grow!(tree, all_leaves, all_internodes)
445452
end
446453
````
447454

448-
Finally, we need to update the dimensions of the organs. The leaf dimensions are
455+
Finally, we need to update the dimensions of the organs. The leaf dimensions are:
449456

450457
````julia
451458
function size_leaves!(all_leaves, tvars)

docs/src/tutorials/tree.md renamed to docs/src/tutorials/from_tree_forest/tree.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Alejandro Morales
44

55
Centre for Crop Systems Analysis - Wageningen University
66

7+
> ### TL;DR
8+
> - Define different types of nodes (introduction to name spaces)
9+
> - Store data in graph (plant-base) vs. in graph node (node-base)
10+
> - Define parameters at the graph-level and node-level
11+
>
712
813
In this example we build a 3D representation of a binary TreeTypes. Although this will not look like a real plant, this example will help introduce additional features of VPL.
914

@@ -15,15 +20,15 @@ The model requires five types of nodes:
1520

1621
*Node*: What is left after a meristem produces a new organ (it separates internodes). They contain no data or geometry (so also a point) but are required to keep the branching structure of the tree as well as connecting leaves.
1722

18-
*Bud*: These are dormant meristems associated to tree nodes. When they are activated, they become an active meristem that produces a branch. They contain no data or geometry but they change the orientation of the turtle.
23+
*Bud*: These are dormant meristems associated to tree nodes. When they are activated, they become an active meristem that produces a branch. They contain no data or geometry, but they change the orientation of the turtle.
1924

20-
*BudNode*: The node left by a bud after it has been activated. They contain no data or geometry but they change the orientation of the turtle.
25+
*BudNode*: The node left by a bud after it has been activated. They contain no data or geometry, but they change the orientation of the turtle.
2126

2227
*Leaf*: These are the nodes associated to leaves in the TreeTypes. They are represented by ellipses with a particular orientation and insertion angle. The insertion angle is assumed constant, but the orientation angle varies according to an elliptical phyllotaxis rule.
2328

24-
In this first simple model, only internodes grow over time according to a relative growth rate, whereas leaves are assumed to be of fixed sized determined at their creation. For simplicity, all active meristems will produce an phytomer (combination of node, internode, leaves and buds) per time step. Bud break is assumed stochastic, with a probability that increases proportional to the number of phytomers from the apical meristem (up to 1). In the following tutorials, these assumptions are replaced by more realistic models of light interception, photosynthesis, etc.
29+
In this first simple model, only internodes grow over time according to a relative growth rate, whereas leaves are assumed to be of fixed sized determined at their creation. For simplicity, all active meristems will produce a phytomer (combination of node, internode, leaves and buds) per time step. Bud break is assumed stochastic, with a probability that increases proportional to the number of phytomers from the apical meristem (up to 1). In the following tutorials, these assumptions are replaced by more realistic models of light interception, photosynthesis, etc.
2530

26-
In order to simulate growth of the 3D binary tree, we need to define a parameter describing the relative rate at which each internode elongates in each iteration of the simulation, a coefficient to compute the probability of bud break as well as the insertion and orientation angles of the leaves. We could stored these values as global constants, but VPL offers to opportunity to store them per plant. This makes it easier to manage multiple plants in the same simulation that may belong to different species, cultivars, ecotypes or simply to simulate plant-to-plant variation. Graphs in VPL can store an object of any user-defined type that will me made accessible to graph rewriting rules and queries. For this example, we define a data type `treeparams` that holds the relevant parameters. We use `Base.@kwdef` to assign default values to all parameters and allow to assign them by name.
31+
In order to simulate growth of the 3D binary tree, we need to define a parameter describing the relative rate at which each internode elongates in each iteration of the simulation, a coefficient to compute the probability of bud break as well as the insertion and orientation angles of the leaves. We could store these values as global constants, but VPL offers to opportunity to store them per plant. This makes it easier to manage multiple plants in the same simulation that may belong to different species, cultivars, ecotypes or simply to simulate plant-to-plant variation. Graphs in VPL can store an object of any user-defined type that will be made accessible to graph rewriting rules and queries. For this example, we define a data type `treeparams` that holds the relevant parameters. We use `Base.@kwdef` to assign default values to all parameters and allow to assign them by name.
2732

2833
````julia
2934
using VirtualPlantLab
@@ -91,7 +96,7 @@ function VirtualPlantLab.feed!(turtle::Turtle, b::TreeTypes.BudNode, vars)
9196
end
9297
````
9398

94-
The growth rule for a branch within a tree is simple: a phytomer (or basic unit of morphology) is composed of a node, a leaf, a bud node, an internode and an active meristem at the end. Each time step, the meristem is replaced by a new phytomer, allowing for developmemnt within a branch.
99+
The growth rule for a branch within a tree is simple: a phytomer (or basic unit of morphology) is composed of a node, a leaf, a bud node, an internode and an active meristem at the end. Each time step, the meristem is replaced by a new phytomer, allowing for the development within a branch.
95100

96101
````julia
97102
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.Node() +
@@ -152,7 +157,7 @@ function elongate!(tree, query)
152157
end
153158
````
154159

155-
Note that we use `vars` on the `Graph` object to extract the object that was stored inside of it. Also, as this function will modify the graph which is passed as input, we append an `!` to the name (this not a special syntax of the language, its just a convention in the Julia community). Also, in this case, the query object is kept separate from the graph. We could have also stored it inside the graph like we did for the parameter `growth`. We could also have packaged the graph and the query into another type representing an individual TreeTypes. This is entirely up to the user and indicates that a model can be implemented in many differences ways with VPL.
160+
Note that we use `vars` on the `Graph` object to extract the object that was stored inside of it. Also, as this function will modify the graph which is passed as input, we append an `!` to the name (this not a special syntax of the language, it's just a convention in the Julia community). Also, in this case, the query object is kept separate from the graph. We could have also stored it inside the graph like we did for the parameter `growth`. We could also have packaged the graph and the query into another type representing an individual TreeTypes. This is entirely up to the user and indicates that a model can be implemented in many differences ways with VPL.
156161

157162
Simulating the growth a tree is a matter of elongating the internodes and applying the rules to create new internodes:
158163

0 commit comments

Comments
 (0)