Effect of spectral light on morphogenesis
Open SpectralLight.gsz and explore the four files it consists of: Main.rgg
, Modules.rgg
, Parameters.rgg
, and KL.java
. The names already suggest that in Main.rgg
you will find the main parts of the model, notably the methods init()
and grow()
, but also methods to create and update the graphical output on charts (initChart()
and updateChart()
); in Modules.rgg
the definition of all modules used in the model; in Parameters.rgg
all parameters; and finally we have again the photosynthesis model KL.java
.
What can this model do? Well, as its name suggests, with this model we can simulate spectral light. So, instead of just simulating a lamp with white light or, at best, red, green and blue light, we now have the possibility to simulate an entire spectrum of visible light and even part of the light just outside the visible spectrum!
Open Parameters.rgg and inspect the lines 8 to 22:
//redLED.spd, blueLED.spd static const float[] WAVELENGTHS = {360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, ...}; static const float[] WAVELENGTHS_PB = {380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, ...}; //red static const float[] AMPLITUDES_RED = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...}; //blue static const float[] AMPLITUDES_BLUE = {0.011596, 0.011512, 0.00871, 0.002914, 0, 0, 0.002729, 0.007988, ...}; //far-red static const float[] AMPLITUDES_FR ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...}; //lamp phenobean static const float[] AMPLITUDES_PHENOB = {7.26375E-05, 0.00023939, 0.000212121, 0.000233373, 0.00020509, 0.000166495, 0.000155523, 0.000184755, 0.000256009, 0.000169664, 0.000140593, 0.000194424, 0.000196017, 0.000221532, 0.000192043, 0.000193233, ...};
Here you will find long arrays of numbers, first of all two arrays with wavelengths between 360(380) and 830 (780) nm, at a resolution of 1 nm. In the second array, “PB” stands for “Phenobean”, and it designates the lamps installed in the PHENOBEAN phenotyping chamber (one of our facilities at Institut Agro in Angers, France).
The following four arrays (L. 12 – 22) yield the amplitude data for red, blue, far red and phenobean LED lamps, whereas the constants in L. 25 – 27 give correction factors to arrive at a PAR output of 52 µmol/m2 per light string, the nominal output power.
To see the process of construction of the different lamp types we have to go to Modules.rgg: In lines 8 to 65 we see the definitions of six lamp modules, of which two blue, two red, one Phenobean, and one far-red. Two red and two blue, because we want top- and interlighting. A lamp is constructed by creating an irregular spectral curve, containing the spectral distribution of light, combined with a PhysicalLight object using the physical distribution (defined in L. 109ff of Parameters.rgg: this is a double array containing the spatial information: azimuth and elevation of the light beam, from its origin).
We have visualized the beams so that you can see them in the scene: at the moment there are five lamps in the scene, they are defined in L. 25 – 29 of Main.rgg
in the init()
method:
==>> ^ M(70) RU(180) RedLEDtop; ==>> ^ M(70) RU(180) Translate(0,20,0) BlueLEDtop; ==>> ^ M(40) RU(180) RL(45) Translate(0,0,-50) RedLED; ==>> ^ M(40) RU(180) FRLED;//RedLEDtop;//FRLED; / ==>> ^ M(50) RU(180) Translate(0,30,0) FRLED;//RedLEDtop;//FRLED;//PHENOBLED;
You can see in the commented block that we have already used several lamps. You can do the same: change the composition of lamps as you like, save the code file, and then on Render View → Flux renderer, to see the color combination.
You may then click on the Run grow
button to see some output: First of all, you note that there are several charts: Leaf surface dynamics (to monitor the leaf surface of each leaf rank), then Internode length dynamics (for each internode rank), Red/Far red ratio, Phytochrome ratio, and Absorbed spectrum. Starting with the last item, Absorbed spectrum actually gives out the light absorbed per leaf rank, but for each “bucket” of about 2.6 nm wavelength, so you can see how much blue, green, red and far red light each leaf is actually absorbing (we can only guess how much of this is transmitted and reflected but all of this must add up to 100%…). How does this work? Have a look at the definition of the Leaf
(Modules.rgg
, L. 82ff):
module Leaf (int ID, super.length, super.width, float al, int age, int rank, Measurement ms, float rfr, float absred, float absfarred, float absblue, float as) extends Box(length, width, 0.01){ { Phong myShader = new Phong(); myShader.setDiffuse(reflectionSPD); myShader.setDiffuseTransparency(transmissionSPD); //ColorGradient colorMap = new ColorGradient("one",0,250, graphState(), 0); setShader(new AlgorithmSwitchShader(new RGBAShader(0,1,0), myShader, leafmat));} float getSurface() { float SCF = 1000; return this.length*this.width*SCF; } };
We note that Leaf
has a lot of parameters apart from its length and width, the absorbed light al
and the amount of assimilates as
: We will come back to that later. Let’s first of all explore the shader of the leaf, it’s called a Phong shader, named after the researcher who worked on this topic. Using such a Phong shader allows you to specify spectra for reflection and transmission (methods setDiffuse()
and setDiffuseTransparency()
). The arguments for these methods are two arrays with numbers containing the amount of light reflected and transmitted per waveband, based on measurements using a spectrophotometer). The two arrays can be found at the very end of Parameter.rgg
(they are in fact curves that are constructed with the static statement in L. 397-401 using data from other arrays (L. 257ff).
Back to the definition of the Leaf module: you note that one of its parameters is called ms
and it’s of a type we’ve never seen before: Measurement
. Let’s see how this is used: go to Main.rgg
, L. 63. Here we see in the method absorbAndGrow()
that the parameter ms of Leaf is updated:
lf[ms] = lm.getAbsorbedPowerMeasurement(lf);
A measurement
is in fact a data table, in which the absorbed spectrum is stored, one measurement per wavelength. This is done by an extended light model called FluxLightModel
. A spectral measurement can now be used in several ways: we can output the data to a graph and display the absorbed spectrum as is done in L. 140 of Main.rgg. Or we can pick specific wavelengths such as the peaks of absorbed blue (450 nm), red (630 nm), and far red (760 nm) and store them in the previously defined variables absblue, absred and absfarred (L. 132 – 134).
lf[absblue] = lf[ms].data[19]; //450 nm lf[absred] = lf[ms].data[86]; //630 nm lf[absfarred] = 0.0001 + lf[ms].data[135]; // 760 nm
It is then quite easy to calculate the red/far red ratio (L. 135), which is another one of the variables of Leaf.
lf[rfr] = lf[absred]/lf[absfarred];
The R/FR ratio is translated within the plant into an equilibrium ratio of two forms of phytochromes Pr and Pfr. This is not a linear relation; therefore we need to employ another function that we called calcPhytochrome()
, defined in L. 75-82 of Parameters.rgg
:
public static double calcPhytochrome(float rfr) { double phi = 0; double Zpfr = 1.7; // slope parameter double phiR = 0.75; // value of phi at high R:FR double phiFR = 0.03; // value of phi at R:FR = zero; return phi = 1 - (rfr + Zpfr) / ( (rfr/(1-phiR)) + (Zpfr/(1-phiFR)) ); }
The function basically defines the response curve of phytochrome ratio to R/FR. You can see the dynamic output in the graphs “Red/Far red ratio” and “Phytochrome ratio”.
What is the effect of different wavelengths on plant morphology? There are several, but it is known that a low R/FR will enhance internode length and leaf surface, and that blue light will have the opposite effect. Also, blue light will have a delaying effect on the phyllochrone. We have added a number of functions to this effect, that will modify the parameters of the logistic growth function for internodes and leaves, as a function of R/Fr and absorbed blue light (methods “maxlength”, “intslope”, and “phyllochron”, L. 83-106 in Parameters.rgg).
public static double maxlength(float absblue, float rfr) { float residual = 0.15; float phi = calcPhytochrome(rfr); float ml = residual + (Math.exp(-phi-25*absblue)); return ml; } public static double intslope(float absblue, float rfr) { float residual = 0.01; float phi = calcPhytochrome(rfr); float isl = residual + 0.1*Math.exp(-phi-25*absblue); //println("intslope: " + isl); return isl; } public static int phyllochron(int rank, int id) { if(rank>3) {Leaf lef = first((* lf:Leaf, (lf[rank]==rank-1 && lf[ID]==id)*)); float phi = calcPhytochrome(lef[rfr]); return (int) (28 + 8*Math.exp(-10*lef[absblue]+2*phi));} else { return 28;} }
Tasks: 1) Run the model with different lamp configurations! Observe the effect on internode length and leaf surface dynamics!
2) Run the model for a number of steps, then move a lamp*, or change its power output! You can also add a Sky light source but beware that this has a dramatic effect on the R/FR ratio (hint! To prevent this, you have to increase the power output of the two far red lamps as it currently is too low). Once you have added a Sky light, you can also have a look at the Photosynthesis rate dynamics (for some reason, the light output of the LED lamps alone is a bit too low).
3) Open the Excel file Spectre.xlsx and inspect the way the relation between absorbed blue and rfr and slope/maximum dimension has been implemented!
4) Currently we have only one plant in the scene: go to Parameters.rgg, L. 45, 46 and 49 and modify the parameters so that you get 25 plants (5 x 5), with plant number 13 being the chosen one! Then run the model again to see if the plants will develop differently!
*To move a lamp, you can click on its tip and then drag the lamp into one direction (x, y z) by clicking, holding and moving one of the three arrowheads. If selection in the scene doesn’t work you can try finding the lamp using the Flat Object Inspector window that is already open in your model: