Skip to content

Commit c633270

Browse files
committed
2 parents 77c867a + 2203d7e commit c633270

4 files changed

Lines changed: 51 additions & 46 deletions

File tree

docs/src/tutorials/from_tree_forest/forest.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Forest
22

3-
Alejandro Morales
3+
Alejandro Morales and Ana Ernst
44

55
Centre for Crop Systems Analysis - Wageningen University
66

77
> ## TL;DR
8-
> Similar in functionality to [Tree]() tutorial with separate graphs for each tree
8+
> Similar in functionality to [Tree](https://virtualplantlab.com/dev/tutorials/from_tree_forest/tree/) tutorial with separate graphs for each tree
99
> - Modify tree parameters for each tree
1010
> - Multithreaded simulation (grow trees in parallel)
1111
> - Scene customization (e.g., add soil)
@@ -28,8 +28,8 @@ module TreeTypes
2828
struct Meristem <: VirtualPlantLab.Node end
2929
# Bud
3030
struct Bud <: VirtualPlantLab.Node end
31-
# Node
32-
struct Node <: VirtualPlantLab.Node end
31+
# TreeNode
32+
struct TreeNode <: VirtualPlantLab.Node end
3333
# BudNode
3434
struct BudNode <: VirtualPlantLab.Node end
3535
# Internode (needs to be mutable to allow for changes over time)
@@ -46,8 +46,8 @@ module TreeTypes
4646
growth::Float64 = 0.1
4747
budbreak::Float64 = 0.25
4848
phyllotaxis::Float64 = 140.0
49-
leaf_angle::Float64 = 30.0
50-
branch_angle::Float64 = 45.0
49+
leaf_angle::Float64 = 45.0
50+
branch_angle::Float64 = 30.0
5151
end
5252
end
5353

@@ -93,7 +93,7 @@ end
9393
Rules for meristem and branches:
9494

9595
````julia
96-
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.Node() +
96+
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.TreeNode() +
9797
(TreeTypes.Bud(), TreeTypes.Leaf()) +
9898
TreeTypes.Internode() + TreeTypes.Meristem())
9999

@@ -179,13 +179,13 @@ We may assume that the initial orientation is uniformly distributed between 0 an
179179
orientations = [rand()*360.0 for i = 1:2.0:20.0, j = 1:2.0:20.0]
180180
````
181181

182-
For the `growth` and `budbreak` parameters we will assumed that they follow a
182+
For the `growth` and `budbreak` parameters we will be assumed to follow a
183183
LogNormal and Beta distribution, respectively. We can generate random
184184
values from these distributions using the `Distributions` package. For the
185185
relative growth rate:
186186

187187
````julia
188-
growths = rand(LogNormal(-2, 0.3), 10, 10)
188+
growths = rand(LogNormal(-2, 0.2), 10, 10)
189189
histogram(vec(growths))
190190
````
191191

@@ -200,7 +200,7 @@ Now we can create our forest by calling the `create_tree` function we defined ea
200200
with the correct inputs per tree:
201201

202202
````julia
203-
forest = vec(create_tree.(origins, growths, budbreaks, orientations));
203+
forest = vec(create_tree.(origins, growths, budbreaks, orientations))
204204
````
205205

206206
By vectorizing `create_tree()` over the different arrays, we end up with an array
@@ -217,7 +217,7 @@ We can simulate the growth of each tree by applying the method `simulate` to eac
217217
tree, creating a new version of the forest (the code below is an array comprehension)
218218

219219
````julia
220-
newforest = [simulate(tree, getInternode, 2) for tree in forest];
220+
newforest = [simulate(tree, getInternode, 2) for tree in forest]
221221
````
222222

223223
And we can render the forest with the function `render` as in the binary tree
@@ -273,7 +273,7 @@ geometric element it is best to combine all these geometries in a `GLScene` obje
273273
with the `newforest` generated in the above:
274274

275275
````julia
276-
scene = Scene(newforest);
276+
scene = Scene(newforest)
277277
````
278278

279279
We can create the soil tile directly, without having to create a graph. The simplest approach is two use

docs/src/tutorials/from_tree_forest/growthforest.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ module TreeTypes
5757
# Bud
5858
struct Bud <: VirtualPlantLab.Node end
5959
# Node
60-
struct Node <: VirtualPlantLab.Node end
60+
struct TreeNode <: VirtualPlantLab.Node end
6161
# BudNode
6262
struct BudNode <: VirtualPlantLab.Node end
6363
# Internode (needs to be mutable to allow for changes over time)
@@ -92,8 +92,8 @@ module TreeTypes
9292
plastochron::Int64 = 5 ## Number of days between phytomer production
9393
leaf_expansion::Float64 = 15.0 ## Number of days that a leaf expands
9494
phyllotaxis::Float64 = 140.0
95-
leaf_angle::Float64 = 30.0
96-
branch_angle::Float64 = 45.0
95+
leaf_angle::Float64 = 45.0
96+
branch_angle::Float64 = 30.0
9797
end
9898
end
9999

