Response curve Background Programs

In principal, generating a response curve consists of the following repetitive pattern: 1) set environmental conditions, 2) wait for stability, 3) log data.

BPs provide a fair amount of flexibility for accomplishing these tasks: Control setpoints can be hand-entered, read from a file, generated from an algorithm, and so on. Wait times can be fixed, or made to adapt to conditions.

The following sections illustrate some response curve options available with BPs.

Basic

A simple BP to generate a response curve for CO2 can be found in the Library GROUPS source, and is shown in Figure 12‑45. To change setpoints, edit the LOOP step, and to change target, edit the SETCONTROL step.

Figure 12‑45. Single variable response using LOOP [List].

Since the list entry in LOOP is evaluated, you can use Python expressions there. For example, if you wanted integer setpoints every 100 ppm from 100 to 1000, you could make use of the range() method, which takes integer arguments of start, stop, and step.

which would (at run time) make the list

[100, 150, 200, 250, ..., 1000]

Another option is shown in Figure 12‑46, where we've added an EXEC step to make available some list generating utility methods available in the module list utility.py). We use that capability to generate a floating point setpoint list given simply a start value, stop value, and number of desired points.

Figure 12‑46. Adding linearList capability.

If you want randomized values, use randomList() instead of linearList().

Table 12‑1. Examples of randomList(), and linearList().
Expression Result
linearList(1,10,4) [1.0, 4.0, 7.0, 10.0]
linearList(5, -5, 6) [5.0, 3.0, 1.0, -3.0, -5.0]
randomList(5, -5, 11) [4.0, 3.0, -1.0, -3.0, 2.0, 1.0, -2.0, -4.0, -5.0, 0.0, 5.0]

The sample program /home/licor/apps/basic/GenericResponse.py (Figure 12‑47) illustrates the use of a TABLE, which makes it easy to coordinate targets and setpoints. Table entries do not by default pass through eval() (i.e., no expressions, no variables), so setpoints have to be explicitly entered.

Figure 12‑47. The program /home/licor/apps/basic/GenericResponse.py.

The GenericResponse.py program does support an opening dialog (Figure 12‑48), from which you can also edit the table.

Figure 12‑48. The opening dialog for /home/licor/apps/basic/GenericResponse.py.

Multiple controls

How to change multiple controls in a response loop? For example, how could you make a light response with the color becoming more red as intensity drops?

One method is to use the control table interface (such as with /home/licor/apps/basic/GenericResponse.py), and make the table look something like this (Figure 12‑49):

Figure 12‑49 . Light curve with increasing fraction of red as light drops.

Another method is illustrated by the example program /home/licor/apps/examples/LightColorCurve.py (Figure 12‑50), which uses programmatically determined setpoints for intensity and color.

Figure 12‑50. Programming color, from /home/licor/apps/examples/LightColorCurve.py.

If we test run this program in verbose mode, we can see the values it picks for the each setpoint (Figure 12‑51).

Figure 12‑51. Test running /home/licor/apps/examples/LightColorCurve.py.

Higher dimensions

Suppose you want to measure a response surface instead of a curve? For example, photosynthesis, conductance, etc. as a function of light and CO2. With just 2 independent variables, you could do nested control loops, as illustrated by ../basic/NestedResponse, with a measurement strategy as illustrated by Figure 12‑52. Basically, we are measuring a light curve (lot of points) at a few different CO2 concentrations.

Figure 12‑52. Measuring a response surface with 12 light setpoints at 4 different CO2 setpoints. 48 total points.

This would provide four high resolution light curves, and 12 very crude CO2 response curves. If you want to balance it out, you could work backwards: how much time do you want to spend maximum (say 2 hours), divide it by the average time to equilibrate at each point (say 5 minutes) to get the 24 total points, take a square root (≈ 5), leaving you with 5 light values and 5 CO2 values. Not very satisfying.

Well, why not use 12 light and 12 CO2 points, and just one loop, setting both each time (Figure 12‑53)? That way, we could be done in 12 × 5 = 60 minutes.

Figure 12‑53. Trying to combine responses leaves you with a very poor sampling of the surface.

