This is an old revision of the document!
Table of Contents
Exercise: Sources, sinks and assimilate transport in a virtual plant
Master 2, specialties “Seed Science and Plant Propagation” and “Plant Health”. Duration: about 2 hours. Work in pairs.
Learning objectives
At the end of this session you should be able to:
- explain how a functional–structural plant model (FSPM) links light interception → photosynthesis → transport → growth of sinks;
- identify, in real model code, where each of these processes is computed and which organs act as sources or sinks;
- run a model experiment rigorously: predict, run, observe, explain;
- modify the model to represent a situation from your own field (a pest or disease, or seed/fruit set);
- critically judge what a model does and does not represent.
You do not need to be a programmer. Every code change you are asked to make is given or guided step by step.
Schedule
| Part | Content | Time |
|---|---|---|
| 0 | Setup: open and run the model | 10 min |
| 1 | The biology in brief | 10 min |
| 2 | The model at a glance | 15 min |
| 3 | Run and observe | 15 min |
| 4 | Reading the code: production, transport, use | 25 min |
| 5 | Virtual experiments | 25 min |
| 6 | Your specialty: plant health or seed science | 15 min |
| 7 | Synthesis | 5 min |
| (Bonus) | Connect transport to fruit growth | for fast groups |
Part 0 – Setup (10 min)
- Start GroIMP and open the project
Transport.gsz(File → Open). - The model code is in the file
Example1.rgg. Open it in the text editor (Panels → Explorers → Files, then double-click the file). - In the toolbar of the 3D view you will find buttons for the public methods of the model. Here there is one:
grow. Each click ongrow= one time step = one hour of simulated time. - To reset the plant to its initial state, use the reset/“init” button (this executes the
init()method). Also, every time you save the code (Ctrl+S), the model is recompiled and reset. - Click
growa few times, then run it repeatedly (run/loop button) and stop it after ~100 steps.
Three charts open automatically:
| Chart | What it shows |
|---|---|
| Light intercepted by canopy | total light absorbed by all leaves during the last hour |
| Canopy photosynthesis | total amount of sugar stored in all leaves (stock, not the hourly production!) |
| Fruit growth | size of every fruit over time (one series per fruit) |
Colour code in the 3D view (false colours, for display only):
- Leaves: colour depends on the light they absorbed.
- Internodes: colour depends on their sugar content – the brighter, the more sugar.
- The brown floor is made of light-absorbing tiles; bright tiles receive more light.
The println messages (e.g. “sugar import into fruit”) appear in the XL Console window.
Part 1 – The biology in brief (10 min)
Plants produce sugars (assimilates) in source organs – mainly mature leaves – and use them in sink organs – young leaves, stems, roots, flowers, fruits and seeds. Sugars travel through the phloem. In the widely accepted Münch model, sugar loading at the source raises the osmotic pressure there, unloading at the sink lowers it, and the resulting pressure difference drives a mass flow from source to sink. A young leaf is first a sink and becomes a source when it reaches roughly a third to half of its final size (sink–source transition).
Questions (answer in 2–3 lines each):
- Q1. Name three sources and three sinks in a tomato plant bearing fruit.
- Q2. Give one example of a pest or pathogen that changes the source–sink balance of a crop, and say whether it mainly reduces the source, adds a sink, or blocks transport.
- Q3. In a seed crop, why can the number of fruits/seeds set early in the season limit the final seed size?
Part 2 – The model at a glance (15 min)
2.1 The organs (modules)
| Module | Role | Important attributes |
|---|---|---|
Bud | apical meristem; produces new metamers | rank (position on the axis), phyllo (countdown until next metamer), order (1 = main stem, 2 = branch, 3 = dormant bud) |
Internode | stem segment; transport pathway and small sink | length, age, rank, as (assimilate content) |
Node | attachment point of a leaf and a lateral bud | – |
Leaf | source (and sink while young) | length, width, al (absorbed light), age, as (assimilate content) |
Flower | becomes a fruit if enough sugar is available | age, max_age |
Fruit | main sink | size, age, as, no (fruit number) |
Tile | light-absorbing ground | al |
MyLight | a 200 W spotlight 50 units above the plant | – |
2.2 What happens during one call of grow()
public void grow () { run(); // 1. architecture: new metamers, flowers, fruits, leaf death lm.compute(); // 2. light model: ray tracing of the whole scene absorbAndGrow(); // 3. light absorption, photosynthesis, organ growth if (time % 24 == 0) { // 4. once every 24 steps ... for (int hour = 0; hour < 24; hour++) { transport(); // ... 24 rounds of transport } } updateChart(); // 5. charts time++; }
Q4. One step represents one hour (constant DURATION = 3600 s). How often is sugar actually transported in this model? Is this realistic? What could be the reason for this choice?
2.3 How the plant is built
The rule that makes a bud produce a new metamer is:
Bud(r, p, o), (r < 10 && p == 0 && o < 3) ==> RV(-0.1) Internode(0.1, 1, r, 0.1) Node [ RL(BRANCH_ANGLE) Bud(r, PHYLLOCHRON, o+1) ] // lateral bud -> branch [ LFA(1) Leaf(0.1, 0.07, 0, 1, 0, r) ] // leaf RH(GOLDEN_ANGLE) RV(-0.1) Internode(0.1, 1, r, 0.1) Bud(r+1, PHYLLOCHRON, o); // the apex continues
Q5. Draw (on paper) one metamer as produced by this rule: which organs, in which order, and what is inside the square brackets [ ]?
Q6. When rank reaches 10, the bud turns into a Flower. How many flowers do you expect on the plant? (Hint: look at the condition o < 3 and at the order given to the main stem in init().)
Part 3 – Run and observe (15 min)
Reset the model and run it for about 300 steps (≈ 12 days). Observe the 3D view, the charts and the console.
Fill in:
| Observation | Your answer |
|---|---|
| Step at which the first flower appears | |
| Step at which the first fruit appears | |
| Number of fruits at step 300 | |
| Shape of the fruit growth curves (linear? S-shaped? all the same?) | |
| Where are the internodes brightest (most sugar)? Top, bottom, main stem, branches? | |
| Which leaves absorb the most light? |
Q7. Do all flowers become fruits at the same time? Why not? (You will find the rule in Part 4.4.)
Part 4 – Reading the code: production, transport, use (25 min)
We now follow a sugar molecule from where it is made to where it is used.
4.1 Production: the light response curve
float calculateCER(float ppfd) { return ((FMAX + DARK_RESPIRATION_RATE) * PHOTO_EFFICIENCY * ppfd) / (PHOTO_EFFICIENCY * ppfd + FMAX + DARK_RESPIRATION_RATE) - DARK_RESPIRATION_RATE; }
ppfd is the photon flux density received by the leaf (µmol photons m⁻² s⁻¹), CER is the CO₂ exchange rate (µmol CO₂ m⁻² s⁻¹). FMAX = 20, DARK_RESPIRATION_RATE = 0.5, PHOTO_EFFICIENCY = 0.85.
- Q8. What is the value of CER in darkness (ppfd = 0)? What does a negative value mean for the leaf?
- Q9. What value does CER approach when ppfd becomes very large? Sketch the curve.
- Q10. The function
calculatePSthen converts CER into kilograms of glucose produced by one leaf in one hour. Which three quantities is CER multiplied by? (Look at the code.)
In absorbAndGrow(), every leaf adds its production to its own stock: lf[as] += calculatePS(…).
4.2 Transport
The method transport() contains three rules. Read them carefully.
Rule 1 – between a leaf and the internode that carries it
lf:Leaf <-minDescendants- itn:Internode ::> { if (lf[as] > 0.01 && lf[age] >= 10) { // mature leaf: EXPORT float exportable = lf[as] - 0.01; float r = DIFF_CONST * exportable; lf[as] -= r; itn[as] += r; } else if (itn[as] > 0.01 && lf[age] < 10) { // young leaf: IMPORT float exportable = itn[as] - 0.01; float r = DIFF_CONST * exportable; lf[as] += r; itn[as] -= r; } }
Rule 2 – between two successive internodes (simplified here, same meaning as in the model)
i_top:Internode <-minDescendants- i_bottom:Internode ::> { float r = DIFF_CONST * (i_top[as] - i_bottom[as]); i_bottom[as] :+= r; i_top[as] :-= r; }
Rule 3 – from an internode to a fruit
itn:Internode -minDescendants-> fr:Fruit ::> { if (itn[as] > 0) { float r = DIFF_CONST * itn[as]; itn[as] :-= r; fr[as] :+= r; } }
Reading tip: a:Leaf ←minDescendants- b:Internode means “b is an Internode found by going down from the leaf a towards the base” – i.e. the internode below the leaf. DIFF_CONST = 0.002 is the fraction of the difference (or of the stock) that moves per transport round.
- Q11. At what age does a leaf switch from sink to source in this model? Why do leaves keep a reserve of 0.01?
- Q12. In Rule 2, can sugar move upwards as well as downwards? What decides the direction? Which physical process does this rule resemble (hint: Fick's law)?
- Q13. Compare Rule 1 (export) and Rule 2. Does the export of a mature leaf depend on how much sugar is already in the internode? Is that consistent with the Münch model?
- Q14. In Rule 3, which quantity drives the flux into the fruit: the fruit's demand, or the internode's stock? What would a “strong” sink look like in this model?
4.3 Use: maintenance and growth
- Internodes lose 1 % of their sugar per step (
MR, maintenance respiration) and grow in length depending on their sugar content (itn[as]). - Leaves grow following a logistic curve (look at the leaf part of
absorbAndGrow()). - Fruits grow in the
fr:Fruit ::> { … }block ofabsorbAndGrow().
Q15 – Detective question. Look closely at the fruit block. Where does the variable sugar that drives fruit growth come from? Is it the sugar fr[as] delivered by transport (Rule 3)? Is the sugar used by the fruit removed from anywhere?
Q16. Does leaf growth depend on the amount of sugar in the leaf? (Read the comment in the code, then read the code itself.)
4.4 Fruit set
fl:Flower(t, m)(* <-minDescendants- Node -minDescendants-> lf:Leaf *), (t >= m && t < m+2) ==> { float sugar = lf[as]; } if (sugar > 0) ( {noFrts++;} Fruit(0.01, 1, 0.1, noFrts) ) else (fl);
Q17. In words: under which condition does a flower become a fruit? Which leaf is checked? What happens to a flower when the condition is not met?
Part 5 – Virtual experiments (25 min)
Method, for each experiment:
- Write your prediction before running (effect on fruit number, fruit size, internode sugar, total leaf sugar).
- Change one value only, save (the model resets), run 300 steps.
- Record the result, then restore the original value.
Every group does E1, plus two other experiments of its choice.
| Exp. | What to change | Where |
|---|---|---|
| E1 | DIFF_CONST: 0.002 → 0.02, then → 0.0002 | constants at the top |
| E2 | Lamp power: setPower(200.0) → 50.0 | module MyLamp |
| E3 | Sink–source transition: leaf age 10 → 30 (two places in Rule 1) | transport() |
| E4 | Maintenance respiration MR: 0.01 → 0.05 | constants |
| E5 | Transport every hour instead of 24 rounds once a day: in grow(), replace the whole if (time % 24 == 0) {…} block by a single line transport(); | grow() |
| E6 | Phyllochron: PHYLLOCHRON 25 → 15 | constants |
Results table (one line per run):
| Exp. | Value | Prediction | Nb fruits (step 300) | Size of largest fruit | Internode colour | Total leaf sugar (chart) | Explanation |
|---|---|---|---|---|---|---|---|
| Ref | – | – | |||||
| E1 | 0.02 | ||||||
| E1 | 0.0002 | ||||||
Q18. Was any result the opposite of your prediction? Use your answer to Q15 to explain it.
Part 6 – Your specialty (15 min)
Choose one track and do at least one task.
Track A – Plant Health
A1. Aphids: a new phloem sink. Aphids feed directly on phloem sap. Add a colony on the internodes of rank 3, starting at step 100.
At the top of the file, next to the other constants, add:
const float APHID_RATE = 0.02; // fraction of internode sugar taken per transport round float aphidSugar = 0; // total sugar taken by the aphids
Inside transport(), add a fourth rule (before the closing ]):
itn:Internode, (itn[rank] == 3 && time > 100) ::> { float r = APHID_RATE * itn[as]; itn[as] :-= r; aphidSugar += r; }
Print the total at each step: add println(“aphids: ” + aphidSugar); in grow(). Compare with the reference run. Then try rank 8 instead of 3 (closer to the flowers).
A2. Defoliation by a leaf disease. Remove all leaves of rank ≤ 4 at step 150. Add this rule in run():
lf:Leaf, (time == 150 && lf[rank] <= 4) ==> ;
A3. A pathogen that lowers photosynthetic capacity (e.g. a leaf spot or a virus): reduce FMAX from 20 to 10.
Questions:
- QA1. Which intervention reduced fruit set / fruit growth the most? Was the position of the aphid colony important? Why?
- QA2. Which of A1, A2, A3 reduces the source, which adds a sink? Why is it useful for a plant pathologist to make this distinction?
- QA3. What would you need to add to the model to represent the aphid population growing over time?
Track B – Seed Science and Plant Propagation
B1. Fruit thinning. Remove every second fruit at step 250. Add this rule in run():
fr:Fruit, (time == 250 && fr[no] % 2 == 0) ==> ;
Compare the size of the remaining fruits with the reference run.
B2. Fruit abortion threshold. In the fruit-set rule (Part 4.4), a flower sets fruit as soon as sugar > 0. Replace 0 with a threshold, e.g. sugar > 0.05, and then with a larger value. Record how the number of fruits and the time of fruit set change.
B3. Competition among fruits. In the fruit block of absorbAndGrow(), the sugar share of each fruit is weighted by Math.exp(-0.05 * fr[age]). This gives younger fruits priority. Set the factor to 0 (equal shares), then to +0.05 (older fruits get priority).
Questions:
- QB1. Is there a trade-off between the number and the size of fruits? Show it with your results.
- QB2. In real plants, the first-set fruits usually dominate later ones. Which setting of B3 is closest to this? What are the consequences for seed-lot uniformity?
- QB3. A seed producer wants large, uniform seeds. Based on the model, what would you advise, and what is missing from the model to give a reliable answer?
Part 7 – Synthesis (5 min)
- Q19. Draw a diagram (boxes and arrows) of the sugar flows in the model as it is coded: production → stocks → transport → use. Mark any place where sugar appears or disappears without an arrow.
- Q20. List two strengths and two limitations of this model for studying source–sink relations.
Bonus – Make fruits grow on the sugar they actually receive
For fast groups (this is a “new functionality” task). At present, fruits grow from the sugar stored in all leaves, which is never consumed (see Q15), while the sugar delivered by Rule 3 (fr[as]) is not used.
Modify the fruit block in absorbAndGrow() so that:
- the fruit computes its potential growth for this step (you can keep the
logistic(…)call with a fixed maximum), - it converts potential growth into a sugar demand (introduce a constant, e.g.
SUGAR_PER_SIZE), - it grows only as much as its stock
fr[as]allows, and removes the sugar used fromfr[as].
Then repeat experiment E1. Do the results now match your original predictions?
Before the exam
This exercise is not handed in, but the questions above cover the kind of reasoning expected in the exam: explaining source–sink relations, reading a simple model rule, and predicting and interpreting the outcome of a virtual experiment. Keep your answers and tables as revision notes.
