Subversion Repositories public iLand

Rev

Rev 547 | Rev 553 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 547 Rev 552
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;
151
    double deficit;
152
    double ft, fw;
152
    double ft, fw;
153
    const double top_layer_content = mRU->waterCycle()->topLayerWaterContent();
153
    const double top_layer_content = mRU->waterCycle()->topLayerWaterContent();
154
    double f_sum = 0.;
154
    double f_sum = 0.;
155
    for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day)
-
 
-
 
155
    int iday=0;
-
 
156
    for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day, ++iday)
156
    {
157
    {
157
        deficit = mRU->waterCycle()->waterDeficit_mm(day->day);
-
 
-
 
158
        deficit = mRU->waterCycle()->waterDeficit_mm(iday);
158
159
159
        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)
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)
160
        fw = 1. - limit(deficit / top_layer_content, 0., 1.);
161
        fw = 1. - limit(deficit / top_layer_content, 0., 1.);
161
        // the water effect: depends on the water deficit; if the deficit is higher than the parameterized
162
        // the water effect: depends on the water deficit; if the deficit is higher than the parameterized
162
        // content of the top layer (where most microbial activity is located), than then fw gets 0.
163
        // content of the top layer (where most microbial activity is located), than then fw gets 0.
163
164
164
        f_sum += ft*fw;
165
        f_sum += ft*fw;
165
    }
166
    }
166
    // the climate factor is defined as the arithmentic annual mean value
167
    // the climate factor is defined as the arithmentic annual mean value
167
    mClimateFactor = f_sum / double(mRU->climate()->daysOfYear());
168
    mClimateFactor = f_sum / double(mRU->climate()->daysOfYear());
168
    return mClimateFactor;
169
    return mClimateFactor;
169
}
170
}
170
171
171
/// do the yearly calculation
172
/// do the yearly calculation
172
/// see http://iland.boku.ac.at/snag+dynamics
173
/// see http://iland.boku.ac.at/snag+dynamics
173
void Snag::calculateYear()
174
void Snag::calculateYear()
174
{
175
{
175
    mSWDtoSoil.clear();
176
    mSWDtoSoil.clear();
176
    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)
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)
177
    if (isEmpty()) // nothing to do
178
    if (isEmpty()) // nothing to do
178
        return;
179
        return;
179
180
180
    // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
181
    // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
181
    mRefractoryFlux+=mOtherWood[mBranchCounter];
182
    mRefractoryFlux+=mOtherWood[mBranchCounter];
182
183
183
    mOtherWood[mBranchCounter].clear();
184
    mOtherWood[mBranchCounter].clear();
184
    mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0.
185
    mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0.
185
    // decay of branches/coarse roots
186
    // decay of branches/coarse roots
186
    for (int i=0;i<5;i++) {
187
    for (int i=0;i<5;i++) {
187
        if (mOtherWood[i].C>0.) {
188
        if (mOtherWood[i].C>0.) {
188
            double survive_rate = exp(- climate_factor_re * mOtherWood[i].parameter() ); // parameter: the "kyr" value...
189
            double survive_rate = exp(- climate_factor_re * mOtherWood[i].parameter() ); // parameter: the "kyr" value...
189
            mOtherWood[i].C *= survive_rate;
190
            mOtherWood[i].C *= survive_rate;
190
        }
191
        }
191
    }
192
    }
192
193
193
    // process standing snags.
194
    // process standing snags.
194
    // the input of the current year is in the mToSWD-Pools
195
    // the input of the current year is in the mToSWD-Pools
195
    for (int i=0;i<3;i++) {
196
    for (int i=0;i<3;i++) {
196
197
197
        // update the swd-pool with this years' input
198
        // update the swd-pool with this years' input
198
        if (!mToSWD[i].isEmpty()) {
199
        if (!mToSWD[i].isEmpty()) {
199
            // update decay rate (apply average yearly input to the state parameters)
200
            // update decay rate (apply average yearly input to the state parameters)
200
            mKSW[i] = mKSW[i]*(mSWD[i].C/(mSWD[i].C+mToSWD[i].C)) + mCurrentKSW[i]*(mToSWD[i].C/(mSWD[i].C+mToSWD[i].C));
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));
201
            //move content to the SWD pool
202
            //move content to the SWD pool
202
            mSWD[i] += mToSWD[i];
203
            mSWD[i] += mToSWD[i];
203
        }
204
        }
