Skip to content

Commit ef40744

Browse files
tbohnJoe Hamman
authored andcommitted
Added simulation of soil carbon storage and fluxes. This formulation was
taken mostly from the LPJ model (Sitch, 2003), which in turn used a Lloyd-Taylor model for the dependence of soil respiration on soil temperature. The dependence of soil respiration on soil moisture was based on the formulation of Yi et al (2012) but modified to allow a small respiration rate under saturated conditions. At this point, we do not simulate the storage of carbon in living biomass. Therefore, the flux of carbon into the soil (litterfall) is set equal to the total NPP of the previous calendar year, spread evenly over the current year. As in the LPJ model, soil carbon is stored in 3 pools: litter (fast), intermediate, and slow; with associated turnover times of 2.86 y, 33.3 y, and 1,000 y, respectively. Litterfall enters the litter pool. Carbon exits the litter pool through respiration (RhLitter). A fraction (fAir) of this respired carbon is in the form of CO2 and is vented directly to the atmosphere (RhLitter2Atm). The remainder is sent to the intermediate and slow pools in the proportions fInter and (1-fInter), respectively. These pools also respire carbon, which is assumed to be in the form of CO2 and vented directly to the atmosphere. There are several new output variables associated with this feature: OUT_RHET: Total heterotrophic respiration vented to the atmosphere (= RhLitter2Atm+RhInter+RhSlow) [g C/m2d] OUT_NEE: Net Ecosystem Exchange (= NPP-RHET) [g C/m2d] OUT_LITTERFALL: Flux of carbon from living biomass into litter pool [g C/m2d] OUT_CLITTER: Carbon density in the litter pool [g C/m2] OUT_CINTER: Carbon density in the intermediate pool [g C/m2] OUT_CSLOW: Carbon density in the slow pool [g C/m2] This feature is part of the carbon cycle, controlled by the setting of the CARBON option in the global parameter file.
1 parent fdaa579 commit ef40744

17 files changed

+608
-24
lines changed

src/LAKE.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
2010-Dec-28 Added latitude to alblake() arglist. TJB
2727
2011-Mar-01 Added rescale_snow_storage(). Added terms to argument
2828
list of initialize_lake(). TJB
29+
2013-Jul-25 Added advect_carbon_storage(). TJB
2930
******************************************************************************/
3031

3132
//#ifndef LAKE_SET
@@ -70,6 +71,7 @@
7071

