flowchart LR G["growth g<br/>pushes plants up<br/>the height axis"] --> N["the size<br/>distribution<br/>N(H | x, a)"] D["death d<br/>removes plants<br/>at each height"] --> N
The maths, gently
theory · start here
This page introduces the equations behind plant slowly, one idea at a time, for readers who want to understand the maths but find the size-structured PDE page heavy going. It covers the same system of equations — just built up gradually, with every symbol explained in words. Once this feels comfortable, the maths, worked through pushes these same equations through one small numerical example, and then that page has the full derivations, boundary conditions, and appendices.
If you have not yet read the big picture, do that first; this page puts equations on the concepts introduced there. We build up in seven steps:
- where a single plant’s rates come from (the carbon economy);
- an individual as three running totals;
- from one plant to a whole size distribution (the central PDE);
- how that PDE is actually solved — by following cohorts;
- competition through shade;
- patches, disturbance, and the seed-rain balance;
- invasion fitness, and reading off averages.
The symbols you will meet
Only a handful of symbols do most of the work. Keep this list nearby:
| Symbol | Means | In words |
|---|---|---|
| \(x\) | traits | what kind of plant (LMA, wood density, seed mass, max height) |
| \(H\) | height | how big a plant is — the model’s measure of size |
| \(a\) | patch age | time since the patch was last cleared by disturbance |
| \(a_0\) | birth age | the patch age at which a given plant germinated |
| \(E_a\) | light environment | how much light reaches each height in a patch of age \(a\) |
| \(g,\ d,\ f\) | rates | growth, death, and fecundity (seed) rates |
| \(N\) | size-density | how many plants of each height are present |
| \(S_{\rm G}\) | germination survival | chance a seed survives to become a seedling |
| \(S_{\rm I}\) | individual survival | chance a plant is still alive at a given age |
| \(S_{\rm P}\) | patch survival | chance a patch has escaped disturbance so far |
| \(P\) | patch-age density | how common patches of each age are |
| \(\bar a\) | mean disturbance interval | average time a patch lasts before being reset |
| \(Y_x\) | seed rain | rate at which seeds of strategy \(x\) arrive in a patch |
| \(k_{\rm I}\) | extinction coefficient | how strongly leaves block light |
A note on integrals: an integral \(\int\) here just means “add up continuously over time (or over height).” Whenever you see one, read it as a running total.
Step 1 — where a plant’s rates come from
The demographic core treats the growth, death, and fecundity rates \(g\), \(d\), \(f\) as given, and asks what population they produce. But it helps to know where they come from. In the default FF16 model, all three trace back to one quantity: the net biomass a plant produces per unit time.
\[ \underbrace{\frac{{\rm d}B}{{\rm d}t}}_{\text{net biomass}} = \underbrace{\text{photosynthesis}}_{\text{income}} \; - \; \underbrace{\text{respiration}}_{\text{upkeep}} \; - \; \underbrace{\text{tissue turnover}}_{\text{replacement}}. \]
Photosynthesis scales with how much leaf area the plant has and how much light that leaf area sees; respiration and turnover are the running costs of keeping leaves, wood, and roots alive. Whatever is left over, the plant invests — and how it splits that investment gives the three demographic rates:
- Growth \(g\) is the share of net biomass spent building tissue, converted into height gain. Young plants spend most of their surplus here.
- Fecundity \(f\) is the share spent on seeds, divided by the cost of one seed. The fraction going to seeds rises as a plant nears its maximum height.
- Mortality \(d\) has a baseline part plus a part that rises as production falls — a starving, shaded plant is more likely to die.
So the same carbon budget drives all three rates, and a plant’s traits (its LMA, wood density, and so on) set the terms of that budget. The full equations are on the FF16 and assimilation & hydraulics pages; here we simply take \(g\), \(d\), and \(f\) as functions the strategy hands us.
Step 2 — one plant, three running totals
Now follow a single plant of traits \(x\) that germinated at patch age \(a_0\). Everything about its life is a running total of those three rates.
Its height is its starting height plus all the growth it has accumulated:
\[ H(a) = H_0 + \int_{a_0}^{a} g \, {\rm d}a'. \]
Its chance of still being alive falls off as death accumulates. Survival is the germination probability \(S_{\rm G}\) times the exponential of minus the total death risk so far:
\[ S_{\rm I}(a) = S_{\rm G} \, \exp\!\left(- \int_{a_0}^{a} d \, {\rm d}a'\right). \]
The exponential is the standard way to turn an accumulating risk into a survival probability: no risk yet means survival \(1\); as risk piles up, survival decays towards \(0\).
Its total seeds so far add up fecundity over time — but only counting plants that are still alive to produce them, hence the survival factor:
\[ \tilde{R}(a) = \int_{a_0}^{a} f \, S_{\rm I}(a') \, {\rm d}a'. \]
That is the whole life of one plant: grow, survive, seed — three integrals of the rates from Step 1. In practice plant does not compute these integrals directly; it writes each as a small differential equation and steps it forward in time with an ODE solver.
Step 3 — from one plant to a distribution
A patch holds many plants, so instead of tracking them individually we track a size-density distribution \(N(H \mid x, a)\): at patch age \(a\), how many plants of traits \(x\) have height \(H\). Picture it as a curve over height whose shape changes as the patch ages.
Two things move that curve, and they map onto the two rates that are not about reproduction:
Written as an equation, this is the model’s central partial differential equation (PDE):
\[ \frac{\partial N}{\partial a} = \underbrace{-\, d \, N}_{\text{deaths remove plants}} \;\underbrace{-\, \frac{\partial}{\partial H}\big(g \, N\big)}_{\text{growth carries plants upward}}. \]
Read it as a conveyor belt. Growth \(g\) carries plants along the height axis (the second term is the flow of that belt); death \(d\) removes a fraction of them wherever they are (the first term). The left-hand side is simply how the distribution changes as the patch gets older.
New plants enter at the bottom of the height axis. This is the PDE’s boundary condition: the flux of plants across the smallest height must equal the rate at which viable seedlings appear,
\[ g(H_0) \, N(H_0 \mid x, a) = Y_x \, S_{\rm G}, \]
where \(Y_x\) is the seed rain (how many seeds arrive) and \(S_{\rm G}\) is the chance one survives germination. This is where the landscape-scale seed rain of Step 6 feeds back into a single patch.
Step 4 — how the PDE is actually solved
Solving a PDE on a fixed grid of heights would be expensive and inaccurate. plant instead uses the method of characteristics: rather than watching fixed heights, it rides along with the plants.
Follow one cohort — a group of plants that all germinated together. Its height simply obeys the growth rate,
\[ \frac{{\rm d}H}{{\rm d}a} = g, \]
so the cohort traces a curve rising up the height axis (a characteristic of the PDE). Along that curve, the cohort’s density changes for two reasons: plants die, and the cohort stretches or compresses as growth speeds up or slows down. Both effects combine into one tidy equation,
\[ \frac{{\rm d}}{{\rm d}a}\ln N = -\left(\, d + \frac{\partial g}{\partial H}\,\right). \]
The \(d\) term is deaths, as before. The \(\partial g / \partial H\) term is the new piece: if growth slows with height (\(\partial g/\partial H < 0\)), successive cohorts bunch up and the density rises; if growth speeds up, they spread out and density falls. Nothing is lost compared with the PDE — this is the same equation, just viewed from the plants’ moving frame.
So a whole patch becomes a modest set of cohorts, each carrying two numbers — its height and its (log) density — that march forward together under simple differential equations. How many cohorts, and when each is introduced, is chosen adaptively (see node spacing).
Step 5 — competition through shade
The rates \(g\) and \(d\) are not fixed: they depend on light, and light depends on all the other plants. plant uses a shading law borrowed from optics (Beer’s law): light falls off exponentially with the amount of leaf area stacked above you.
\[ E_a(z) = \exp\!\left(-k_{\rm I} \times (\text{leaf area above height } z)\right). \]
Here \(z\) is a height in the canopy, \(E_a(z)\) is the fraction of open-sky light reaching it, and \(k_{\rm I}\) is the extinction coefficient (how strongly leaves block light). The “leaf area above \(z\)” is itself found by adding up the leaf area of every cohort taller than \(z\) — that is, by integrating over the size distribution \(N\).
This closes the feedback loop from the big picture: the distribution \(N\) sets the leaf area, the leaf area sets the light \(E_a\), and the light feeds back into the growth and death rates that reshape \(N\). Because taller plants shade shorter ones but not the reverse, the competition is asymmetric.
Step 6 — patches, disturbance, and the seed-rain balance
The patch mosaic. Zoom out to the landscape. Disturbances strike patches at random, so at any moment the landscape contains patches of every age. \(P(a)\) describes how common patches of age \(a\) are, and it decays as older patches keep getting knocked back to age zero:
\[ \frac{{\rm d}P}{{\rm d}a} = -\, d_{\rm P}(a) \, P(a), \]
where \(d_{\rm P}(a)\) is the chance a patch of age \(a\) is disturbed. Solving this gives the chance a patch has escaped disturbance up to age \(a\),
\[ S_{\rm P}(a) = \exp\!\left(-\int_0^a d_{\rm P}(a')\,{\rm d}a'\right), \]
and \(P(a)\) is proportional to \(S_{\rm P}(a)\). Two cases matter:
- If the disturbance risk \(d_{\rm P}\) is constant, old patches simply grow rarer and rarer — an exponential distribution of ages.
plant’s default instead lets the risk rise with age (\(d_{\rm P}\propto a\)): young patches almost always survive, old ones almost never do. This gives a Weibull distribution, \(S_{\rm P}(a) = \exp(-\lambda a^{2})\).
Either way, the whole age distribution is pinned down by one number: \(\bar a\), the mean interval between disturbances.
The seed-rain balance. Now the two scales meet. Across the whole landscape, a strategy’s total seed output is found by adding up the seeds made in every patch, weighted by how common patches of that age are:
\[ Y_x = \int_0^\infty \int_0^\infty P(a) \, S_{\rm D} \, f \, N \, {\rm d}H \, {\rm d}a. \]
The inner integral adds seed production over all plant heights in a patch; the outer integral averages over patches of all ages; \(S_{\rm D}\) is the fraction of seeds surviving dispersal.
Here is the catch: the seed rain \(Y_x\) feeds the patches (it set the boundary condition in Step 3) and comes out of them (the equation above). Write the output as a function of the assumed input, \(Y_x^{\text{out}} = \Phi(Y_x)\). At equilibrium the two must agree,
\[ Y_x = \Phi(Y_x), \]
which is a fixed-point (root-finding) problem — exactly the loop drawn in the big picture. For a single strategy it is a one-dimensional root find, solved by simple bisection; for several competing strategies it becomes a harder multi-dimensional solve.
Step 7 — invasion fitness and reading off answers
Can a mutant invade? Once the resident community is at its balanced seed rain, we can test a rare mutant with traits \(x'\). Because it is rare, it does not change the light environment — it just grows in the residents’ shade. Its invasion fitness is the expected number of dispersing offspring produced by one of its seeds over a full patch lifetime, averaged over the age of patch it happens to land in:
\[ R(x', x) = \int_0^\infty P(a_0) \, \tilde{R}(x', a_0) \, {\rm d}a_0, \]
where \(\tilde{R}(x', a_0)\) is that one seed’s lifetime seed output (Step 2, now also discounted by patch survival \(S_{\rm P}\)). The reading is simple:
- \(R(x', x) > 1\) → one seed makes more than one seed; the mutant can invade.
- \(R(x', x) < 1\) → the mutant fades out; the resident holds.
Trait values that no mutant can beat (\(R \le 1\) for every \(x'\)) are evolutionarily stable — the model’s prediction for how plants “should” be built. This is the whole content of the adaptive dynamics page.
Reading off averages. Finally, any quantity you care about is an average over the size distribution, weighted by how common each patch age is. For some quantity \(w\) (density, biomass, mortality…), its landscape average is
\[ \hat{w}(x) = \frac{1}{\hat N(x)}\int_0^\infty \int_0^\infty P(a) \, N \, w \; {\rm d}H \, {\rm d}a, \qquad \hat N(x) = \int_0^\infty \int_0^\infty P(a) \, N \; {\rm d}H \, {\rm d}a, \]
where \(\hat N(x)\) is just the average total density (the same integral with \(w = 1\)), used to normalise. Total stem density, leaf area, biomass, and the size–density (self-thinning) relationship all come out of this one weighted-integral pattern — see the emergent properties guide for it in action.
Where to go next
You now have the skeleton of the whole model. To go deeper:
- The maths, worked through — the gentlest next step: the same equations pushed through one small numerical example, one plant at a time, before the abstract treatment.
- The full size-structured PDE page — every equation above with its derivation, boundary conditions, and the Weibull appendix.
- Assimilation & hydraulics and the FF16 model — where the growth, death, and fecundity rates (\(g\), \(d\), \(f\)) actually come from.
- Adaptive dynamics — the full treatment of invasion fitness and evolutionary endpoints.
- The implementation pages — how these integrals and the PDE are actually solved: the characteristic method, ODE stepping, and node spacing.