Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Coon, Ethan
ELM_Kernels
Commits
902b33f4
Commit
902b33f4
authored
Jan 17, 2021
by
Beisman, James Joseph
Browse files
started Photosynthesis; minor changes and documentation for CanopyFluxes
parent
8420a94b
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/CMakeLists.txt
View file @
902b33f4
add_library
(
physics physics_dummy.cc CanopyHydrology.cc coldstart_topography.cc coldstart_snow.cc SurfaceRadiation.cc SurfaceResistance.cc QSat.cc CanopyTemperature.cc FrictionVelocity.cc BareGroundFluxes.cc CanopyFluxes.cc
)
add_library
(
physics physics_dummy.cc CanopyHydrology.cc coldstart_topography.cc coldstart_snow.cc SurfaceRadiation.cc SurfaceResistance.cc QSat.cc CanopyTemperature.cc FrictionVelocity.cc BareGroundFluxes.cc CanopyFluxes.cc
Photosynthesis.cc
)
target_include_directories
(
physics PUBLIC
${
CMAKE_CURRENT_SOURCE_DIR
}
)
src/CanopyFluxes.cc
View file @
902b33f4
/* functions derived from CanopyFluxesMod.F90
DESCRIPTION:
1.
Calculates
the
leaf temperature
:
2. C
alculates the
leaf fluxes, transpiration, photosynthesis and updates the dew accumulation due to evaporation
.
Calculates leaf temperature
leaf fluxes, transpiration, photosynthesis and updates the dew accumulation due to evaporation.
Also c
alculates the
irrigation rate
.
The member functions should be called in the following order:
InitializeFlux()
StabilityIteration() Irrigation()
ComputeFlux()
*/
#include <algorithm>
#include <cmath>
...
...
@@ -58,7 +62,6 @@ private:
double
temp1
;
// relation for potential temperature profile
double
temp2
;
// relation for specific humidity profile
double
tlbef
;
// leaf temperature from previous iteration [K]
double
ram
;
// aerodynamical resistance (s/m)
double
delq
;
// temporary
double
dt_veg
;
// change in t_veg, last iteration (Kelvin)
...
...
@@ -455,7 +458,6 @@ void StabilityIteration(
double
&
btran
,
double
&
qflx_tran_veg_out
,
double
&
qflx_evap_veg_out
,
double
&
eflx_sh_veg_out
...
...
@@ -465,7 +467,6 @@ void StabilityIteration(
// we operate on single cells, so we will replace the filter criteria with something else
{
forc_rho
=
forc_rho_in
;
if
(
!
Land
.
lakpoi
&&
!
Land
.
urbpoi
&&
frac_veg_nosno
!=
0
)
{
bool
stop
=
false
;
int
itmax
=
40
;
// maximum number of iteration [-]
...
...
@@ -792,7 +793,7 @@ void ComputeFlux(
// Determine total photosynthesis -- need to implement
// PhotosynthesisTotal(fn, filterp, atm2lnd_vars, cnstate_vars, canopystate_vars, photosyns_vars)
// evaluate error and write??
// evaluate error and write??
-- best way to write?
// if (abs(err(p)) > 0.1_r8)
...
...
src/Photosynthesis.cc
0 → 100644
View file @
902b33f4
#include <stdexcept>
#include <cmath>
namespace
Photosynthesis
{
// DESCRIPTION: evaluate the function f(ci)=ci - (ca - (1.37rb+1.65rs))*patm*an
void
quadratic
(
const
double
&
a
,
const
double
&
b
,
const
double
&
c
,
double
&
r1
,
double
&
r2
)
{
double
q
;
if
(
a
==
0.0
)
{
throw
std
::
runtime_error
(
"ELM ERROR: quadratic solution a == 0.0"
);
}
//error! end run
if
(
b
>=
0.0
)
{
q
=
-
0.5
*
(
b
+
std
::
sqrt
(
b
*
b
-
4.0
*
a
*
c
));
}
else
{
q
=
-
0.5
*
(
b
-
std
::
sqrt
(
b
*
b
-
4.0
*
a
*
c
));
}
r1
=
q
/
a
;
if
(
q
/=
0.0
)
{
r2
=
c
/
q
;
}
else
{
r2
=
1.0e36
;
}
}
void
TimeStepInit
()
{
}
// DESCRIPTION: evaluate the function f(ci)=ci - (ca - (1.37rb+1.65rs))*patm*an
void
ci_func
(
const
double
&
ci
,
// intracellular leaf CO2 (Pa)
double
&
fval
,
// return function of the value f(ci)
const
int
&
iv
,
// canopy index
const
double
&
gb_mol
,
// leaf boundary layer conductance (umol H2O/m**2/s)
const
double
&
je
,
// electron transport rate (umol electrons/m**2/s)
const
double
&
cair
,
// Atmospheric CO2 partial pressure (Pa)
const
double
&
oair
,
// Atmospheric O2 partial pressure (Pa)
const
double
&
lmr_z
,
// canopy layer: leaf maintenance respiration rate (umol CO2/m**2/s)
const
double
&
par_z
,
// par absorbed per unit lai for canopy layer (w/m**2)
const
double
&
rh_can
,
// canopy air realtive humidity
double
&
gs_mol
,
// leaf stomatal conductance (umol H2O/m**2/s)
const
double
*
vcmax_z
,
// [length of nlevcan & nrad)] maximum rate of carboxylation (umol co2/m**2/s)
const
double
&
forc_pbot
,
// atmospheric pressure (Pa)
const
bool
&
c3flag
,
// true if C3 and false if C4
double
*
ac
,
// [length of nlevcan & nrad)] Rubisco-limited gross photosynthesis (umol CO2/m**2/s)
double
*
aj
,
// [length of nlevcan & nrad)] RuBP-limited gross photosynthesis (umol CO2/m**2/s)
double
*
ap
,
// [length of nlevcan & nrad)] product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s)
double
*
ag
,
// [length of nlevcan & nrad)] co-limited gross leaf photosynthesis (umol CO2/m**2/s)
double
*
an
,
// [length of nlevcan & nrad)] net leaf photosynthesis (umol CO2/m**2/s)
const
double
&
cp
,
// CO2 compensation point (Pa)
const
double
&
kc
,
// Michaelis-Menten constant for CO2 (Pa)
const
double
&
ko
,
// Michaelis-Menten constant for O2 (Pa)
const
double
&
qe
,
// quantum efficiency, used only for C4 (mol CO2 / mol photons)
const
double
*
tpu_z
,
// triose phosphate utilization rate (umol CO2/m**2/s)
const
double
*
kp_z
,
// initial slope of CO2 response curve (C4 plants)
const
double
&
theta_cj
,
// empirical curvature parameter for ac, aj photosynthesis co-limitation
const
double
&
bbb
,
// Ball-Berry minimum leaf conductance (umol H2O/m**2/s)
const
double
&
mbb
)
// Ball-Berry slope of conductance-photosynthesis relationship
{
static
const
double
theta_ip
=
0.95
;
double
r1
,
r2
;
// roots of quadratic equation
if
(
c3flag
)
{
// C3: Rubisco-limited photosynthesis
ac
[
iv
]
=
vcmax_z
[
iv
]
*
std
::
max
(
ci
-
cp
,
0.0
)
/
(
ci
+
kc
*
(
1.0
+
oair
/
ko
));
// C3: RuBP-limited photosynthesis
aj
[
iv
]
=
je
*
std
::
max
(
ci
-
cp
,
0.0
)
/
(
4.0
*
ci
+
8.0
*
cp
);
// C3: Product-limited photosynthesis
ap
[
iv
]
=
3.0
*
tpu_z
[
iv
];
}
else
{
// C4: Rubisco-limited photosynthesis
ac
[
iv
]
=
vcmax_z
[
iv
];
// C4: RuBP-limited photosynthesis
aj
[
iv
]
=
qe
*
par_z
*
4.6
;
// C4: PEP carboxylase-limited (CO2-limited)
ap
[
iv
]
=
kp_z
[
iv
]
*
std
::
max
(
ci
,
0.0
)
/
forc_pbot
;
}
// Gross photosynthesis. First co-limit ac and aj. Then co-limit ap
double
aquad
=
theta_cj
;
// terms for quadratic equations
double
bquad
=
-
(
ac
[
iv
]
+
aj
[
iv
]);
double
cquad
=
ac
[
iv
]
*
aj
[
iv
];
quadratic
(
aquad
,
bquad
,
cquad
,
r1
,
r2
);
double
ai
=
std
::
min
(
r1
,
r2
);
// intermediate co-limited photosynthesis (umol CO2/m**2/s)
aquad
=
theta_ip
;
bquad
=
-
(
ai
+
ap
[
iv
]);
cquad
=
ai
*
ap
[
iv
];
quadratic
(
aquad
,
bquad
,
cquad
,
r1
,
r2
);
ag
[
iv
]
=
std
::
min
(
r1
,
r2
);
// Net photosynthesis. Exit iteration if an < 0
an
[
iv
]
=
ag
[
iv
]
-
lmr_z
;
if
(
an
[
iv
]
<
0.0
)
{
fval
=
0.0
;
return
;
}
// Quadratic gs_mol calculation with an known. Valid for an >= 0.
// With an <= 0, then gs_mol = bbb
double
cs
=
cair
-
1.4
/
gb_mol
*
an
[
iv
]
*
forc_pbot
;
// CO2 partial pressure at leaf surface (Pa)
cs
=
std
::
max
(
cs
,
1.e-6
);
aquad
=
cs
;
bquad
=
cs
*
(
gb_mol
-
bbb
)
-
mbb
*
an
[
iv
]
*
forc_pbot
;
cquad
=
-
gb_mol
*
(
cs
*
bbb
+
mbb
*
an
[
iv
]
*
forc_pbot
*
rh_can
);
quadratic
(
aquad
,
bquad
,
cquad
,
r1
,
r2
);
gs_mol
=
std
::
max
(
r1
,
r2
);
// Derive new estimate for ci
fval
=
ci
-
cair
+
an
[
iv
]
*
forc_pbot
*
(
1.4
*
gs_mol
+
1.6
*
gb_mol
)
/
(
gb_mol
*
gs_mol
);
}
// ci_func
// DESCRIPTION: Use Brent's method to find the root of a single variable function ci_func, which is known to exist between x1 and x2.
// The found root will be updated until its accuracy is tol.
// modified from numerical recipes in F90 by press et al. 1188-1189
void
brent
(
double
&
x
,
// indepedent variable of the single value function ci_func(x)
const
double
&
x1
,
// minimum and maximum of the variable domain to search for the solution ci_func(x1) = f1, ci_func(x2)=f2
const
double
&
x2
,
const
double
&
f1
,
const
double
&
f2
,
const
double
&
tol
,
// the error tolerance
const
int
&
iv
,
// canopy index
const
double
&
gb_mol
,
// leaf boundary layer conductance (umol H2O/m**2/s)
const
double
&
je
,
// electron transport rate (umol electrons/m**2/s)
const
double
&
cair
,
// Atmospheric CO2 partial pressure (Pa)
const
double
&
oair
,
// Atmospheric O2 partial pressure (Pa)
const
double
&
lmr_z
,
// canopy layer: leaf maintenance respiration rate (umol CO2/m**2/s)
const
double
&
par_z
,
// par absorbed per unit lai for canopy layer (w/m**2)
const
double
&
rh_can
,
// canopy air realtive humidity
double
&
gs_mol
,
// leaf stomatal conductance (umol H2O/m**2/s)
const
double
*
vcmax_z
,
// [length of nlevcan & nrad)] maximum rate of carboxylation (umol co2/m**2/s)
const
double
&
forc_pbot
,
// atmospheric pressure (Pa)
const
bool
&
c3flag
,
// true if C3 and false if C4
double
*
ac
,
// [length of nlevcan & nrad)] Rubisco-limited gross photosynthesis (umol CO2/m**2/s)
double
*
aj
,
// [length of nlevcan & nrad)] RuBP-limited gross photosynthesis (umol CO2/m**2/s)
double
*
ap
,
// [length of nlevcan & nrad)] product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s)
double
*
ag
,
// [length of nlevcan & nrad)] co-limited gross leaf photosynthesis (umol CO2/m**2/s)
double
*
an
,
// [length of nlevcan & nrad)] net leaf photosynthesis (umol CO2/m**2/s)
const
double
&
cp
,
// CO2 compensation point (Pa)
const
double
&
kc
,
// Michaelis-Menten constant for CO2 (Pa)
const
double
&
ko
,
// Michaelis-Menten constant for O2 (Pa)
const
double
&
qe
,
// quantum efficiency, used only for C4 (mol CO2 / mol photons)
const
double
*
tpu_z
,
// triose phosphate utilization rate (umol CO2/m**2/s)
const
double
*
kp_z
,
// initial slope of CO2 response curve (C4 plants)
const
double
&
theta_cj
,
// empirical curvature parameter for ac, aj photosynthesis co-limitation
const
double
&
bbb
,
// Ball-Berry minimum leaf conductance (umol H2O/m**2/s)
const
double
&
mbb
)
// Ball-Berry slope of conductance-photosynthesis relationship
{
static
const
int
ITMAX
=
20
;
// maximum number of iterations
static
const
double
EPS
=
1.0e-2
;
// relative error tolerance
double
d
,
e
,
p
,
q
,
r
,
s
,
tol1
,
xm
;
double
a
=
x1
;
double
b
=
x2
;
double
fa
=
f1
;
double
fb
=
f2
;
if
((
fa
>
0.0
&&
fb
>
0.0
)
||
(
fa
<
0.0
&&
fb
<
0.0
))
{
throw
std
::
runtime_error
(
"ELM ERROR: root must be bracketed for brent"
);
}
//error! end run
double
c
=
b
;
double
fc
=
fb
;
int
iter
=
0
;
while
(
iter
!=
ITMAX
)
{
iter
+=
1
;
if
((
fb
>
0.0
&&
fc
>
0.0
)
||
(
fb
<
0.0
&&
fc
<
0.0
))
{
c
=
a
;
// Rename a, b, c and adjust bounding interval d.
fc
=
fa
;
d
=
b
-
a
;
e
=
d
;
}
if
(
std
::
abs
(
fc
)
<
std
::
abs
(
fb
))
{
a
=
b
;
b
=
c
;
c
=
a
;
fa
=
fb
;
fb
=
fc
;
fc
=
fa
;
}
tol1
=
2.0
*
EPS
*
std
::
abs
(
b
)
+
0.5
*
tol
;
// Convergence check.
xm
=
0.5
*
(
c
-
b
);
if
(
std
::
abs
(
xm
)
<=
tol1
||
fb
==
0.0
)
{
x
=
b
;
return
;
}
if
(
std
::
abs
(
e
)
>=
tol1
&&
std
::
abs
(
fa
)
>
std
::
abs
(
fb
))
{
s
=
fb
/
fa
;
// Attempt inverse quadratic interpolation.
if
(
a
==
c
)
{
p
=
2.0
*
xm
*
s
;
q
=
1.0
-
s
;
}
else
{
q
=
fa
/
fc
;
r
=
fb
/
fc
;
p
=
s
*
(
2.0
*
xm
*
q
*
(
q
-
r
)
-
(
b
-
a
)
*
(
r
-
1.0
));
q
=
(
q
-
1.0
)
*
(
r
-
1.0
)
*
(
s
-
1.0
);
}
if
(
p
>
0.0
)
{
q
*=
-
1.0
;
}
// Check whether in bounds.
p
=
std
::
abs
(
p
);
if
(
2.0
*
p
<
std
::
min
(
3.0
*
xm
*
q
-
std
::
abs
(
tol1
*
q
),
std
::
abs
(
e
*
q
)))
{
e
=
d
;
// Accept interpolation.
d
=
p
/
q
;
}
else
{
d
=
xm
;
// Interpolation failed, use bisection.
e
=
d
;
}
}
else
{
// Bounds decreasing too slowly, use bisection.
d
=
xm
;
e
=
d
;
}
a
=
b
;
//Move last best guess to a.
fa
=
fb
;
if
(
std
::
abs
(
d
)
>
tol1
)
{
// Evaluate new trial root.
b
=
b
+
d
;
}
else
{
b
=
b
+
copysign
(
tol1
,
xm
);
}
ci_func
(
b
,
fb
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
if
(
fb
==
0.0
)
{
break
;
}
}
// if (iter == ITMAX)write(iulog,*) 'brent exceeding maximum iterations', b, fb -- include message???
x
=
b
;
}
// brent
// DESCRIPTION: use a hybrid solver to find the root of equation f(x) = x- h(x), we want to find x, s.t. f(x) = 0.
// the hybrid approach combines the strength of the newton secant approach (find the solution domain)
// and the bisection approach implemented with the Brent's method to guarrantee convergence.
void
hybrid
(
double
&
x0
,
// initial guess and final value of the solution
const
int
&
iv
,
// canopy index
const
double
&
gb_mol
,
// leaf boundary layer conductance (umol H2O/m**2/s)
const
double
&
je
,
// electron transport rate (umol electrons/m**2/s)
const
double
&
cair
,
// Atmospheric CO2 partial pressure (Pa)
const
double
&
oair
,
// Atmospheric O2 partial pressure (Pa)
const
double
&
lmr_z
,
// canopy layer: leaf maintenance respiration rate (umol CO2/m**2/s)
const
double
&
par_z
,
// par absorbed per unit lai for canopy layer (w/m**2)
const
double
&
rh_can
,
// canopy air realtive humidity
double
&
gs_mol
,
// leaf stomatal conductance (umol H2O/m**2/s)
const
double
*
vcmax_z
,
// [length of nlevcan & nrad)] maximum rate of carboxylation (umol co2/m**2/s)
const
double
&
forc_pbot
,
// atmospheric pressure (Pa)
const
bool
&
c3flag
,
// true if C3 and false if C4
double
*
ac
,
// [length of nlevcan & nrad)] Rubisco-limited gross photosynthesis (umol CO2/m**2/s)
double
*
aj
,
// [length of nlevcan & nrad)] RuBP-limited gross photosynthesis (umol CO2/m**2/s)
double
*
ap
,
// [length of nlevcan & nrad)] product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s)
double
*
ag
,
// [length of nlevcan & nrad)] co-limited gross leaf photosynthesis (umol CO2/m**2/s)
double
*
an
,
// [length of nlevcan & nrad)] net leaf photosynthesis (umol CO2/m**2/s)
const
double
&
cp
,
// CO2 compensation point (Pa)
const
double
&
kc
,
// Michaelis-Menten constant for CO2 (Pa)
const
double
&
ko
,
// Michaelis-Menten constant for O2 (Pa)
const
double
&
qe
,
// quantum efficiency, used only for C4 (mol CO2 / mol photons)
const
double
*
tpu_z
,
// triose phosphate utilization rate (umol CO2/m**2/s)
const
double
*
kp_z
,
// initial slope of CO2 response curve (C4 plants)
const
double
&
theta_cj
,
// empirical curvature parameter for ac, aj photosynthesis co-limitation
const
double
&
bbb
,
// Ball-Berry minimum leaf conductance (umol H2O/m**2/s)
const
double
&
mbb
)
// Ball-Berry slope of conductance-photosynthesis relationship
{
static
const
double
eps
=
1.0e-2
;
// relative accuracy
static
const
double
eps1
=
1.0e-4
;
static
const
int
itmax
=
40
;
// maximum number of iterations
double
x1
,
f0
,
f1
,
x
,
dx
,
tol
,
minx
,
minf
;
ci_func
(
x0
,
f0
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
if
(
f0
==
0.0
)
{
return
;
}
minx
=
x0
;
minf
=
f0
;
x1
=
x0
*
0.99
;
ci_func
(
x1
,
f1
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
if
(
f1
==
0.0
)
{
x0
=
x1
;
return
;
}
if
(
f1
<
minf
)
{
minx
=
x1
;
minf
=
f1
;
}
// first use the secant approach, then use the brent approach as a backup
int
iter
=
0
;
while
(
true
)
{
// infinite loop until break
iter
+=
1
;
dx
=
-
f1
*
(
x1
-
x0
)
/
(
f1
-
f0
);
x
=
x1
+
dx
;
tol
=
std
::
abs
(
x
)
*
eps
;
if
(
std
::
abs
(
dx
)
<
tol
)
{
x0
=
x
;
break
;
}
x0
=
x1
;
f0
=
f1
;
x1
=
x
;
ci_func
(
x1
,
f1
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
if
(
f1
<
minf
)
{
minx
=
x1
;
minf
=
f1
;
}
if
(
std
::
abs
(
f1
)
<=
eps1
)
{
x0
=
x1
;
break
;
}
// if a root zone is found, use the brent method for a robust backup strategy
if
(
f1
*
f0
<
0.0
)
{
brent
(
x
,
x0
,
x1
,
f0
,
f1
,
tol
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
x0
=
x
;
break
;
}
if
(
iter
>
itmax
)
{
// in case of failing to converge within itmax iterations
// stop at the minimum function
// this happens because of some other issues besides the stomatal conductance calculation
// and it happens usually in very dry places and more likely with c4 plants.
ci_func
(
minx
,
f1
,
iv
,
gb_mol
,
je
,
cair
,
oair
,
lmr_z
,
par_z
,
rh_can
,
gs_mol
,
vcmax_z
,
forc_pbot
,
c3flag
,
ac
,
aj
,
ap
,
ag
,
an
,
cp
,
kc
,
ko
,
qe
,
tpu_z
,
kp_z
,
theta_cj
,
bbb
,
mbb
);
break
;
}
}
// while loop
}
// hybrid
}
// namespace Photosynthesis
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment