The BioCro C++ Library
boundary_layer_conductance.cpp
Go to the documentation of this file.
1#include <cmath> // for std::max, std::min, pow, log
2#include "../framework/constants.h" // for celsius_to_kelvin
3#include "conductance_helpers.h" // for g_to_mass
4#include "../math/roots/onedim/dekker.h" // for dekker
5#include "water_and_air_properties.h" // for saturation_vapor_pressure
7
53 double air_temperature, // degrees C
54 double delta_t, // degrees C
55 double lw, // m
56 double windspeed, // m / s
57 double p // Pa
58)
59{
60 // Set constants
61 double constexpr coef_forced = 0.147;
62 double constexpr coef_free = 0.055;
63
64 // Calculate conductances
65 double const gbv_forced = coef_forced * sqrt(windspeed / lw); // mol / m^2 / s
66 double const gbv_free = coef_free * pow(std::abs(delta_t) / lw, 0.25); // mol / m^2 / s
67
68 // The overall conductance is the larger one
69 double const gbv_leaf = std::max(gbv_forced, gbv_free); // mol / m^2 / s
70
71 // Convert to a mass conductance and return
72 return g_to_mass(p, gbv_leaf, air_temperature + delta_t); // m / s
73}
74
131 double air_temperature, // degrees C
132 double delta_t, // degrees C
133 double ea, // Pa
134 double gsv, // m / s
135 double lw, // m
136 double windspeed, // m / s
137 double p // Pa
138)
139{
140 double const leaftemp = air_temperature + delta_t; // degrees C
141 double const Tak = air_temperature + conversion_constants::celsius_to_kelvin; // K
142 double const Tlk = leaftemp + conversion_constants::celsius_to_kelvin; // K
143
144 double const esTl = saturation_vapor_pressure(leaftemp); // Pa
145
146 // Set constants
147 double constexpr cf = 4.322e-3; // for broad leaves
148 double constexpr ce = 1.6361e-3; // for broad leaves
149 double constexpr ct = 0.378;
150
151 // Equation 29
152 double const gbv_forced = cf * pow(Tak, 0.56) *
153 sqrt((Tak + 120) * windspeed / (lw * p)); // m / s
154
155 // This lambda function equals zero only if gbv_free satisfies the Nikolov
156 // model equations for free boundary layer conductance. Here, gbv_free
157 // should be expressed in m / s.
158 auto check_leaf_gbv_free = [=](double const gbv_free) {
159 // Equation 35
160 double const eb = (gsv * esTl + gbv_free * ea) / (gsv + gbv_free); // Pa
161
162 // Equation 34
163 double const Tvdiff = Tlk / (1.0 - ct * eb / p) -
164 Tak / (1.0 - ct * ea / p); // K
165
166 // Equation 33
167 double const new_gbv_free =
168 ce * pow(Tlk, 0.56) * sqrt((Tlk + 120) / p) *
169 pow(std::abs(Tvdiff) / lw, 0.25); // m / s
170
171 return gbv_free - new_gbv_free; // m / s
172 };
173
174 // Run the Dekker method; check_leaf_gbv_free is always positive for
175 // gbv_free = 0, but it is difficult to find a finite value where
176 // check_leaf_gbv_free is guaranteed to be negative; here we just use a
177 // very large value and hope for the best.
178 root_finding::dekker solver(500, 1e-12, 1e-12);
179
180 root_finding::result_t result = solver.solve(
181 check_leaf_gbv_free,
182 1e-4, // first guess
183 0, // lower bound of initial bracket
184 0.5 // upper bound of initial bracket
185 );
186
187 // Throw exception if not converged
188 if (!root_finding::is_successful(result.flag)) {
189 throw std::runtime_error(
190 "gbv_free solver reports failed convergence with termination flag:\n " +
191 root_finding::flag_message(result.flag));
192 }
193
194 // Get final value
195 double const gbv_free = result.root; // m / s
196
197 // The overall conductance is the larger one
198 return std::max(gbv_forced, gbv_free); // m / s
199}
200
259 double CanopyHeight, // m
260 double WindSpeed, // m / s
261 double minimum_gbw, // m / s
262 double WindSpeedHeight // m
263)
264{
265 // Define constants used in the model. `kappa` is von Karmon's constant.
266 // In the original text, the value of `dCoef` is reported as 0.64. In the
267 // 2000 reprinting of the text, the authors state that this value should be
268 // 0.77. See "Errata to the 2000 printing" on the page after the preface of
269 // the 2000 reprinting of the 1990 text.
270 constexpr double kappa = 0.41; // dimensionless, Thornley and Johnson pgs 414 and 416.
271 constexpr double ZetaCoef = 0.026; // dimensionless, Thornley and Johnson 1990, Eq. 14.9o
272 constexpr double ZetaMCoef = 0.13; // dimensionless, Thornley and Johnson 1990, Eq. 14.9o
273 constexpr double dCoef = 0.77; // dimensionless, Thornley and Johnson 1990, Eq. 14.9o
274
275 // Apply the height limit
276 CanopyHeight = std::min(CanopyHeight, 0.98 * WindSpeedHeight); // meters
277
278 // Calculate terms that depend on the canopy height (Eq. 14.9o)
279 const double Zeta = ZetaCoef * CanopyHeight; // meters
280 const double Zetam = ZetaMCoef * CanopyHeight; // meters
281 const double d = dCoef * CanopyHeight; // meters
282
283 // Calculate the boundary layer conductance `ga` according to Thornley and
284 // Johnson Eq. 14.9n, pg. 416
285 const double ga0 = pow(kappa, 2) * WindSpeed; // m / s
286 const double ga1 = log((WindSpeedHeight + Zeta - d) / Zeta); // dimensionless
287 const double ga2 = log((WindSpeedHeight + Zetam - d) / Zetam); // dimensionless
288 const double gbv = ga0 / (ga1 * ga2); // m / s
289
290 // Apply the minimum
291 return std::max(gbv, minimum_gbw); // m / s
292}
double leaf_boundary_layer_conductance_campbell(double air_temperature, double delta_t, double lw, double windspeed, double p)
Calculates the conductance for water vapor flow from the leaf across its boundary layer using a model...
double leaf_boundary_layer_conductance_nikolov(double air_temperature, double delta_t, double ea, double gsv, double lw, double windspeed, double p)
Calculates the conductance for water vapor flow from the leaf across its boundary layer using a model...
double canopy_boundary_layer_conductance_thornley(double CanopyHeight, double WindSpeed, double minimum_gbw, double WindSpeedHeight)
Calculates the conductance for water vapor flow from the canopy across its boundary layer using a mod...
double g_to_mass(double const pressure, double const conductance, double const temperature)
Convert a conductance value from a "molecular" basis (in units of mol / m^2 / s) to a "mass" basis (i...
double saturation_vapor_pressure(double air_temperature)
Determine saturation water vapor pressure (Pa) from air temperature (degrees C) using the Arden Buck ...