Plotting out that strategy (Figure 12‑53) makes it clear why it is not helpful: every point we get is on a unique light or CO2 curve, leaving us with little or no knowledge of what that response surface actually looks like.

But, suppose we use those 12 pairs of points, and randomize the order so that we have a very low correlation between them (Figure 12‑54).

Figure 12‑54. Randomizing the order of the Q and CO2 setpoints to minimize the correlation between them greatly improves the chances of determining the response surface.

Now we are sampling across the light CO2 space, and have a chance of getting a reasonable estimate of what the surface above it might be like.

This approach is easy to do with a BP. Let’s start building a program to try this out (Figure 12‑55). We add the list list_utility.py module (an EXEC step), then make two lists of 12 evenly spaced setpoints: q (for light) from 50 to 1500, and c (for CO2) from 50 to 1000). Another EXEC passes setpoint lists to makeOrtho() to shuffle them, getting back a list of lists, which we put into the original variables. We use SHOW to look at the values.

Figure 12‑55. Creating orthogonal setpoint lists in a test program using the makeOrtho() function from the list_utility module.

Now all we need is to add a LOOP with SETCONTROLs, WAIT, and LOG, and we have the program /home/licor/apps/examples/OrthoLightCO2.py (Figure 12‑56).

Figure 12‑56. A program to measure a CO2 and light response surface, using orthogonal setpoints.

There are two optional parameters provided by makeOrtho() (see The list_utility module), that are illustrated in the following example. Suppose you want three independent variables: light, CO2, and temperature. Making big jumps in CO2 or light is not a problem (other than longer leaf equilibration times), but with temperature, you would prefer to make the changes in a monotonic manner as much as possible just to minimize system equilibration time. How can that be done?

An example is /home/licor/apps/examples/OrthoTempLightCO2.py (Figure 12‑57).

Figure 12‑57. A program to measure a temperature, CO2, and light response surface using orthogonal setpoints.

Changes to the previous program are:

(line 3, ASSIGN) - Added a variable (temp) that holds 12 temperature setpoints from 15 to 30.

(line 6, EXEC) - Added temp and some optional parameters to the makeOrtho() call, so it looks like this"

makeOrtho((temp,q,c), lock index=0, outfile='/home/licor/logs/ortho3_values.txt')

lock_index=0 tells makeOrtho() to not randomize the first (0th) list, which is temp.

outfile='/home/licor/logs/ortho3_values.txt' instructs makeOrtho() to also write its results to a file, so we can view or use these same setpoints later (Listing 12‑2).

corr_coeff= 0.076648340643

15.0 1105.0 568.0

16.36 182.0 827.0

17.73 1368.0 741.0

19.09 50.0 223.0

20.45 1500.0 309.0

21.82 314.0 482.0

23.18 445.0 136.0

24.55 973.0 1000.0

25.91 841.0 50.0

27.27 709.0 655.0

28.64 577.0 914.0

30.0 1236.0 395.0

Listing 12‑2. Listing of /home/licor/logs/ortho3_values.txt.

(line 7, SHOW) - Added temp to the list.

(line 9, SETCONTROL) - Set leaf temperature to the ith value of temp.

Variable stability wait times

Suppose you wish to do a light curve at a few different CO2 concentrations by nested loops, with an outer loop that changes CO2, and inner loop that changes light (the program /home/licor/apps/examples/Light_CO2_autofile.py will do this, putting each light curve in its own log file.) An important consideration with this method is the wait time for the first light value needs to be longer than normal, since the CO2 will have just changed, and the light will have had a big change from the last value of the previous light curve. A method of accommodating that is shown in (Figure 12‑58).

Figure 12‑58. Adding wait time variables to a table.

The equivalent to Figure 12‑58 without using TABLE could be done as illustrated in Figure 12‑59. Here we take advantage of being able to easily generate setpoints (linearList()). minWait is a normal minimum wait time, and firstWait is the time to use on the first pass through the light curve each time. Maximum wait times are always 2 times the minimum.

Figure 12‑59. Nest control loop with computed wait times.