7172
double adjflux(double, double, double ,double, double, double, double,
7273
double, double, double, double *, double *);
74+
void advect_carbon_storage(double, double, lake_var_struct *, cell_data_struct *);
7375
void advect_soil_veg_storage(double, double, double, double *, soil_con_struct *, veg_con_struct *, cell_data_struct *, veg_var_struct *, lake_con_struct);
7476
void advect_snow_storage(double, double, double, snow_data_struct *);
7577
void alblake(double, double, double *, double *, float *, float *, double, double,

src/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
# 2013-Jul-25 Added compute_coszen.c. TJB
4141
# 2013-Jul-25 Added calc_Nscale_factors.c, canopy_assimilation.c, faparl.c,
4242
# photosynth.c. TJB
43+
# 2013-Jul-25 Added compute_soil_resp.c and soil_carbon_balance.c. TJB
4344
#
4445
# $Id$
4546
#
@@ -86,7 +87,7 @@ OBJS = CalcAerodynamic.o CalcBlowingSnow.o SnowPackEnergyBalance.o \
8687
calc_water_energy_balance_errors.o canopy_assimilation.o canopy_evap.o \
8788
check_files.o check_state_file.o close_files.o cmd_proc.o \
8889
compress_files.o compute_coszen.o compute_dz.o compute_pot_evap.o \
89-
compute_treeline.o compute_zwt.o correct_precip.o \
90+
compute_soil_resp.o compute_treeline.o compute_zwt.o correct_precip.o \
9091
display_current_settings.o dist_prec.o estimate_T1.o faparl.o free_dist_prcp.o \
9192
free_vegcon.o frozen_soil.o full_energy.o func_atmos_energy_bal.o \
9293
func_atmos_moist_bal.o func_canopy_energy_bal.o \
@@ -104,7 +105,7 @@ OBJS = CalcAerodynamic.o CalcBlowingSnow.o SnowPackEnergyBalance.o \
104105
read_snowband.o read_soilparam.o read_soilparam_arc.o read_veglib.o \
105106
read_vegparam.o redistribute_during_storm.o root_brent.o runoff.o \
106107
set_output_defaults.o snow_intercept.o snow_melt.o \
107-
snow_utility.o soil_conduction.o \
108+
snow_utility.o soil_carbon_balance.o soil_conduction.o \
108109
soil_thermal_eqn.o solve_snow.o \
109110
surface_fluxes.o svp.o vicNl.o vicerror.o \
110111
write_data.o write_forcing_file.o write_header.o write_layer.o \

src/README.txt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,64 @@ Added simulation of photosynthesis.
145145

146146

147147

148+
Added simulation of soil carbon storage and fluxes.
149+
150+
Files Affected:
151+
152+
compute_soil_resp.c (new)
153+
full_energy.c
154+
initialize_lake.c
155+
initialize_soil.c
156+
initialize_veg.c
157+
LAKE.h
158+
lakes.eb.c
159+
Makefile
160+
output_list_utils.c
161+
put_data.c
162+
read_initial_model_state.c
163+
soil_carbon_balance.c (new)
164+
surface_fluxes.c
165+
vicNl_def.h
166+
vicNl.h
167+
write_model_state.c
168+
169+
Description:
170+
171+
Added simulation of soil carbon storage and fluxes. This formulation was
172+
taken mostly from the LPJ model (Sitch, 2003), which in turn used a
173+
Lloyd-Taylor model for the dependence of soil respiration on soil
174+
temperature. The dependence of soil respiration on soil moisture was
175+
based on the formulation of Yi et al (2012) but modified to allow a small
176+
respiration rate under saturated conditions.
177+
178+
At this point, we do not simulate the storage of carbon in living biomass.
179+
Therefore, the flux of carbon into the soil (litterfall) is set equal to
180+
the total NPP of the previous calendar year, spread evenly over the current
181+
year. As in the LPJ model, soil carbon is stored in 3 pools: litter (fast),
182+
intermediate, and slow; with associated turnover times of 2.86 y, 33.3 y, and
183+
1,000 y, respectively. Litterfall enters the litter pool. Carbon exits the
184+
litter pool through respiration (RhLitter). A fraction (fAir) of this
185+
respired carbon is in the form of CO2 and is vented directly to the atmosphere
186+
(RhLitter2Atm). The remainder is sent to the intermediate and slow pools
187+
in the proportions fInter and (1-fInter), respectively. These pools also
188+
respire carbon, which is assumed to be in the form of CO2 and vented directly
189+
to the atmosphere.
190+
191+
There are several new output variables associated with this feature:
192+
OUT_RHET: Total heterotrophic respiration vented to the atmosphere
193+
(= RhLitter2Atm+RhInter+RhSlow) [g C/m2d]
194+
OUT_NEE: Net Ecosystem Exchange (= NPP-RHET) [g C/m2d]
195+
OUT_LITTERFALL: Flux of carbon from living biomass into litter pool [g C/m2d]
196+
OUT_CLITTER: Carbon density in the litter pool [g C/m2]
197+
OUT_CINTER: Carbon density in the intermediate pool [g C/m2]
198+
OUT_CSLOW: Carbon density in the slow pool [g C/m2]
199+
200+
This feature is part of the carbon cycle, controlled by the setting of the
201+
CARBON option in the global parameter file.
202+
203+
204+
205+
148206
Bug Fixes:
149207
----------
150208

src/compute_soil_resp.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/********************************************************************************
2+
filename : compute_soil_resp.c
3+
purpose : Calculate soil respiration (heterotrophic respiration, or Rh)
4+
interface : - input :
5+
- Nnodes: number of points (vertically) at which to evaluate soil respiration
6+
- dZ[]: array of layer thicknesses [m] pertaining to nodes
7+
- dZTot: total depth [m] of all layers (total depth of soil containing carbon)
8+
- dt: timestep length [h]
9+
- T[]: array of node temperatures [K]
10+
- w[]: array of node moisture fractions [fraction]
11+
- CLitter: carbon storage in litter pool [gC/m2]
12+
- CInter: carbon storage in intermediate pool [gC/m2]
13+
- CSlow: carbon storage in slow pool [gC/m2]
14+
Note: the litter pool is concentrated at the soil surface, while the intermediate and
15+
slow pools are both assumed to be distributed uniformly throughout soil column.
16+
17+
- constants:
18+
- E0_LT: Lloyd-Taylor E0 parameter [K]
19+
- T0_LT: Lloyd-Taylor E0 parameter [K]
20+
- wminFM: minimum soil moisture (fraction) at which soil respiration can occur
21+
- wmaxFM: maximum soil moisture (fraction) at which soil respiration can occur
22+
- woptFM: soil moisture (fraction) at which maximum soil respiration occurs
23+
- Rhsat: ratio of soil respiration rate under saturated conditions (w=wmaxFM) to
24+
that under optimal conditions (w=woptFM)
25+
- Rfactor: scaling factor to account for other (non-moisture) sources of inhibition
26+
of respiration
27+
- tauLitter: Litter pool turnover time [y]
28+
- tauInter: Intermediate pool turnover time [y]
29+
- tauSlow: Slow pool turnover time [y]
30+
31+
- output:
32+
- RhLitter: Soil respiration from litter pool [gC/m2]
33+
- RhInterTot: Soil respiration from intermediate pool [gC/m2]
34+
- RhSlowTot: Soil respiration from slow pool [gC/m2]
35+
36+
programmer: Ted Bohn
37+
date : July 25, 2013
38+
changes :
39+
references:
40+
********************************************************************************/
41+
42+
#include <stdio.h>
43+
#include <stdlib.h>
44+
#include <string.h>
45+
#include <vicNl.h>
46+
47+
static char vcid[] = "$Id: $";
48+
49+
void compute_soil_resp(int Nnodes,
50+
double *dZ,
51+
double dZTot,
52+
double dt,
53+
double *T,
54+
double *w,
55+
double CLitter,
56+
double CInter,
57+
double CSlow,
58+
double *RhLitter,
59+
double *RhInterTot,
60+
double *RhSlowTot)
61+
{
62+
extern option_struct options;
63+
int i;
64+
double Tref;
65+
double *TK;
66+
double fTLitter;
67+
double *fTSoil;
68+
double fMLitter;
69+
double *fMSoil;
70+
double *CInterNode;
71+
double *CSlowNode;
72+
double *RhInter;
73+
double *RhSlow;
74+
75+
/* Allocate temp arrays */
76+
TK = (double*)calloc(Nnodes,sizeof(double));
77+
fTSoil = (double*)calloc(Nnodes,sizeof(double));
78+
fMSoil = (double*)calloc(Nnodes,sizeof(double));
79+
CInterNode = (double*)calloc(Nnodes,sizeof(double));
80+
CSlowNode = (double*)calloc(Nnodes,sizeof(double));
81+
RhInter = (double*)calloc(Nnodes,sizeof(double));
82+
RhSlow = (double*)calloc(Nnodes,sizeof(double));
83+
84+
/* Compute Lloyd-Taylor temperature dependence */
85+
Tref = 10+KELVIN; /* reference temperature of 10 C */
86+
for (i=0; i<Nnodes; i++) {
87+
TK[i] = T[i]+KELVIN;
88+
if (TK[i] < T0_LT) TK[i] = T0_LT;
89+
}
90+
fTLitter = exp( E0_LT * ( 1/(Tref-T0_LT) - 1/(TK[0]-T0_LT) ) );
91+
for (i=0; i<Nnodes; i++) {
92+
fTSoil[i] = exp( E0_LT * ( 1/(Tref-T0_LT) - 1/(TK[i]-T0_LT) ) );
93+
}
94+
95+
/* Compute moisture dependence */
96+
for (i=0; i<Nnodes; i++) {
97+
if (w[i] < wminFM) w[i] = wminFM;
98+
if (w[i] > wmaxFM) w[i] = wmaxFM;
99+
}
100+
if (w[0] <= woptFM)
101+
fMLitter = (w[0]-wminFM)*(w[0]-wmaxFM)/((w[0]-wminFM)*(w[0]-wmaxFM)-(w[0]-woptFM)*(w[0]-woptFM));
102+
else
103+
fMLitter = Rhsat + (1-Rhsat)*(w[0]-wminFM)*(w[0]-wmaxFM)/((w[0]-wminFM)*(w[0]-wmaxFM)-(w[0]-woptFM)*(w[0]-woptFM));
104+
if (fMLitter > 1.0) fMLitter = 1.0;
105+
if (fMLitter < 0.0) fMLitter = 0.0;
106+
for (i=0; i<Nnodes; i++) {
107+
if (w[i] <= woptFM)
108+
fMSoil[i] = (w[i]-wminFM)*(w[i]-wmaxFM)/((w[i]-wminFM)*(w[i]-wmaxFM)-(w[i]-woptFM)*(w[i]-woptFM));
109+
else
110+
fMSoil[i] = Rhsat + (1-Rhsat)*(w[i]-wminFM)*(w[i]-wmaxFM)/((w[i]-wminFM)*(w[i]-wmaxFM)-(w[i]-woptFM)*(w[i]-woptFM));
111+
if (fMSoil[i] > 1.0) fMSoil[i] = 1.0;
112+
if (fMSoil[i] < 0.0) fMSoil[i] = 0.0;
113+
}
114+
115+
/* Compute C per node */
116+
for (i=0; i<Nnodes; i++) {
117+
CInterNode[i] = CInter * dZ[i]/dZTot;
118+
CSlowNode[i] = CSlow * dZ[i]/dZTot;
119+
}
120+
121+
/* Compute Rh for various pools, nodes; C fluxes in [gC/m2d] */
122+
*RhLitter = Rfactor*(fTLitter*fMLitter/(tauLitter*365.25*24/dt))*CLitter;
123+
*RhInterTot = 0;
124+
*RhSlowTot = 0;
125+
for (i=0; i<Nnodes; i++) {
126+
RhInter[i] = Rfactor*(fTSoil[i]*fMSoil[i]/(tauInter*365.25*24/dt))*CInterNode[i];
127+
RhSlow[i] = Rfactor*(fTSoil[i]*fMSoil[i]/(tauSlow*365.25*24/dt))*CSlowNode[i];
128+
*RhInterTot += RhInter[i];
129+
*RhSlowTot += RhSlow[i];
130+
}
131+
132+
free((char *)TK);
133+
free((char *)fTSoil);
134+
free((char *)fMSoil);
135+
free((char *)CInterNode);
136+
free((char *)CSlowNode);
137+
free((char *)RhInter);
138+
free((char *)RhSlow);
139+
140+
}
141+

src/full_energy.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ int full_energy(char NEWCELL,
107107
2012-Aug-28 Added accumulation of rain and snow over lake to grid cell
108108
totals. TJB
109109
2013-Jul-25 Added photosynthesis terms. TJB
110+
2013-Jul-25 Added soil carbon terms. TJB
110111
111112
**********************************************************************/
112113
{
@@ -407,11 +408,7 @@ int full_energy(char NEWCELL,
407408
veg_var[dist][iveg][band].rsLayer[cidx] = HUGE_RESIST;
408409
}
409410
veg_var[dist][iveg][band].aPAR = 0;
410-
}
411-
}
412-
if (dmy[rec].hour == 0) {
413-
for (dist=0; dist<Ndist; dist++) {
414-
for(band=0; band<Nbands; band++) {
411+
if (dmy->hour == 0) {
415412
calc_Nscale_factors(veg_lib[veg_class].NscaleFlag,
416413
veg_con[iveg].CanopLayerBnd,
417414
veg_lib[veg_class].LAI[dmy[rec].month-1],
@@ -421,6 +418,10 @@ int full_energy(char NEWCELL,
421418
dmy[rec],
422419
veg_var[dist][iveg][band].NscaleFactor);
423420
}
421+
if (dmy[rec].month == 1 && dmy[rec].day == 1) {
422+
veg_var[dist][iveg][band].AnnualNPPPrev = veg_var[dist][iveg][band].AnnualNPP;
423+
veg_var[dist][iveg][band].AnnualNPP = 0;
424+
}
424425
}
425426
}
426427
}

src/initialize_lake.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ int initialize_lake (lake_var_struct *lake,
7474
2012-Feb-08 Renamed depth_full_snow_cover to max_snow_distrib_slope
7575
and clarified the descriptions of the SPATIAL_SNOW
7676
option. TJB
77+
2013-Jul-25 Added soil carbon terms. TJB
7778
**********************************************************************/
7879
{
7980
extern option_struct options;
@@ -331,6 +332,16 @@ int initialize_lake (lake_var_struct *lake,
331332
lake->soil.pot_evap[i] = 0.0;
332333
}
333334
}
335+
if (options.CARBON) {
336+
lake->soil.RhLitter = 0.0;
337+
lake->soil.RhLitter2Atm = 0.0;
338+
lake->soil.RhInter = 0.0;
339+
lake->soil.RhSlow = 0.0;
340+
lake->soil.RhTot = 0.0;
341+
lake->soil.CLitter = 0.0;
342+
lake->soil.CInter = 0.0;
343+
lake->soil.CSlow = 0.0;
344+
}
334345

335346
return(0);
336347

src/initialize_soil.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void initialize_soil (cell_data_struct **cell,
2626
2009-Dec-11 Removed min_liq and options.MIN_LIQ. TJB
2727
2011-Mar-01 Now initializes more cell data structure terms, including
2828
asat and zwt. TJB
29+
2013-Jul-25 Added soil carbon terms. TJB
2930
**********************************************************************/
3031
{
3132
extern option_struct options;
@@ -53,6 +54,9 @@ void initialize_soil (cell_data_struct **cell,
5354
}
5455
compute_runoff_and_asat(soil_con, tmp_moist, 0, &(cell[veg][band].asat), &tmp_runoff);
5556
wrap_compute_zwt(soil_con, &(cell[veg][band]));
57+
cell[veg][band].CLitter = 0;
58+
cell[veg][band].CInter = 0;
59+
cell[veg][band].CSlow = 0;
5660
}
5761
}
5862

src/initialize_veg.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void initialize_veg(veg_var_struct **veg_var,
2121
types to include the wetland vegetation fraction when the
2222
lake model is active. LCB
2323
2013-Jul-25 Added photosynthesis terms. TJB
24+
2013-Jul-25 Added AnnualNPP. TJB
2425
2526
**********************************************************************/
2627
{
@@ -45,6 +46,8 @@ void initialize_veg(veg_var_struct **veg_var,
4546
veg_var[i][j].Rgrowth = 0.0;
4647
veg_var[i][j].Raut = 0.0;
4748
veg_var[i][j].NPP = 0.0;
49+
veg_var[i][j].AnnualNPP = 0.0;
50+
veg_var[i][j].AnnualNPPPrev = 0.0;
4851
for ( k = 0 ; k < options.Ncanopy ; k++ ) {
4952
veg_var[i][j].NscaleFactor[k] = 0.0;
5053
veg_var[i][j].aPARLayer[k] = 0.0;

src/lakes.eb.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,7 @@ int water_balance (lake_var_struct *lake, lake_con_struct lake_con, int dt, dist
19311931
2011-Mar-07 Fixed bug in computation of lake->soil.runoff, baseflow, etc . TJB
19321932
2011-Mar-31 Fixed typo in declaration of frost_fract. TJB
19331933
2011-Sep-22 Added logic to handle lake snow cover extent. TJB
1934+
2013-Jul-25 Added soil carbon terms. TJB
19341935
**********************************************************************/
19351936
{
19361937
extern option_struct options;
@@ -2385,6 +2386,10 @@ int water_balance (lake_var_struct *lake, lake_con_struct lake_con, int dt, dist
23852386
}
23862387
}
23872388

2389+
if (options.CARBON) {
2390+
advect_carbon_storage(lakefrac, newfraction, lake, &(cell[WET][iveg][band]));
2391+
}
2392+
23882393
free((char*)delta_moist);
23892394
free((char*)moist);
23902395

@@ -2766,3 +2771,39 @@ void rescale_snow_energy_fluxes(double oldfrac,
27662771

27672772
}
27682773

2774+
void advect_carbon_storage(double lakefrac,
2775+
double newfraction,
2776+
lake_var_struct *lake,
2777+
cell_data_struct *cell)
2778+
/**********************************************************************
2779+
advect_carbon_storage Ted Bohn 2013
2780+
2781+
Function to update carbon storage in the lake and wetland soil columns
2782+
to account for changes in wetland area.
2783+
2784+
Modifications:
2785+
**********************************************************************/
2786+
{
2787+
2788+
extern option_struct options;
2789+
int i,k;
2790+
2791+
if (newfraction > lakefrac) { // lake grew, wetland shrank
2792+
2793+
if (newfraction < SMALL) newfraction = SMALL;
2794+
lake->soil.CLitter = (lakefrac*lake->soil.CLitter + (newfraction-lakefrac)*cell->CLitter)/newfraction;
2795+
lake->soil.CInter = (lakefrac*lake->soil.CInter + (newfraction-lakefrac)*cell->CInter)/newfraction;
2796+
lake->soil.CSlow = (lakefrac*lake->soil.CSlow + (newfraction-lakefrac)*cell->CSlow)/newfraction;
2797+
2798+
}
2799+
2800+
else if (newfraction < lakefrac) { // lake shrank, wetland grew
2801+
2802+
if ((1-newfraction) < SMALL) newfraction = 1 - SMALL;
2803+
cell->CLitter = ((lakefrac-newfraction)*lake->soil.CLitter + (1-lakefrac)*cell->CLitter)/(1-newfraction);
2804+
cell->CInter = ((lakefrac-newfraction)*lake->soil.CInter + (1-lakefrac)*cell->CInter)/(1-newfraction);
2805+
cell->CSlow = ((lakefrac-newfraction)*lake->soil.CSlow + (1-lakefrac)*cell->CSlow)/(1-newfraction);
2806+
2807+
}
2808+
2809+
}

0 commit comments

Comments
 (0)