@@ -145,7 +145,7 @@ internodes and will only be triggered every X days, where X is the plastochron.
145145
function create_meristem_rule(vleaf, vint)
146146
meristem_rule = Rule(TreeTypes.Meristem,
147147
lhs = mer -> mod(data(mer).age, graph_data(mer).plastochron) == 0,
148-
rhs = mer -> TreeTypes.Node() +
148+
rhs = mer -> TreeTypes.TreeNode() +
149149
(TreeTypes.Bud(),
150150
TreeTypes.Leaf(biomass = vleaf.biomass,
151151
length = vleaf.length,
@@ -178,7 +178,7 @@ function prob_break(bud)
178178
child = children(child)[1]
179179
data_child = data(child)
180180
# If we encounter a node, extract the next internode
181-
elseif data_child isa TreeTypes.Node
181+
elseif data_child isa TreeTypes.TreeNode
182182
child = filter(x -> data(x) isa TreeTypes.Internode, children(child))[1]
183183
data_child = data(child)
184184
else

docs/src/tutorials/from_tree_forest/raytracedforest.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
# Ray-traced forest
22

3-
Alejandro Morales
3+
Alejandro Morales and Ana Ernst
44

55
Centre for Crop Systems Analysis - Wageningen University
66

77
> ## TL;DR
88
> 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
9+
> - Include [material](https://virtualplantlab.com/dev/manual/Raytracer/#Materials) as a property for each object
10+
> - Create sky for specific conditions and locations using [SkyDomes](https://virtualplantlab.com/dev/VPLVerse/SkyDomes/)
1111
> - Layer different types of radiation in sky domes (e.g., direct and diffuse)
1212
> - Combine graph and sky with a ray-tracer
13-
> - Compute growth and biomass production according to PAR interception and RUE
13+
> - Compute growth and biomass production according to PAR interception and RUE
1414
>
1515
16-
In this example we extend the forest growth model to include PAR interception and
17-
radiation use efficiency to compute the daily growth rate.
16+
In this example we extend the [Growth Forest](https://virtualplantlab.com/dev/tutorials/from_tree_forest/growthforest/) model to include PAR interception and radiation use efficiency to compute the daily growth rate.
1817

1918
The following packages are needed:
2019

@@ -50,8 +49,8 @@ module TreeTypes
5049
end
5150
# Bud
5251
struct Bud <: VirtualPlantLab.Node end
53-
# Node
54-
struct Node <: VirtualPlantLab.Node end
52+
# TreeNode
53+
struct TreeNode <: VirtualPlantLab.Node end
5554
# BudNode
5655
struct BudNode <: VirtualPlantLab.Node end
5756
# Internode (needs to be mutable to allow for changes over time)
@@ -89,8 +88,8 @@ module TreeTypes
8988
plastochron::Int64 = 5 ## Number of days between phytomer production
9089
leaf_expansion::Float64 = 15.0 ## Number of days that a leaf expands
9190
phyllotaxis::Float64 = 140.0
92-
leaf_angle::Float64 = 30.0
93-
branch_angle::Float64 = 45.0
91+
leaf_angle::Float64 = 45.0
92+
branch_angle::Float64 = 30.0
9493
end
9594
end
9695

@@ -142,7 +141,7 @@ internodes and will only be triggered every X days, where X is the plastochron.
142141
function create_meristem_rule(vleaf, vint)
143142
meristem_rule = Rule(TreeTypes.Meristem,
144143
lhs = mer -> mod(data(mer).age, graph_data(mer).plastochron) == 0,
145-
rhs = mer -> TreeTypes.Node() +
144+
rhs = mer -> TreeTypes.TreeNode() +
146145
(TreeTypes.Bud(),
147146
TreeTypes.Leaf(biomass = vleaf.biomass,
148147
length = vleaf.length,
@@ -175,11 +174,11 @@ function prob_break(bud)
175174
child = children(child)[1]
176175
data_child = data(child)
177176
# If we encounter a node, extract the next internode
178-
elseif data_child isa TreeTypes.Node
177+
elseif data_child isa TreeTypes.TreeNode
179178
child = filter(x -> data(x) isa TreeTypes.Internode, children(child))[1]
180179
data_child = data(child)
181180
else
182-
error("Should be Internode, Node or Meristem")
181+
error("Should be Internode, TreeNode or Meristem")
183182
end
184183
end
185184
# Compute the probability of bud break as function of distance and
@@ -221,6 +220,7 @@ function create_soil()
221220
VirtualPlantLab.translate!(soil, Vec(0.0, 10.5, 0.0)) ## Corner at (0,0,0)
222221
return soil
223222
end
223+
224224
function create_scene(forest)
225225
# These are the trees
226226
scene = Scene(vec(forest))
@@ -251,10 +251,12 @@ function create_sky(;scene, lat = 52.0*π/180.0, DOY = 182)
251251
dec = declination(DOY)
252252
DL = day_length(lat, dec)*3600
253253
# Compute solar irradiance
254-
temp = [clear_sky(lat = lat, DOY = DOY, f = f) for f in fs] # W/m2
254+
temp = [clear_sky(lat = lat, DOY = DOY, f = f) for f in fs] # W m2
255255
Ig = getindex.(temp, 1)
256256
Idir = getindex.(temp, 2)
257257
Idif = getindex.(temp, 3)
258+
theta = getindex.(temp, 4)
259+
phi = getindex.(temp, 5)
258260
# Conversion factors to PAR for direct and diffuse irradiance
259261
f_dir = waveband_conversion(Itype = :direct, waveband = :PAR, mode = :power)
260262
f_dif = waveband_conversion(Itype = :diffuse, waveband = :PAR, mode = :power)
@@ -268,8 +270,11 @@ function create_sky(;scene, lat = 52.0*π/180.0, DOY = 182)
268270
nrays_dif = 1_000_000, ## Total number of rays for diffuse solar radiation
269271
sky_model = StandardSky, ## Angular distribution of solar radiation
270272
dome_method = equal_solid_angles, ## Discretization of the sky dome
273+
# Angles
271274
ntheta = 9, ## Number of discretization steps in the zenith angle
272-
nphi = 12) ## Number of discretization steps in the azimuth angle
275+
theta_dir = theta, ## Direction of the zenith angle
276+
nphi = 12, ## Number of discretization steps in the azimuth angle
277+
phi_dir = phi) ## Direction of the azimuth angle
273278
# Add direct sources for different times of the day
274279
for I in Idir_PAR
275280
push!(dome, sky(scene, Idir = I/10*DL, nrays_dir = 100_000, Idif = 0.0)[1])
@@ -514,7 +519,7 @@ histogram(vec(orientations))
514519
origins = [Vec(i,j,0) for i = 1:2.0:20.0, j = 1:2.0:20.0];
515520
````
516521

517-
The following initalizes a tree based on the origin, orientation and RUE:
522+
The following initializes a tree based on the origin, orientation and RUE:
518523

519524
````julia
520525
function create_tree(origin, orientation, RUE)

docs/src/tutorials/from_tree_forest/tree.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Tree
22

3-
Alejandro Morales
3+
Alejandro Morales and Ana Ernst
44

55
Centre for Crop Systems Analysis - Wageningen University
66

@@ -14,17 +14,17 @@ In this example we build a 3D representation of a binary TreeTypes. Although thi
1414

1515
The model requires five types of nodes:
1616

17-
*Meristem*: These are the nodes responsible for growth of new organs in our binary TreeTypes. They contain no data or geometry (i.e. they are a point in the 3D structure).
17+
- *Meristem*: These are the nodes responsible for growth of new organs in our binary TreeTypes. They contain no data or geometry (i.e. they are a point in the 3D structure).
1818

19-
*Internode*: The result of growth of a branch, between two nodes. Internodes are represented by cylinders with a fixed width but variable length.
19+
- *Internode*: The result of growth of a branch, between two nodes. Internodes are represented by cylinders with a fixed width but variable length.
2020

21-
*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.
21+
- *TreeNode*: 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.
2222

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.
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.
2424

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.
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.
2626

27-
*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.
27+
- *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.
2828

2929
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.
3030

@@ -41,8 +41,8 @@ module TreeTypes
4141
struct Meristem <: VirtualPlantLab.Node end
4242
# Bud
4343
struct Bud <: VirtualPlantLab.Node end
44-
# Node
45-
struct Node <: VirtualPlantLab.Node end
44+
# TreeNode
45+
struct TreeNode <: VirtualPlantLab.Node end
4646
# BudNode
4747
struct BudNode <: VirtualPlantLab.Node end
4848
# Internode (needs to be mutable to allow for changes over time)
@@ -59,8 +59,8 @@ module TreeTypes
5959
growth::Float64 = 0.1
6060
budbreak::Float64 = 0.25
6161
phyllotaxis::Float64 = 140.0
62-
leaf_angle::Float64 = 30.0
63-
branch_angle::Float64 = 45.0
62+
leaf_angle::Float64 = 45.0
63+
branch_angle::Float64 = 30.0
6464
end
6565
end
6666
````
@@ -99,9 +99,9 @@ end
9999
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.
100100

101101
````julia
102-
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.Node() +
102+
meristem_rule = Rule(TreeTypes.Meristem, rhs = mer -> TreeTypes.TreeNode() +
103103
(TreeTypes.Bud(), TreeTypes.Leaf()) +
104-
TreeTypes.Internode() + TreeTypes.Meristem())
104+
TreeTypes.Internode() + TreeTypes.Meristem())
105105
````
106106

107107
In addition, every step of the simulation, each bud may break, creating a new branch. The probability of bud break is proportional to the number of phytomers from the apical meristem (up to 1), which requires a relational rule to count the number of internodes in the graph up to reaching a meristem. When a bud breaks, it is replaced by a bud node, an internode and a new meristem. This new meristem becomes the apical meristem of the new branch, such that `meristem_rule` would apply. Note how we create an external function to compute whether a bud breaks or not. This is useful to keep the `branch_rule` rule simple and readable, while allow for a relatively complex bud break model. It also makes it easier to debug the bud break model, since it can be tested independently of the graph rewriting.

0 commit comments

Comments
 (0)