204
205
205
        if (mSWD[i].C > 0) {
206
        if (mSWD[i].C > 0) {
206
            // reduce the Carbon (note: the N stays, thus the CN ratio changes)
207
            // reduce the Carbon (note: the N stays, thus the CN ratio changes)
207
            // use the decay rate that is derived as a weighted average of all standing woody debris
208
            // use the decay rate that is derived as a weighted average of all standing woody debris
208
            double survive_rate = exp(-mKSW[i] *climate_factor_re * 1. ); // 1: timestep
209
            double survive_rate = exp(-mKSW[i] *climate_factor_re * 1. ); // 1: timestep
209
            mTotalToAtm.C += mSWD[i].C * (1. - survive_rate);
210
            mTotalToAtm.C += mSWD[i].C * (1. - survive_rate);
210
            mSWD[i].C *= survive_rate;
211
            mSWD[i].C *= survive_rate;
211
212
212
            // transition to downed woody debris
213
            // transition to downed woody debris
213
            // update: use negative exponential decay, species parameter: half-life
214
            // update: use negative exponential decay, species parameter: half-life
214
            // modified for the climatic effect on decomposition, i.e. if decomp is slower, snags stand longer and vice versa
215
            // modified for the climatic effect on decomposition, i.e. if decomp is slower, snags stand longer and vice versa
215
            // this is loosely oriented on Standcarb2 (http://andrewsforest.oregonstate.edu/pubs/webdocs/models/standcarb2.htm),
216
            // this is loosely oriented on Standcarb2 (http://andrewsforest.oregonstate.edu/pubs/webdocs/models/standcarb2.htm),
216
            // where lag times for cohort transitions are linearly modified with re although here individual good or bad years have
217
            // where lag times for cohort transitions are linearly modified with re although here individual good or bad years have
217
            // an immediate effect, the average climatic influence should come through (and it is inherently transient)
218
            // an immediate effect, the average climatic influence should come through (and it is inherently transient)
218
            // note that swd.hl is species-specific, and thus a weighted average over the species in the input (=mortality)
219
            // note that swd.hl is species-specific, and thus a weighted average over the species in the input (=mortality)
219
            // needs to be calculated, followed by a weighted update of the previous swd.hl.
220
            // needs to be calculated, followed by a weighted update of the previous swd.hl.
220
            // As weights here we use stem number, as the processes here pertain individual snags
221
            // As weights here we use stem number, as the processes here pertain individual snags
221
            // calculate the transition probability of SWD to downed dead wood
222
            // calculate the transition probability of SWD to downed dead wood
222
223
223
            double half_life = mHalfLife[i] / climate_factor_re;
224
            double half_life = mHalfLife[i] / climate_factor_re;
224
            double rate = -M_LN2 / half_life; // M_LN2: math. constant
225
            double rate = -M_LN2 / half_life; // M_LN2: math. constant
225
226
226
            // higher decay rate for the class with smallest diameters
227
            // higher decay rate for the class with smallest diameters
227
            if (i==0)
228
            if (i==0)
228
                rate*=2.;
229
                rate*=2.;
229
230
230
            double transfer = 1. - exp(rate);
231
            double transfer = 1. - exp(rate);
231
232
232
            // calculate flow to soil pool...
233
            // calculate flow to soil pool...
233
            mSWDtoSoil += mSWD[i] * transfer;
234
            mSWDtoSoil += mSWD[i] * transfer;
234
            mRefractoryFlux += mSWD[i] * transfer;
235
            mRefractoryFlux += mSWD[i] * transfer;
235
            mSWD[i] *= (1.-transfer); // reduce pool
236
            mSWD[i] *= (1.-transfer); // reduce pool
236
            // calculate the stem number of remaining snags
237
            // calculate the stem number of remaining snags
237
            mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - transfer);
238
            mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - transfer);
238
239
239
            mTimeSinceDeath[i] += 1.;
240
            mTimeSinceDeath[i] += 1.;
240
            // if stems<0.5, empty the whole cohort into DWD, i.e. release the last bit of C and N and clear the stats
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
241
            // also, if the Carbon of an average snag is less than 10% of the original average tree
242
            // also, if the Carbon of an average snag is less than 10% of the original average tree
242
            // (derived from allometries for the three diameter classes), the whole cohort is emptied out to DWD
243
            // (derived from allometries for the three diameter classes), the whole cohort is emptied out to DWD
