The BioCro C++ Library
c3photo.cpp
Go to the documentation of this file.
1#include <algorithm> // for std::min
2#include <cmath> // for pow, sqrt
3#include <limits> // for std::numeric_limits
4#include "../framework/constants.h" // for dr_stomata, dr_boundary
5#include "ball_berry_gs.h" // for ball_berry_gs
6#include "c3_temperature_response.h" // for c3_temperature_response
7#include "conductance_helpers.h" // for sequential_conductance
8#include "conductance_limited_assim.h" // for conductance_limited_assim
9#include "FvCB_assim.h" // for FvCB_assim
10#include "../math/roots/onedim/dekker.h" // for dekker
11#include "c3photo.h"
12
13using physical_constants::dr_boundary;
14using physical_constants::dr_stomata;
15/*
16
17 The secant method is used to solve for assimilation, Ci, and stomatal conductance,
18 because of known convergence issues when using fixed-point iteration, based on
19 Sun et al. (2012) "A numerical issue in calculating the coupled carbon and
20 water fluxes in a climate model." *Journal of Geophysical Research*
21 https://dx.doi.org/10.1029/2012JD018059
22
23*/
24
27 double const absorbed_ppfd, // micromol / m^2 / s
28 double const Tleaf, // degrees C
29 double const Tambient, // degrees C
30 double const RH, // dimensionless
31 double const Vcmax_at_25, // micromol / m^2 / s
32 double const Jmax_at_25, // micromol / m^2 / s
33 double const TPU_rate_max, // micromol / m^2 / s
34 double const RL_at_25, // micromol / m^2 / s
35 double const b0, // mol / m^2 / s
36 double const b1, // dimensionless
37 double const Gs_min, // mol / m^2 / s
38 double const Ca, // micromol / mol
39 double const AP, // Pa (TEMPORARILY UNUSED)
40 double const O2, // millimol / mol (atmospheric oxygen mole fraction)
41 double const StomWS, // dimensionless
42 double const electrons_per_carboxylation, // self-explanatory units
43 double const electrons_per_oxygenation, // self-explanatory units
44 double const beta_PSII, // dimensionless (fraction of absorbed light that reaches photosystem II)
45 double const gbw // mol / m^2 / s
46)
47{
48 // Define infinity
49 double const inf = std::numeric_limits<double>::infinity();
50
51 // Check inputs
52 if (absorbed_ppfd < 0) {
53 throw std::out_of_range("Input `absorbed_ppfd` cannot be negative. Check `solar` is not negative.");
54 }
55
56 // Calculate values of key parameters at leaf temperature
57 c3_param_at_tleaf c3_param = c3_temperature_response(tr_param, Tleaf);
58
59 double const dark_adapted_phi_PSII = c3_param.phi_PSII; // dimensionless
60 double const Gstar = c3_param.Gstar; // micromol / mol
61 double const Jmax = Jmax_at_25 * c3_param.Jmax_norm; // micromol / m^2 / s
62 double const Kc = c3_param.Kc; // micromol / mol
63 double const Ko = c3_param.Ko; // mmol / mol
64 double const RL = RL_at_25 * c3_param.RL_norm; // micromol / m^2 / s
65 double const theta = c3_param.theta; // dimensionless
66 double const TPU = TPU_rate_max * c3_param.Tp_norm; // micromol / m^2 / s
67 double const Vcmax = Vcmax_at_25 * c3_param.Vcmax_norm; // micromol / m^2 / s
68
69 // The variable that we call `I2` here has been described as "the useful
70 // light absorbed by photosystem II" (S. von Caemmerer (2002)) and "the
71 // maximum fraction of incident quanta that could be utilized in electron
72 // transport" (Bernacchi et al. (2003)). Here we calculate its value using
73 // Equation 3 from Bernacchi et al. (2003), except that we have replaced the
74 // factor `Q * alpha_leaf` (the product of the incident PPFD `Q` and the
75 // leaf absorptance) with the absorbed PPFD, as this is clearly the intended
76 // meaning of the `Q * alpha_leaf` factor. See also Equation 8 from the
77 // original FvCB paper, where `J` (equivalent to our `I2`) is proportional
78 // to the absorbed PPFD rather than the incident PPFD.
79 double I2 = absorbed_ppfd * dark_adapted_phi_PSII * beta_PSII; // micromol / m^2 / s
80
81 double const J =
82 (Jmax + I2 - sqrt(pow(Jmax + I2, 2) - 4.0 * theta * I2 * Jmax)) /
83 (2.0 * theta); // micromol / m^2 / s
84
85 double const Oi = O2 * solo(Tleaf); // mmol / mol
86
87 // The alpha constant for calculating Ap is from Eq. 2.26, von Caemmerer, S.
88 // Biochemical models of leaf photosynthesis.
89 double const alpha_TPU = 0.0; // dimensionless. Without more information, alpha=0 is often assumed.
90
91 // Adjust Ball-Berry parameters in response to water stress
92 double const b0_adj = StomWS * b0 + Gs_min * (1.0 - StomWS);
93 double const b1_adj = StomWS * b1;
94
95 // Initialize variables before running fixed point iteration in a loop
96 // these are updated as a side effect in the secant method iterations
97 FvCB_outputs FvCB_res;
98 stomata_outputs BB_res;
99 double Gs{1e3}; // mol / m^2 / s (initial guess)
100 double Assim{0.0}; // micromol / mol (initial guess)
101
102 // This lambda function equals zero only if Ci satisfies both the FvCB and
103 // Ball-Berry models. Here, Ci should be expressed in micromol / mol.
104 auto check_assim_rate = [=, &FvCB_res, &BB_res, &Gs, &Assim](double Ci) {
105 // Use Ci to compute the assimilation rate according to the FvCB model.
106 FvCB_res = FvCB_assim(
107 Ci, Gstar, J, Kc, Ko, Oi, RL, TPU, Vcmax, alpha_TPU,
108 electrons_per_carboxylation,
109 electrons_per_oxygenation);
110
111 Assim = FvCB_res.An; // micromol / m^2 / s
112
113 // Use Assim to compute the stomatal conductance according to the
114 // Ball-Berry model. If Assim is too high, Cs will take a negative
115 // value, which is not allowed by the Ball-Berry model. To avoid this,
116 // we clamp Assim to the value that produces Cs = 0; this will result
117 // in Gs = infinity.
118 BB_res = ball_berry_gs(
119 std::min(Assim, conductance_limited_assim(Ca, gbw, inf)) * 1e-6,
120 Ca * 1e-6,
121 RH,
122 b0_adj,
123 b1_adj,
124 gbw,
125 Tleaf,
126 Tambient);
127
128 Gs = BB_res.gsw; // mol / m^2 / s
129
130 // Using Ci and Gs, make a new estimate of the assimilation rate. If
131 // the initial value of Ci was correct, this should be identical to
132 // Assim.
133 double Gt = sequential_conductance(gbw / dr_boundary, Gs / dr_stomata); // mol / m^2 / s
134
135 return Assim - Gt * (Ca - Ci); // micromol / m^2 / s
136 };
137
138 // Get an upper bound for Ci by finding the most negative value of An (which
139 // occurs when Ci = 0), the smallest total conductance to CO2 (which occurs
140 // when gsw takes its minimum value b0), and then using Ci = Ca - An / gtc.
141 double const A_min =
143 0.0, Gstar, J, Kc, Ko, Oi, RL, TPU, Vcmax, alpha_TPU,
144 electrons_per_carboxylation,
145 electrons_per_oxygenation)
146 .An; // micromol / m^2 / s
147
148 double const Ci_max =
149 Ca - A_min * (dr_boundary / gbw + dr_stomata / b0_adj); // micromol / mol
150
151 // Run the Dekker method
152 using namespace root_finding;
153 dekker solve{500, 1e-12, 1e-12};
154 result_t result = solve(
155 check_assim_rate,
156 0.718 * Ca,
157 0,
158 Ci_max * 1.01);
159
160 // Throw exception if not converged
161 if (!is_successful(result.flag)) {
162 throw std::runtime_error(
163 "Ci solver reports failed convergence with termination flag:\n " +
164 flag_message(result.flag));
165 }
166
167 // Get final values
168 double const Ci = result.root; // micromol / mol
169 double const an_conductance = conductance_limited_assim(Ca, gbw, Gs); // micromol / m^2 / s
170
172 /* .Assim = */ Assim, // micromol / m^2 / s
173 /* .Assim_check = */ result.residual, // micromol / m^2 / s
174 /* .Assim_conductance = */ an_conductance, // micromol / m^2 / s
175 /* .Ci = */ Ci, // micromol / mol
176 /* .Cs = */ BB_res.cs, // micromol / m^2 / s
177 /* .GrossAssim = */ FvCB_res.Vc, // micromol / m^2 / s
178 /* .Gs = */ Gs, // mol / m^2 / s
179 /* .RHs = */ BB_res.hs, // dimensionless from Pa / Pa
180 /* .RL = */ RL, // micromol / m^2 / s
181 /* .Rp = */ FvCB_res.Vc * Gstar / Ci, // micromol / m^2 / s
182 /* .iterations = */ result.iteration // not a physical quantity
183 };
184}
185
186// This function returns the solubility of O2 in H2O relative to its value at
187// 25 degrees C. The equation used here was developed by forming a polynomial
188// fit to tabulated solubility values from a reference book, and then a
189// subsequent normalization to the return value at 25 degrees C. For more
190// details, See Long, Plant, Cell & Environment 14, 729–739 (1991)
191// (https://doi.org/10.1111/j.1365-3040.1991.tb01439.x).
192double solo(
193 double LeafT // degrees C
194)
195{
196 return (0.047 - 0.0013087 * LeafT + 2.5603e-05 * pow(LeafT, 2) - 2.1441e-07 * pow(LeafT, 3)) / 0.026934;
197}
FvCB_outputs FvCB_assim(double Ci, double Gstar, double J, double Kc, double Ko, double Oi, double RL, double TPU, double Vcmax, double alpha_TPU, double electrons_per_carboxylation, double electrons_per_oxygenation)
Computes the net CO2 assimilation rate (and other values) using the Farquhar-von-Caemmerer-Berry mode...
Definition: FvCB_assim.cpp:117
stomata_outputs ball_berry_gs(double assimilation, double ambient_c, double ambient_rh, double bb_offset, double bb_slope, double gbw, double leaf_temperature, double ambient_air_temperature)
Calculates steady-state stomatal conductance to water vapor using the Ball-Berry model.
c3_param_at_tleaf c3_temperature_response(c3_temperature_response_parameters param, double Tleaf)
Calculates the values of key C3 photosynthesis parameters at leaf temperature.
double solo(double LeafT)
Definition: c3photo.cpp:192
photosynthesis_outputs c3photoC(c3_temperature_response_parameters const tr_param, double const absorbed_ppfd, double const Tleaf, double const Tambient, double const RH, double const Vcmax_at_25, double const Jmax_at_25, double const TPU_rate_max, double const RL_at_25, double const b0, double const b1, double const Gs_min, double const Ca, double const AP, double const O2, double const StomWS, double const electrons_per_carboxylation, double const electrons_per_oxygenation, double const beta_PSII, double const gbw)
Definition: c3photo.cpp:25
double sequential_conductance(double const conductance_1, double const conductance_2)
Calculates the total conductance across two sequential gas paths.
double conductance_limited_assim(double Ca, double gbw, double gsw)
Computes the conductance-limited net CO2 assimilation rate.
A simple structure for holding the output of FvCB calculations.
Definition: FvCB_assim.h:7
double An
Net CO2 assimilation rate (micromol / m^2 / s)
Definition: FvCB_assim.h:8
double Vc
RuBP carboxylation rate (micromol / m^2 / s)
Definition: FvCB_assim.h:12
double Tp_norm
Tp normalized to its value at 25 degrees C (dimensionless)
double Ko
Michaelis-Menten constant for Rubisco oxygenation (mmol / mol)
double phi_PSII
Dark-adapted operating efficiency of photosystem II (dimensionless)
double Kc
Michaelis-Menten constant for Rubisco carboxylation (micromol / mol)
double theta
Linear light response factor (dimensionless)
double RL_norm
RL normalized to its value at 25 degrees C (dimensionless)
double Gstar
CO2 compensation point in the absence of RL (micromol / mol)
double Vcmax_norm
Vcmax normalized to its value at 25 degrees C (dimensionless)
double Jmax_norm
Jmax normalized to its value at 25 degrees C (dimensionless)
A simple structure for holding the output of photosynthesis calculations.
A simple structure for holding the output of stomatal conductance calculations.
double gsw
Stomatal conductance to water vapor (mmol / m^2 / s)
double hs
Relative humidity at the leaf surface (dimensionless)
double cs
CO2 concentration at the leaf surface (micromol / mol)