User Tools

Site Tools


tutorials:radiation-model-in-crop_model3

Introducing leaf growth

Open the file LeafGrowth.gsz.

Currently, the leaves and internodes of our plant just “pop up” with their final size, although in a real plant they would, of course, grow. Growth in length can be modelled easily: first, we need to give both Leaf and Internode several new parameters: length and age for Internode; and length, width and age for Leaf (L. 9 and L. 14).

module Internode(super.length) extends 
	Cylinder(length, 0.05) {
	{setShader(internodemat);}
}
 
module Leaf(super.length, super.width, float al) extends 
	Box(length,width,0.01).
	(setShader(new AlgorithmSwitchShader(new RGBAShader(0, 1, 0), GREEN)));

Then we initialize the length (and width) with a small value (0.1 and 0.07), and set the initial age to 1 in the init() method:

Bud(r, p, o), (r < 10 && p == 0 && o <= 3) ==> RV(-0.1) 
		Internode(0.1, 1) Node [RL(BRANCH_ANGLE) Bud(r, PHYLLOCHRON, o+1) ]
		[ RL(LEAF_ANGLE) Leaf(0.1, 0.07, 0)] RH(GOLDEN_ANGLE) RV(-0.1) 
		Internode(0.1) Bud(r+1, PHYLLOCHRON, o);	

Next, we need to find an appropriate function that describes growth. The logistic function is actually quite accurate when it comes to description of organ length. It is one of the many sigmoid functions. Its derivative can be used to describe the growth rate as a function of organ age. We declare the derivative of this logistic function as a new public method in the code, before the init() method:

//logistic function, used to determine growth rate:
public float logistic (float maxdim, int time, float phylloM, float slope)
{
	return(slope*maxdim*Math.exp(-slope*(time-phylloM)))/
	((Math.exp(-slope*(time-phylloM))+1)**2);
}

The function has three parameters, for now we are only interested in organ age. This we declare as a further (integer) parameter in Leaf and Internode:

module Internode(super.length, int age) extends 
	Cylinder(length, 0.05) {
	{setShader(internodemat);}
}
 
module Leaf(super.length, super.width, float al, int age) extends 
	Box(length,width,0.01).
	(setShader(new AlgorithmSwitchShader(new RGBAShader(0, 1, 0), GREEN)));

Next, we need to initialize age with 1 in the run() method (L. 103).

Bud(r, p, o), (r < 10 && p == 0 && o <= 3) ==> RV(-0.1) 
		Internode(0.1, 1) Node [RL(BRANCH_ANGLE) Bud(r, PHYLLOCHRON, o+1) ]
		[ RL(LEAF_ANGLE) Leaf(0.1, 0.07, 0, 1)] RH(GOLDEN_ANGLE) RV(-0.1) 
		Internode(0.1, 1) Bud(r+1, PHYLLOCHRON, o);	

Then, we extend the Leaf rule in the method that we now rename to absorbAndGrow() to model leaf ageing and extension in length and width:

protected void absorbAndGrow()
[               
	lf:Leaf ::> {
		lf[al] = lm.getAbsorbedPower3d(lf).integrate()*2.25;
		//println(lf[al]);
		lf.(setShader(new AlgorithmSwitchShader(new RGBAShader(lf[al]/5.0, lf[al]*2,lf[al]/100.0),GREEN)));
		//ageing and growth of leaf: 
		lf[age]++;
		lf[length] += logistic(3,lf[age],40,0.1);
		lf[width] = lf[length]*0.7;
	}                      
]

Finally, we add another execution (update) rule to model internode extension:

protected void absorbAndGrow()
[               
	lf:Leaf ::> {
		lf[al] = lm.getAbsorbedPower3d(lf).integrate()*2.25;
		//println(lf[al]);
		lf.(setShader(new AlgorithmSwitchShader(new RGBAShader(lf[al]/5.0, lf[al]*2,lf[al]/100.0),GREEN)));
		//ageing and growth of leaf: 
		lf[age]++;
		lf[length] += logistic(3,lf[age],40,0.1);
		lf[width] = lf[length]*0.7;
	}                      
	//extension of internode:    
	itn:Internode ::> {
		itn[age]++;
		itn[length] += logistic(1,itn[age],10,0.1);
	}
]

Task: Change the leaf growth parameters to obtain a very flat or else a rather steep light interception curve! (see figures below)

tutorials/radiation-model-in-crop_model3.txt · Last modified: 2025/05/27 17:55 by barley1965