243
            if (mNumberOfSnags[i] < 0.5 || mSWD[i].C / mNumberOfSnags[i] < mCarbonThreshold[i]) {
244
            if (mNumberOfSnags[i] < 0.5 || mSWD[i].C / mNumberOfSnags[i] < mCarbonThreshold[i]) {
244
                // clear the pool: add the rest to the soil, clear statistics of the pool
245
                // clear the pool: add the rest to the soil, clear statistics of the pool
245
                mRefractoryFlux += mSWD[i];
246
                mRefractoryFlux += mSWD[i];
246
                mSWDtoSoil += mSWD[i];
247
                mSWDtoSoil += mSWD[i];
247
                mSWD[i].clear();
248
                mSWD[i].clear();
248
                mAvgDbh[i] = 0.;
249
                mAvgDbh[i] = 0.;
249
                mAvgHeight[i] = 0.;
250
                mAvgHeight[i] = 0.;
250
                mAvgVolume[i] = 0.;
251
                mAvgVolume[i] = 0.;
251
                mKSW[i] = 0.;
252
                mKSW[i] = 0.;
252
                mCurrentKSW[i] = 0.;
253
                mCurrentKSW[i] = 0.;
253
                mHalfLife[i] = 0.;
254
                mHalfLife[i] = 0.;
254
                mTimeSinceDeath[i] = 0.;
255
                mTimeSinceDeath[i] = 0.;
255
            }
256
            }
256
257
257
        }
258
        }
258
259
259
    }
260
    }
260
    // total carbon in the snag-container on the RU *after* processing is the content of the
261
    // total carbon in the snag-container on the RU *after* processing is the content of the
261
    // standing woody debris pools + the branches
262
    // standing woody debris pools + the branches
262
    mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C +
263
    mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C +
263
                       mOtherWood[0].C + mOtherWood[1].C + mOtherWood[2].C + mOtherWood[3].C + mOtherWood[4].C;
264
                       mOtherWood[0].C + mOtherWood[1].C + mOtherWood[2].C + mOtherWood[3].C + mOtherWood[4].C;
264
}
265
}
265
266
266
/// foliage and fineroot litter is transferred during tree growth.
267
/// foliage and fineroot litter is transferred during tree growth.
267
void Snag::addTurnoverLitter(const Tree *tree, const double litter_foliage, const double litter_fineroot)
268
void Snag::addTurnoverLitter(const Tree *tree, const double litter_foliage, const double litter_fineroot)
268
{
269
{
269
    mLabileFlux.addBiomass(litter_foliage, tree->species()->cnFoliage(), tree->species()->snagKyl());
270
    mLabileFlux.addBiomass(litter_foliage, tree->species()->cnFoliage(), tree->species()->snagKyl());
270
    mLabileFlux.addBiomass(litter_fineroot, tree->species()->cnFineroot(), tree->species()->snagKyl());
271
    mLabileFlux.addBiomass(litter_fineroot, tree->species()->cnFineroot(), tree->species()->snagKyl());
271
}
272
}
272
273
273
/// after the death of the tree the five biomass compartments are processed.
274
/// after the death of the tree the five biomass compartments are processed.
274
void Snag::addMortality(const Tree *tree)
275
void Snag::addMortality(const Tree *tree)
275
{
276
{
276
    const Species *species = tree->species();
277
    const Species *species = tree->species();
277
278
278
    // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
279
    // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
279
    mLabileFlux.addBiomass(tree->biomassFoliage(), species->cnFoliage(), tree->species()->snagKyl());
280
    mLabileFlux.addBiomass(tree->biomassFoliage(), species->cnFoliage(), tree->species()->snagKyl());
280
    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
281
    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
281
282
282
    // branches and coarse roots are equally distributed over five years:
283
    // branches and coarse roots are equally distributed over five years:
283
    double biomass_rest = (tree->biomassBranch()+tree->biomassCoarseRoot()) * 0.2;
284
    double biomass_rest = (tree->biomassBranch()+tree->biomassCoarseRoot()) * 0.2;
284
    for (int i=0;i<5; i++)
285
    for (int i=0;i<5; i++)
285
        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
286
        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
286
287
287
    // just for book-keeping: keep track of all inputs into branches / roots / swd
288
    // just for book-keeping: keep track of all inputs into branches / roots / swd
288
    mTotalIn.addBiomass(tree->biomassBranch() + tree->biomassCoarseRoot() + tree->biomassStem(), species->cnWood());
289
    mTotalIn.addBiomass(tree->biomassBranch() + tree->biomassCoarseRoot() + tree->biomassStem(), species->cnWood());
289
    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
290
    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
290
    int pi = poolIndex(tree->dbh()); // get right transfer pool
291
    int pi = poolIndex(tree->dbh()); // get right transfer pool
291
292
292
    // update statistics - stemnumber-weighted averages
293
    // update statistics - stemnumber-weighted averages
293
    // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
294
    // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
294
    double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers)
295
    double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers)
