Rev 552 | Rev 557 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 552 | Rev 553 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/snag.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/snag.cpp': |
2 | #include "snag.h"
|
2 | #include "snag.h"
|
3 | #include "tree.h"
|
3 | #include "tree.h"
|
4 | #include "species.h"
|
4 | #include "species.h"
|
5 | #include "globalsettings.h"
|
5 | #include "globalsettings.h"
|
6 | #include "expression.h"
|
6 | #include "expression.h"
|
7 | // for calculation of climate decomposition
|
7 | // for calculation of climate decomposition
|
8 | #include "resourceunit.h"
|
8 | #include "resourceunit.h"
|
9 | #include "watercycle.h"
|
9 | #include "watercycle.h"
|
10 | #include "climate.h"
|
10 | #include "climate.h"
|
11 | #include "model.h"
|
11 | #include "model.h"
|
12 | 12 | ||
13 | /** @class Snag
|
13 | /** @class Snag
|
14 | Snag deals with carbon / nitrogen fluxes from the forest until the reach soil pools.
|
14 | Snag deals with carbon / nitrogen fluxes from the forest until the reach soil pools.
|
15 | Snag lives on the level of the ResourceUnit; carbon fluxes from trees enter Snag, and parts of the biomass of snags
|
15 | Snag lives on the level of the ResourceUnit; carbon fluxes from trees enter Snag, and parts of the biomass of snags
|
16 | is subsequently forwarded to the soil sub model.
|
16 | is subsequently forwarded to the soil sub model.
|
17 | Carbon is stored in three classes (depending on the size)
|
17 | Carbon is stored in three classes (depending on the size)
|
18 | The Snag dynamics class uses the following species parameter:
|
18 | The Snag dynamics class uses the following species parameter:
|
19 | cnFoliage, cnFineroot, cnWood, snagHalflife, snagKSW
|
19 | cnFoliage, cnFineroot, cnWood, snagHalflife, snagKSW
|
20 | 20 | ||
21 | */
|
21 | */
|
22 | // static variables
|
22 | // static variables
|
23 | double Snag::mDBHLower = -1.; |
23 | double Snag::mDBHLower = -1.; |
24 | double Snag::mDBHHigher = 0.; |
24 | double Snag::mDBHHigher = 0.; |
25 | double Snag::mCarbonThreshold[] = {0., 0., 0.}; |
25 | double Snag::mCarbonThreshold[] = {0., 0., 0.}; |
26 | 26 | ||
27 | double CNPair::biomassCFraction = biomassCFraction; // get global from globalsettings.h |
27 | double CNPair::biomassCFraction = biomassCFraction; // get global from globalsettings.h |
28 | 28 | ||
29 | /// add biomass and weigh the parameter_value with the current C-content of the pool
|
29 | /// add biomass and weigh the parameter_value with the current C-content of the pool
|
30 | void CNPool::addBiomass(const double biomass, const double CNratio, const double parameter_value) |
30 | void CNPool::addBiomass(const double biomass, const double CNratio, const double parameter_value) |
31 | {
|
31 | {
|
32 | if (biomass==0.) |
32 | if (biomass==0.) |
33 | return; |
33 | return; |
34 | double new_c = biomass*biomassCFraction; |
34 | double new_c = biomass*biomassCFraction; |
35 | double p_old = C / (new_c + C); |
35 | double p_old = C / (new_c + C); |
36 | mParameter = mParameter*p_old + parameter_value*(1.-p_old); |
36 | mParameter = mParameter*p_old + parameter_value*(1.-p_old); |
37 | CNPair::addBiomass(biomass, CNratio); |
37 | CNPair::addBiomass(biomass, CNratio); |
38 | }
|
38 | }
|
39 | 39 | ||
40 | // increase pool (and weigh the value)
|
40 | // increase pool (and weigh the value)
|
41 | void CNPool::operator+=(const CNPool &s) |
41 | void CNPool::operator+=(const CNPool &s) |
42 | {
|
42 | {
|
43 | if (s.C==0.) |
43 | if (s.C==0.) |
44 | return; |
44 | return; |
45 | mParameter = parameter(s); // calculate weighted parameter |
45 | mParameter = parameter(s); // calculate weighted parameter |
46 | C+=s.C; |
46 | C+=s.C; |
47 | N+=s.N; |
47 | N+=s.N; |
48 | }
|
48 | }
|
49 | 49 | ||
50 | double CNPool::parameter(const CNPool &s) const |
50 | double CNPool::parameter(const CNPool &s) const |
51 | {
|
51 | {
|
52 | if (s.C==0.) |
52 | if (s.C==0.) |
53 | return parameter(); |
53 | return parameter(); |
54 | double p_old = C / (s.C + C); |
54 | double p_old = C / (s.C + C); |
55 | double result = mParameter*p_old + s.parameter()*(1.-p_old); |
55 | double result = mParameter*p_old + s.parameter()*(1.-p_old); |
56 | return result; |
56 | return result; |
57 | }
|
57 | }
|
58 | 58 | ||
59 | 59 | ||
60 | void Snag::setupThresholds(const double lower, const double upper) |
60 | void Snag::setupThresholds(const double lower, const double upper) |
61 | {
|
61 | {
|
62 | if (mDBHLower == lower) |
62 | if (mDBHLower == lower) |
63 | return; |
63 | return; |
64 | mDBHLower = lower; |
64 | mDBHLower = lower; |
65 | mDBHHigher = upper; |
65 | mDBHHigher = upper; |
66 | mCarbonThreshold[0] = lower / 2.; |
66 | mCarbonThreshold[0] = lower / 2.; |
67 | mCarbonThreshold[1] = lower + (upper - lower)/2.; |
67 | mCarbonThreshold[1] = lower + (upper - lower)/2.; |
68 | mCarbonThreshold[2] = upper + (upper - lower)/2.; |
68 | mCarbonThreshold[2] = upper + (upper - lower)/2.; |
69 | //# threshold levels for emptying out the dbh-snag-classes
|
69 | //# threshold levels for emptying out the dbh-snag-classes
|
70 | //# derived from Psme woody allometry, converted to C, with a threshold level set to 10%
|
70 | //# derived from Psme woody allometry, converted to C, with a threshold level set to 10%
|
71 | //# values in kg!
|
71 | //# values in kg!
|
72 | for (int i=0;i<3;i++) |
72 | for (int i=0;i<3;i++) |
73 | mCarbonThreshold[i] = 0.10568*pow(mCarbonThreshold[i],2.4247)*0.5*0.1; |
73 | mCarbonThreshold[i] = 0.10568*pow(mCarbonThreshold[i],2.4247)*0.5*0.1; |
74 | }
|
74 | }
|
75 | 75 | ||
76 | 76 | ||
77 | Snag::Snag() |
77 | Snag::Snag() |
78 | {
|
78 | {
|
79 | mRU = 0; |
79 | mRU = 0; |
80 | CNPair::setCFraction(biomassCFraction); |
80 | CNPair::setCFraction(biomassCFraction); |
81 | }
|
81 | }
|
82 | 82 | ||
83 | void Snag::setup( const ResourceUnit *ru) |
83 | void Snag::setup( const ResourceUnit *ru) |
84 | {
|
84 | {
|
85 | mRU = ru; |
85 | mRU = ru; |
86 | mClimateFactor = 0.; |
86 | mClimateFactor = 0.; |
87 | // branches
|
87 | // branches
|
88 | mBranchCounter=0; |
88 | mBranchCounter=0; |
89 | for (int i=0;i<3;i++) { |
89 | for (int i=0;i<3;i++) { |
90 | mTimeSinceDeath[i] = 0.; |
90 | mTimeSinceDeath[i] = 0.; |
91 | mNumberOfSnags[i] = 0.; |
91 | mNumberOfSnags[i] = 0.; |
92 | mAvgDbh[i] = 0.; |
92 | mAvgDbh[i] = 0.; |
93 | mAvgHeight[i] = 0.; |
93 | mAvgHeight[i] = 0.; |
94 | mAvgVolume[i] = 0.; |
94 | mAvgVolume[i] = 0.; |
95 | mKSW[i] = 0.; |
95 | mKSW[i] = 0.; |
96 | mCurrentKSW[i] = 0.; |
96 | mCurrentKSW[i] = 0.; |
97 | }
|
97 | }
|
98 | mTotalSnagCarbon = 0.; |
98 | mTotalSnagCarbon = 0.; |
99 | if (mDBHLower<=0) |
99 | if (mDBHLower<=0) |
100 | throw IException("Snag::setupThresholds() not called or called with invalid parameters."); |
100 | throw IException("Snag::setupThresholds() not called or called with invalid parameters."); |
101 | }
|
101 | }
|
102 | 102 | ||
103 | // debug outputs
|
103 | // debug outputs
|
104 | QList<QVariant> Snag::debugList() |
104 | QList<QVariant> Snag::debugList() |
105 | {
|
105 | {
|
106 | // list columns
|
106 | // list columns
|
107 | // for three pools
|
107 | // for three pools
|
108 | QList<QVariant> list; |
108 | QList<QVariant> list; |
109 | 109 | ||
110 | // totals
|
110 | // totals
|
111 | list << mTotalSnagCarbon << mTotalIn.C << mTotalToAtm.C << mSWDtoSoil.C << mSWDtoSoil.N; |
111 | list << mTotalSnagCarbon << mTotalIn.C << mTotalToAtm.C << mSWDtoSoil.C << mSWDtoSoil.N; |
112 | // fluxes to labile soil pool and to refractory soil pool
|
112 | // fluxes to labile soil pool and to refractory soil pool
|
113 | list << mLabileFlux.C << mLabileFlux.N << mRefractoryFlux.C << mRefractoryFlux.N; |
113 | list << mLabileFlux.C << mLabileFlux.N << mRefractoryFlux.C << mRefractoryFlux.N; |
114 | 114 | ||
115 | for (int i=0;i<3;i++) { |
115 | for (int i=0;i<3;i++) { |
116 | // pools "swdx_c", "swdx_n", "swdx_count", "swdx_tsd", "toswdx_c", "toswdx_n"
|
116 | // pools "swdx_c", "swdx_n", "swdx_count", "swdx_tsd", "toswdx_c", "toswdx_n"
|
117 | list << mSWD[i].C << mSWD[i].N << mNumberOfSnags[i] << mTimeSinceDeath[i] << mToSWD[i].C << mToSWD[i].N; |
117 | list << mSWD[i].C << mSWD[i].N << mNumberOfSnags[i] << mTimeSinceDeath[i] << mToSWD[i].C << mToSWD[i].N; |
118 | list << mAvgDbh[i] << mAvgHeight[i] << mAvgVolume[i]; |
118 | list << mAvgDbh[i] << mAvgHeight[i] << mAvgVolume[i]; |
119 | }
|
119 | }
|
120 | 120 | ||
121 | // branch/coarse wood pools (5 yrs)
|
121 | // branch/coarse wood pools (5 yrs)
|
122 | for (int i=0;i<5;i++) { |
122 | for (int i=0;i<5;i++) { |
123 | list << mOtherWood[i].C << mOtherWood[i].N; |
123 | list << mOtherWood[i].C << mOtherWood[i].N; |
124 | }
|
124 | }
|
125 | // list << mOtherWood[mBranchCounter].C << mOtherWood[mBranchCounter].N
|
125 | // list << mOtherWood[mBranchCounter].C << mOtherWood[mBranchCounter].N
|
126 | // << mOtherWood[(mBranchCounter+1)%5].C << mOtherWood[(mBranchCounter+1)%5].N
|
126 | // << mOtherWood[(mBranchCounter+1)%5].C << mOtherWood[(mBranchCounter+1)%5].N
|
127 | // << mOtherWood[(mBranchCounter+2)%5].C << mOtherWood[(mBranchCounter+2)%5].N
|
127 | // << mOtherWood[(mBranchCounter+2)%5].C << mOtherWood[(mBranchCounter+2)%5].N
|
128 | // << mOtherWood[(mBranchCounter+3)%5].C << mOtherWood[(mBranchCounter+3)%5].N
|
128 | // << mOtherWood[(mBranchCounter+3)%5].C << mOtherWood[(mBranchCounter+3)%5].N
|
129 | // << mOtherWood[(mBranchCounter+4)%5].C << mOtherWood[(mBranchCounter+4)%5].N;
|
129 | // << mOtherWood[(mBranchCounter+4)%5].C << mOtherWood[(mBranchCounter+4)%5].N;
|
130 | return list; |
130 | return list; |
131 | }
|
131 | }
|
132 | 132 | ||
133 | void Snag::newYear() |
133 | void Snag::newYear() |
134 | {
|
134 | {
|
135 | for (int i=0;i<3;i++) { |
135 | for (int i=0;i<3;i++) { |
136 | mToSWD[i].clear(); // clear transfer pools to standing-woody-debris |
136 | mToSWD[i].clear(); // clear transfer pools to standing-woody-debris |
137 | mCurrentKSW[i] = 0.; |
137 | mCurrentKSW[i] = 0.; |
138 | }
|
138 | }
|
139 | mLabileFlux.clear(); |
139 | mLabileFlux.clear(); |
140 | mRefractoryFlux.clear(); |
140 | mRefractoryFlux.clear(); |
141 | mTotalToAtm.clear(); |
141 | mTotalToAtm.clear(); |
142 | mTotalToExtern.clear(); |
142 | mTotalToExtern.clear(); |
143 | mTotalIn.clear(); |
143 | mTotalIn.clear(); |
144 | mSWDtoSoil.clear(); |
144 | mSWDtoSoil.clear(); |
145 | }
|
145 | }
|
146 | 146 | ||
147 | /// calculate the dynamic climate modifier for decomposition 're'
|
147 | /// calculate the dynamic climate modifier for decomposition 're'
|
148 | /// calculation is done on the level of ResourceUnit because the water content per day is needed.
|
148 | /// calculation is done on the level of ResourceUnit because the water content per day is needed.
|
149 | double Snag::calculateClimateFactors() |
149 | double Snag::calculateClimateFactors() |
150 | {
|
150 | {
|
151 | double deficit; |
- | |
152 | double ft, fw; |
151 | double ft, fw; |
153 | const double top_layer_content = mRU->waterCycle()->topLayerWaterContent(); |
- | |
154 | double f_sum = 0.; |
152 | double f_sum = 0.; |
155 | int iday=0; |
153 | int iday=0; |
- | 154 | // calculate the water-factor for each month (see Adair et al 2008)
|
|
- | 155 | double fw_month[12]; |
|
- | 156 | double ratio; |
|
- | 157 | for (int m=0;m<12;m++) { |
|
- | 158 | if (mRU->waterCycle()->potentialEvapotranspiration()[m]>0.) |
|
- | 159 | ratio = mRU->climate()->precipitationMonth()[m] / mRU->waterCycle()->potentialEvapotranspiration()[m]; |
|
- | 160 | else
|
|
- | 161 | ratio = 0; |
|
- | 162 | fw_month[m] = 1. / (1. + 30.*exp(-8.5*ratio)); |
|
- | 163 | qDebug() <<"month"<< m << "PET" << mRU->waterCycle()->potentialEvapotranspiration()[m] << "prec" <<mRU->climate()->precipitationMonth()[m]; |
|
- | 164 | }
|
|
- | 165 | ||
156 | for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day, ++iday) |
166 | for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day, ++iday) |
157 | {
|
167 | {
|
158 | deficit = mRU->waterCycle()->waterDeficit_mm(iday); |
- | |
159 | - | ||
160 | ft = exp(308.56*(1./56.02-1./((273.+day->temperature)-227.13))); // empirical variable Q10 model of Lloyd and Taylor (1994), see also Adair et al. (2008) |
168 | ft = exp(308.56*(1./56.02-1./((273.+day->temperature)-227.13))); // empirical variable Q10 model of Lloyd and Taylor (1994), see also Adair et al. (2008) |
161 | fw = 1. - limit(deficit / top_layer_content, 0., 1.); |
- | |
162 | // the water effect: depends on the water deficit; if the deficit is higher than the parameterized
|
- | |
163 | // content of the top layer (where most microbial activity is located), than then fw gets 0.
|
- | |
- | 169 | fw = fw_month[day->month-1]; |
|
164 | 170 | ||
165 | f_sum += ft*fw; |
171 | f_sum += ft*fw; |
166 | }
|
172 | }
|
167 | // the climate factor is defined as the arithmentic annual mean value
|
173 | // the climate factor is defined as the arithmentic annual mean value
|
168 | mClimateFactor = f_sum / double(mRU->climate()->daysOfYear()); |
174 | mClimateFactor = f_sum / double(mRU->climate()->daysOfYear()); |
169 | return mClimateFactor; |
175 | return mClimateFactor; |
170 | }
|
176 | }
|
171 | 177 | ||
172 | /// do the yearly calculation
|
178 | /// do the yearly calculation
|
173 | /// see http://iland.boku.ac.at/snag+dynamics
|
179 | /// see http://iland.boku.ac.at/snag+dynamics
|
174 | void Snag::calculateYear() |
180 | void Snag::calculateYear() |
175 | {
|
181 | {
|
176 | mSWDtoSoil.clear(); |
182 | mSWDtoSoil.clear(); |
177 | const double climate_factor_re = calculateClimateFactors(); // calculate anyway, because also the soil module needs it (and currently one can have Snag and Soil only as a couple) |
183 | const double climate_factor_re = calculateClimateFactors(); // calculate anyway, because also the soil module needs it (and currently one can have Snag and Soil only as a couple) |
178 | if (isEmpty()) // nothing to do |
184 | if (isEmpty()) // nothing to do |
179 | return; |
185 | return; |
180 | 186 | ||
181 | // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
|
187 | // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
|
182 | mRefractoryFlux+=mOtherWood[mBranchCounter]; |
188 | mRefractoryFlux+=mOtherWood[mBranchCounter]; |
183 | 189 | ||
184 | mOtherWood[mBranchCounter].clear(); |
190 | mOtherWood[mBranchCounter].clear(); |
185 | mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0. |
191 | mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0. |
186 | // decay of branches/coarse roots
|
192 | // decay of branches/coarse roots
|
187 | for (int i=0;i<5;i++) { |
193 | for (int i=0;i<5;i++) { |
188 | if (mOtherWood[i].C>0.) { |
194 | if (mOtherWood[i].C>0.) { |
189 | double survive_rate = exp(- climate_factor_re * mOtherWood[i].parameter() ); // parameter: the "kyr" value... |
195 | double survive_rate = exp(- climate_factor_re * mOtherWood[i].parameter() ); // parameter: the "kyr" value... |
190 | mOtherWood[i].C *= survive_rate; |
196 | mOtherWood[i].C *= survive_rate; |
191 | }
|
197 | }
|
192 | }
|
198 | }
|
193 | 199 | ||
194 | // process standing snags.
|
200 | // process standing snags.
|
195 | // the input of the current year is in the mToSWD-Pools
|
201 | // the input of the current year is in the mToSWD-Pools
|
196 | for (int i=0;i<3;i++) { |
202 | for (int i=0;i<3;i++) { |
197 | 203 | ||
198 | // update the swd-pool with this years' input
|
204 | // update the swd-pool with this years' input
|
199 | if (!mToSWD[i].isEmpty()) { |
205 | if (!mToSWD[i].isEmpty()) { |
200 | // update decay rate (apply average yearly input to the state parameters)
|
206 | // update decay rate (apply average yearly input to the state parameters)
|
201 | mKSW[i] = mKSW[i]*(mSWD[i].C/(mSWD[i].C+mToSWD[i].C)) + mCurrentKSW[i]*(mToSWD[i].C/(mSWD[i].C+mToSWD[i].C)); |
207 | mKSW[i] = mKSW[i]*(mSWD[i].C/(mSWD[i].C+mToSWD[i].C)) + mCurrentKSW[i]*(mToSWD[i].C/(mSWD[i].C+mToSWD[i].C)); |
202 | //move content to the SWD pool
|
208 | //move content to the SWD pool
|
203 | mSWD[i] += mToSWD[i]; |
209 | mSWD[i] += mToSWD[i]; |
204 | }
|
210 | }
|
205 | 211 | ||
206 | if (mSWD[i].C > 0) { |
212 | if (mSWD[i].C > 0) { |
207 | // reduce the Carbon (note: the N stays, thus the CN ratio changes)
|
213 | // reduce the Carbon (note: the N stays, thus the CN ratio changes)
|
208 | // use the decay rate that is derived as a weighted average of all standing woody debris
|
214 | // use the decay rate that is derived as a weighted average of all standing woody debris
|
209 | double survive_rate = exp(-mKSW[i] *climate_factor_re * 1. ); // 1: timestep |
215 | double survive_rate = exp(-mKSW[i] *climate_factor_re * 1. ); // 1: timestep |
210 | mTotalToAtm.C += mSWD[i].C * (1. - survive_rate); |
216 | mTotalToAtm.C += mSWD[i].C * (1. - survive_rate); |
211 | mSWD[i].C *= survive_rate; |
217 | mSWD[i].C *= survive_rate; |
212 | 218 | ||
213 | // transition to downed woody debris
|
219 | // transition to downed woody debris
|
214 | // update: use negative exponential decay, species parameter: half-life
|
220 | // update: use negative exponential decay, species parameter: half-life
|
215 | // modified for the climatic effect on decomposition, i.e. if decomp is slower, snags stand longer and vice versa
|
221 | // modified for the climatic effect on decomposition, i.e. if decomp is slower, snags stand longer and vice versa
|
216 | // this is loosely oriented on Standcarb2 (http://andrewsforest.oregonstate.edu/pubs/webdocs/models/standcarb2.htm),
|
222 | // this is loosely oriented on Standcarb2 (http://andrewsforest.oregonstate.edu/pubs/webdocs/models/standcarb2.htm),
|
217 | // where lag times for cohort transitions are linearly modified with re although here individual good or bad years have
|
223 | // where lag times for cohort transitions are linearly modified with re although here individual good or bad years have
|
218 | // an immediate effect, the average climatic influence should come through (and it is inherently transient)
|
224 | // an immediate effect, the average climatic influence should come through (and it is inherently transient)
|
219 | // note that swd.hl is species-specific, and thus a weighted average over the species in the input (=mortality)
|
225 | // note that swd.hl is species-specific, and thus a weighted average over the species in the input (=mortality)
|
220 | // needs to be calculated, followed by a weighted update of the previous swd.hl.
|
226 | // needs to be calculated, followed by a weighted update of the previous swd.hl.
|
221 | // As weights here we use stem number, as the processes here pertain individual snags
|
227 | // As weights here we use stem number, as the processes here pertain individual snags
|
222 | // calculate the transition probability of SWD to downed dead wood
|
228 | // calculate the transition probability of SWD to downed dead wood
|
223 | 229 | ||
224 | double half_life = mHalfLife[i] / climate_factor_re; |
230 | double half_life = mHalfLife[i] / climate_factor_re; |
225 | double rate = -M_LN2 / half_life; // M_LN2: math. constant |
231 | double rate = -M_LN2 / half_life; // M_LN2: math. constant |
226 | 232 | ||
227 | // higher decay rate for the class with smallest diameters
|
233 | // higher decay rate for the class with smallest diameters
|
228 | if (i==0) |
234 | if (i==0) |
229 | rate*=2.; |
235 | rate*=2.; |
230 | 236 | ||
231 | double transfer = 1. - exp(rate); |
237 | double transfer = 1. - exp(rate); |
232 | 238 | ||
233 | // calculate flow to soil pool...
|
239 | // calculate flow to soil pool...
|
234 | mSWDtoSoil += mSWD[i] * transfer; |
240 | mSWDtoSoil += mSWD[i] * transfer; |
235 | mRefractoryFlux += mSWD[i] * transfer; |
241 | mRefractoryFlux += mSWD[i] * transfer; |
236 | mSWD[i] *= (1.-transfer); // reduce pool |
242 | mSWD[i] *= (1.-transfer); // reduce pool |
237 | // calculate the stem number of remaining snags
|
243 | // calculate the stem number of remaining snags
|
238 | mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - transfer); |
244 | mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - transfer); |
239 | 245 | ||
240 | mTimeSinceDeath[i] += 1.; |
246 | mTimeSinceDeath[i] += 1.; |
241 | // if stems<0.5, empty the whole cohort into DWD, i.e. release the last bit of C and N and clear the stats
|
247 | // if stems<0.5, empty the whole cohort into DWD, i.e. release the last bit of C and N and clear the stats
|
242 | // also, if the Carbon of an average snag is less than 10% of the original average tree
|
248 | // also, if the Carbon of an average snag is less than 10% of the original average tree
|
243 | // (derived from allometries for the three diameter classes), the whole cohort is emptied out to DWD
|
249 | // (derived from allometries for the three diameter classes), the whole cohort is emptied out to DWD
|
244 | if (mNumberOfSnags[i] < 0.5 || mSWD[i].C / mNumberOfSnags[i] < mCarbonThreshold[i]) { |
250 | if (mNumberOfSnags[i] < 0.5 || mSWD[i].C / mNumberOfSnags[i] < mCarbonThreshold[i]) { |
245 | // clear the pool: add the rest to the soil, clear statistics of the pool
|
251 | // clear the pool: add the rest to the soil, clear statistics of the pool
|
246 | mRefractoryFlux += mSWD[i]; |
252 | mRefractoryFlux += mSWD[i]; |
247 | mSWDtoSoil += mSWD[i]; |
253 | mSWDtoSoil += mSWD[i]; |
248 | mSWD[i].clear(); |
254 | mSWD[i].clear(); |
249 | mAvgDbh[i] = 0.; |
255 | mAvgDbh[i] = 0.; |
250 | mAvgHeight[i] = 0.; |
256 | mAvgHeight[i] = 0.; |
251 | mAvgVolume[i] = 0.; |
257 | mAvgVolume[i] = 0.; |
252 | mKSW[i] = 0.; |
258 | mKSW[i] = 0.; |
253 | mCurrentKSW[i] = 0.; |
259 | mCurrentKSW[i] = 0.; |
254 | mHalfLife[i] = 0.; |
260 | mHalfLife[i] = 0.; |
255 | mTimeSinceDeath[i] = 0.; |
261 | mTimeSinceDeath[i] = 0.; |
256 | }
|
262 | }
|
257 | 263 | ||
258 | }
|
264 | }
|
259 | 265 | ||
260 | }
|
266 | }
|
261 | // total carbon in the snag-container on the RU *after* processing is the content of the
|
267 | // total carbon in the snag-container on the RU *after* processing is the content of the
|
262 | // standing woody debris pools + the branches
|
268 | // standing woody debris pools + the branches
|
263 | mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C + |
269 | mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C + |
264 | mOtherWood[0].C + mOtherWood[1].C + mOtherWood[2].C + mOtherWood[3].C + mOtherWood[4].C; |
270 | mOtherWood[0].C + mOtherWood[1].C + mOtherWood[2].C + mOtherWood[3].C + mOtherWood[4].C; |
265 | }
|
271 | }
|
266 | 272 | ||
267 | /// foliage and fineroot litter is transferred during tree growth.
|
273 | /// foliage and fineroot litter is transferred during tree growth.
|
268 | void Snag::addTurnoverLitter(const Tree *tree, const double litter_foliage, const double litter_fineroot) |
274 | void Snag::addTurnoverLitter(const Tree *tree, const double litter_foliage, const double litter_fineroot) |
269 | {
|
275 | {
|
270 | mLabileFlux.addBiomass(litter_foliage, tree->species()->cnFoliage(), tree->species()->snagKyl()); |
276 | mLabileFlux.addBiomass(litter_foliage, tree->species()->cnFoliage(), tree->species()->snagKyl()); |
271 | mLabileFlux.addBiomass(litter_fineroot, tree->species()->cnFineroot(), tree->species()->snagKyl()); |
277 | mLabileFlux.addBiomass(litter_fineroot, tree->species()->cnFineroot(), tree->species()->snagKyl()); |
272 | }
|
278 | }
|
273 | 279 | ||
274 | /// after the death of the tree the five biomass compartments are processed.
|
280 | /// after the death of the tree the five biomass compartments are processed.
|
275 | void Snag::addMortality(const Tree *tree) |
281 | void Snag::addMortality(const Tree *tree) |
276 | {
|
282 | {
|
277 | const Species *species = tree->species(); |
283 | const Species *species = tree->species(); |
278 | 284 | ||
279 | // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
|
285 | // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
|
280 | mLabileFlux.addBiomass(tree->biomassFoliage(), species->cnFoliage(), tree->species()->snagKyl()); |
286 | mLabileFlux.addBiomass(tree->biomassFoliage(), species->cnFoliage(), tree->species()->snagKyl()); |
281 | mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl()); |
287 | mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl()); |
282 | 288 | ||
283 | // branches and coarse roots are equally distributed over five years:
|
289 | // branches and coarse roots are equally distributed over five years:
|
284 | double biomass_rest = (tree->biomassBranch()+tree->biomassCoarseRoot()) * 0.2; |
290 | double biomass_rest = (tree->biomassBranch()+tree->biomassCoarseRoot()) * 0.2; |
285 | for (int i=0;i<5; i++) |
291 | for (int i=0;i<5; i++) |
286 | mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr()); |
292 | mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr()); |
287 | 293 | ||
288 | // just for book-keeping: keep track of all inputs into branches / roots / swd
|
294 | // just for book-keeping: keep track of all inputs into branches / roots / swd
|
289 | mTotalIn.addBiomass(tree->biomassBranch() + tree->biomassCoarseRoot() + tree->biomassStem(), species->cnWood()); |
295 | mTotalIn.addBiomass(tree->biomassBranch() + tree->biomassCoarseRoot() + tree->biomassStem(), species->cnWood()); |
290 | // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
|
296 | // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
|
291 | int pi = poolIndex(tree->dbh()); // get right transfer pool |
297 | int pi = poolIndex(tree->dbh()); // get right transfer pool |
292 | 298 | ||
293 | // update statistics - stemnumber-weighted averages
|
299 | // update statistics - stemnumber-weighted averages
|
294 | // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
|
300 | // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
|
295 | double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers) |
301 | double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers) |
296 | double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1). |
302 | double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1). |
297 | mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new; |
303 | mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new; |
298 | mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new; |
304 | mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new; |
299 | mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new; |
305 | mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new; |
300 | mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new; |
306 | mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new; |
301 | mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new; |
307 | mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new; |
302 | 308 | ||
303 | // average the decay rate (ksw); this is done based on the carbon content
|
309 | // average the decay rate (ksw); this is done based on the carbon content
|
304 | // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
|
310 | // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
|
305 | if (tree->biomassStem()==0) |
311 | if (tree->biomassStem()==0) |
306 | throw IException("Snag::addMortality: tree without stem biomass!!"); |
312 | throw IException("Snag::addMortality: tree without stem biomass!!"); |
307 | p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction); |
313 | p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction); |
308 | p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction); |
314 | p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction); |
309 | mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new; |
315 | mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new; |
310 | mNumberOfSnags[pi]++; |
316 | mNumberOfSnags[pi]++; |
311 | 317 | ||
312 | // finally add the biomass
|
318 | // finally add the biomass
|
313 | CNPool &to_swd = mToSWD[pi]; |
319 | CNPool &to_swd = mToSWD[pi]; |
314 | to_swd.addBiomass(tree->biomassStem(), species->cnWood(), tree->species()->snagKyr()); |
320 | to_swd.addBiomass(tree->biomassStem(), species->cnWood(), tree->species()->snagKyr()); |
315 | }
|
321 | }
|
316 | 322 | ||
317 | /// add residual biomass of 'tree' after harvesting.
|
323 | /// add residual biomass of 'tree' after harvesting.
|
318 | /// remove_{stem, branch, foliage}_fraction: percentage of biomass compartment that is *removed* by the harvest operation (i.e.: not to stay in the system)
|
324 | /// remove_{stem, branch, foliage}_fraction: percentage of biomass compartment that is *removed* by the harvest operation (i.e.: not to stay in the system)
|
319 | /// records on harvested biomass is collected (mTotalToExtern-pool).
|
325 | /// records on harvested biomass is collected (mTotalToExtern-pool).
|
320 | void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction ) |
326 | void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction ) |
321 | {
|
327 | {
|
322 | const Species *species = tree->species(); |
328 | const Species *species = tree->species(); |
323 | 329 | ||
324 | // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
|
330 | // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
|
325 | mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), species->cnFoliage(), tree->species()->snagKyl()); |
331 | mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), species->cnFoliage(), tree->species()->snagKyl()); |
326 | mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl()); |
332 | mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl()); |
327 | 333 | ||
328 | // for branches, add all biomass that remains in the forest to the soil
|
334 | // for branches, add all biomass that remains in the forest to the soil
|
329 | mRefractoryFlux.addBiomass(tree->biomassBranch()*(1.-remove_branch_fraction), species->cnWood(), tree->species()->snagKyr()); |
335 | mRefractoryFlux.addBiomass(tree->biomassBranch()*(1.-remove_branch_fraction), species->cnWood(), tree->species()->snagKyr()); |
330 | // the same treatment for stem residuals
|
336 | // the same treatment for stem residuals
|
331 | mRefractoryFlux.addBiomass(tree->biomassStem() * remove_stem_fraction, species->cnWood(), tree->species()->snagKyr()); |
337 | mRefractoryFlux.addBiomass(tree->biomassStem() * remove_stem_fraction, species->cnWood(), tree->species()->snagKyr()); |
332 | 338 | ||
333 | // split the corase wood biomass into parts (slower decay)
|
339 | // split the corase wood biomass into parts (slower decay)
|
334 | double biomass_rest = (tree->biomassCoarseRoot()) * 0.2; |
340 | double biomass_rest = (tree->biomassCoarseRoot()) * 0.2; |
335 | for (int i=0;i<5; i++) |
341 | for (int i=0;i<5; i++) |
336 | mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr()); |
342 | mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr()); |
337 | 343 | ||
338 | 344 | ||
339 | // for book-keeping...
|
345 | // for book-keeping...
|
340 | mTotalToExtern.addBiomass(tree->biomassFoliage()*remove_foliage_fraction + |
346 | mTotalToExtern.addBiomass(tree->biomassFoliage()*remove_foliage_fraction + |
341 | tree->biomassBranch()*remove_branch_fraction + |
347 | tree->biomassBranch()*remove_branch_fraction + |
342 | tree->biomassStem()*remove_stem_fraction, species->cnWood()); |
348 | tree->biomassStem()*remove_stem_fraction, species->cnWood()); |
343 | }
|
349 | }
|
344 | 350 | ||
345 | 351 | ||
346 | 352 | ||
347 | 353 | ||
348 | 354 |