02_user_tutorials:02_growth_modelling:02_simple-tomato-model
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| 02_user_tutorials:02_growth_modelling:02_simple-tomato-model [2025/01/24 13:15] – removed - external edit (Unknown date) 127.0.0.1 | 02_user_tutorials:02_growth_modelling:02_simple-tomato-model [2025/01/24 16:31] (current) – tim2 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | {{howhard> | ||
| + | ====== A simple tomato plant model ====== | ||
| + | In this tutorial we will create a simple model of a tomato plant architecture. | ||
| + | |||
| + | ===== Preliminary steps ===== | ||
| + | |||
| + | We start a new project by opening a new RGG template model (File -> New -> RGG Project). | ||
| + | |||
| + | The simple model that we are going to create will have the following structure: | ||
| + | |||
| + | <code java> | ||
| + | |||
| + | // modules | ||
| + | |||
| + | // parameters | ||
| + | |||
| + | protected void init() | ||
| + | [ | ||
| + | Axiom ==> | ||
| + | // initial structure | ||
| + | ; | ||
| + | ] | ||
| + | |||
| + | public void run() | ||
| + | [ | ||
| + | // rewriting rule | ||
| + | ] | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ===== Organs ===== | ||
| + | |||
| + | As first, we specify a base module '' | ||
| + | |||
| + | <code java> | ||
| + | module Organ(super.length) extends M(length) | ||
| + | { | ||
| + | int rank; | ||
| + | | ||
| + | { | ||
| + | rank = 1; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Now we can specify a number of modules for different organ types that we observe in a tomato plant. | ||
| + | |||
| + | <code java> | ||
| + | module Apex extends Organ; | ||
| + | module Internode extends Organ; | ||
| + | module Leaf extends Organ; | ||
| + | module Truss extends Organ; | ||
| + | </ | ||
| + | |||
| + | ==== Model parameters ==== | ||
| + | |||
| + | Outside of the modules, we define model parameters that will be used later to specify the shape of organs. | ||
| + | |||
| + | <code java> | ||
| + | // leaf parameters | ||
| + | const double LEAF_LENGTH = 0.40; | ||
| + | const double PETIOLE_WIDTH = 0.01; | ||
| + | const double PHYLLOTAXIS_ANGLE = 137.51; | ||
| + | const double LEAF_ANGLE = 60; | ||
| + | |||
| + | // internode parameters | ||
| + | const double INTERNODE_LENGTH = 0.08; | ||
| + | const double INTERNODE_WIDTH = 0.02; | ||
| + | |||
| + | // truss parameters | ||
| + | const int NB_FRUITS = 5; | ||
| + | const double TRUSS_LENGTH = 0.1; | ||
| + | const double TRUSS_ANGLE = 60; | ||
| + | const double FRUIT_RADIUS = 0.02; | ||
| + | </ | ||
| + | |||
| + | ==== Specifying organ geometry ==== | ||
| + | |||
| + | We extend the modules' | ||
| + | |||
| + | An '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Apex extends Organ | ||
| + | ==> | ||
| + | Sphere(0.01).(setShader(RED)) | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | An '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Internode extends Organ | ||
| + | { | ||
| + | double width; | ||
| + | |||
| + | { | ||
| + | length = INTERNODE_LENGTH; | ||
| + | width = INTERNODE_WIDTH; | ||
| + | } | ||
| + | } | ||
| + | ==> | ||
| + | Cylinder(length, | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | For a leaf, we will start with a very simple representation. It will be made of a petiole (a green cylinder) and a rectangular blade. A turtle command '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Leaf extends Organ | ||
| + | { | ||
| + | double width; | ||
| + | double angle; | ||
| + | double petioleLength; | ||
| + | double petioleWidth; | ||
| + | | ||
| + | { | ||
| + | length = LEAF_LENGTH; | ||
| + | width = 0.5*LEAF_LENGTH; | ||
| + | angle = LEAF_ANGLE; | ||
| + | petioleLength = 0.2*LEAF_LENGTH; | ||
| + | petioleWidth = PETIOLE_WIDTH; | ||
| + | } | ||
| + | } | ||
| + | ==> | ||
| + | RL(angle) | ||
| + | // petiole | ||
| + | Cylinder(petioleLength, | ||
| + | // leaf blade | ||
| + | Parallelogram(length-petioleLength, | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | Truss will be made of multiple fruits ('' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Truss extends Organ | ||
| + | { | ||
| + | {length = TRUSS_LENGTH; | ||
| + | } | ||
| + | ==> | ||
| + | RL(TRUSS_ANGLE) RH(90) | ||
| + | for (int i: | ||
| + | Cylinder(length/ | ||
| + | [ | ||
| + | if(i%2==0) ( | ||
| + | RH(90) | ||
| + | ) else ( | ||
| + | RH(-90) | ||
| + | ) | ||
| + | RU(60) | ||
| + | Cylinder(0.02, | ||
| + | // fruit | ||
| + | Sphere(FRUIT_RADIUS).(setShader(RED)) | ||
| + | ] | ||
| + | RU(-20) | ||
| + | ) | ||
| + | ; | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== The initial condition ===== | ||
| + | |||
| + | The initial structure, the axiom, is an apex. | ||
| + | |||
| + | <code java> | ||
| + | protected void init() | ||
| + | [ | ||
| + | Axiom ==> Apex; | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | ===== Rewriting rules ===== | ||
| + | |||
| + | Now we can specify rewriting rules for apex. | ||
| + | |||
| + | First, we specify rewriting rules for vegetative development of the primary shoot in tomato. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | public void run() | ||
| + | [ | ||
| + | a:Apex ==> | ||
| + | Internode | ||
| + | [Leaf] | ||
| + | RH(PHYLLOTAXIS_ANGLE) | ||
| + | a | ||
| + | ; | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | The turtle command '' | ||
| + | |||
| + | Now that we have specified the '' | ||
| + | |||
| + | By applying the above rule to an apex 7 times, we create a small plant made of 7 internodes and 7 leaves. | ||
| + | |||
| + | In tomato, after a certain number of phytomers (internodes with leaves), specified by a parameter '' | ||
| + | |||
| + | We first specify a new parameter for the number of phytomers in primary shoot: | ||
| + | |||
| + | <code java> | ||
| + | const int NB_VEG_PHYTOMERS = 8; | ||
| + | </ | ||
| + | |||
| + | Afterwards, we can add a condition inside our rule, as a switch between primary shoot and sympodial shoot. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | public void run() | ||
| + | [ | ||
| + | a:Apex ==> | ||
| + | Internode | ||
| + | // in primary shoot, every internode has a leaf | ||
| + | if (a[rank] <= NB_VEG_PHYTOMERS) ( | ||
| + | [Leaf] | ||
| + | // in sympodial shoot, only the first in every four | ||
| + | // internodes has a truss, otherwise it has a leaf | ||
| + | ) else ( | ||
| + | if ((a[rank] - NB_VEG_PHYTOMERS) % 4 == 1) ( | ||
| + | [Truss] | ||
| + | ) else ( | ||
| + | [Leaf] | ||
| + | ) | ||
| + | ) | ||
| + | RH(PHYLLOTAXIS_ANGLE) | ||
| + | a | ||
| + | {a[rank]++; | ||
| + | ; | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | Note, that in this simple model, we assumed that tomato plants don't form side shoots (in the greenhouse production of high-wire tomatoes, the side shoots are normally removed). | ||
| + | |||
| + | ===== Improving leaf structure ===== | ||
| + | |||
| + | Having captured the basic architecture of tomato plants, we can now improve the leaf structure. Tomato has a composed leaf, with a number of leaflet pairs and a terminal leaflet. We also add leaf curvature, by slightly bending down each segment of the leaf. | ||
| + | |||
| + | <code java> | ||
| + | const int NB_LEAFLET_PAIRS = 3; | ||
| + | </ | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Leaf extends Organ | ||
| + | { | ||
| + | ... | ||
| + | } | ||
| + | ==> | ||
| + | RL(angle) | ||
| + | // petiole | ||
| + | Cylinder(petioleLength, | ||
| + | |||
| + | { double segmentLength = (length-petioleLength)/ | ||
| + | |||
| + | // leaflet pairs | ||
| + | for (int i: | ||
| + | [RU(-80) RL(-30) Cylinder(0.04, | ||
| + | [RU( 80) RL(-30) Cylinder(0.04, | ||
| + | RL(20) | ||
| + | Cylinder(segmentLength, | ||
| + | ) | ||
| + | // terminal leaflet | ||
| + | Parallelogram(segmentLength, | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | ===== Improving leaflet shape ===== | ||
| + | |||
| + | So far, we used a simple parallelogram to approximate the shape of a leaflet. We can further refine the leaflet shape, for example by using a '' | ||
| + | |||
| + | For an example on how to generate a leaflet mesh, see the tutorial [[02_user_tutorials: | ||
| + | |||
| + | We use the code from the leaf triangulation tutorial to create a leaflet mesh '' | ||
| + | |||
| + | To use the leaflet mesh in our tomato model, we create a new module for leaflet: | ||
| + | |||
| + | <code java> | ||
| + | module Leaflet(double length) | ||
| + | ==> | ||
| + | RL(90) Scale(length, | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | Then we replace '' | ||
| + | |||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | module Leaf extends Organ | ||
| + | { | ||
| + | ... | ||
| + | } | ||
| + | ==> | ||
| + | ... | ||
| + | | ||
| + | // leaflet pairs | ||
| + | for (int i: | ||
| + | [RU(-80) RL(-30) Cylinder(0.04, | ||
| + | [RU( 80) RL(-30) Cylinder(0.04, | ||
| + | RL(20) | ||
| + | Cylinder(segmentLength, | ||
| + | ) | ||
| + | // terminal leaflet | ||
| + | Leaflet(segmentLength) | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