295
    double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1).
296
    double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1).
296
    mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new;
297
    mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new;
297
    mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new;
298
    mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new;
298
    mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new;
299
    mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new;
299
    mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new;
300
    mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new;
300
    mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new;
301
    mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new;
301
302
302
    // average the decay rate (ksw); this is done based on the carbon content
303
    // average the decay rate (ksw); this is done based on the carbon content
303
    // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
304
    // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
304
    if (tree->biomassStem()==0)
305
    if (tree->biomassStem()==0)
305
        throw IException("Snag::addMortality: tree without stem biomass!!");
306
        throw IException("Snag::addMortality: tree without stem biomass!!");
306
    p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
307
    p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
307
    p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
308
    p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
308
    mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new;
309
    mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new;
309
    mNumberOfSnags[pi]++;
310
    mNumberOfSnags[pi]++;
310
311
311
    // finally add the biomass
312
    // finally add the biomass
312
    CNPool &to_swd = mToSWD[pi];
313
    CNPool &to_swd = mToSWD[pi];
313
    to_swd.addBiomass(tree->biomassStem(), species->cnWood(), tree->species()->snagKyr());
314
    to_swd.addBiomass(tree->biomassStem(), species->cnWood(), tree->species()->snagKyr());
314
}
315
}
315
316
316
/// add residual biomass of 'tree' after harvesting.
317
/// add residual biomass of 'tree' after harvesting.
317
/// remove_{stem, branch, foliage}_fraction: percentage of biomass compartment that is *removed* by the harvest operation (i.e.: not to stay in the system)
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)
318
/// records on harvested biomass is collected (mTotalToExtern-pool).
319
/// records on harvested biomass is collected (mTotalToExtern-pool).
319
void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction )
320
void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction )
320
{
321
{
321
    const Species *species = tree->species();
322
    const Species *species = tree->species();
322
323
323
    // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
324
    // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
324
    mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), species->cnFoliage(), tree->species()->snagKyl());
325
    mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), species->cnFoliage(), tree->species()->snagKyl());
325
    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
326
    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
326
327
327
    // for branches, add all biomass that remains in the forest to the soil
328
    // for branches, add all biomass that remains in the forest to the soil
328
    mRefractoryFlux.addBiomass(tree->biomassBranch()*(1.-remove_branch_fraction), species->cnWood(), tree->species()->snagKyr());
329
    mRefractoryFlux.addBiomass(tree->biomassBranch()*(1.-remove_branch_fraction), species->cnWood(), tree->species()->snagKyr());
329
    // the same treatment for stem residuals
330
    // the same treatment for stem residuals
330
    mRefractoryFlux.addBiomass(tree->biomassStem() * remove_stem_fraction, species->cnWood(), tree->species()->snagKyr());
331
    mRefractoryFlux.addBiomass(tree->biomassStem() * remove_stem_fraction, species->cnWood(), tree->species()->snagKyr());
331
332
332
    // split the corase wood biomass into parts (slower decay)
333
    // split the corase wood biomass into parts (slower decay)
333
    double biomass_rest = (tree->biomassCoarseRoot()) * 0.2;
334
    double biomass_rest = (tree->biomassCoarseRoot()) * 0.2;
334
    for (int i=0;i<5; i++)
335
    for (int i=0;i<5; i++)
335
        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
336
        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
336
337
337
338
338
    // for book-keeping...
339
    // for book-keeping...
339
    mTotalToExtern.addBiomass(tree->biomassFoliage()*remove_foliage_fraction +
340
    mTotalToExtern.addBiomass(tree->biomassFoliage()*remove_foliage_fraction +
340
                              tree->biomassBranch()*remove_branch_fraction +
341
                              tree->biomassBranch()*remove_branch_fraction +
341
                              tree->biomassStem()*remove_stem_fraction, species->cnWood());
342
                              tree->biomassStem()*remove_stem_fraction, species->cnWood());
342
}
343
}
343
344
344
345
345
346
346
347
347
 
348