Subversion Repositories public iLand

Rev

Rev 540 | Rev 546 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 540 Rev 541
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
12
12
/** @class Snag
13
/** @class Snag
13
  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.
14
  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
15
  is subsequently forwarded to the soil sub model.
16
  is subsequently forwarded to the soil sub model.
16
  Carbon is stored in three classes (depending on the size)
17
  Carbon is stored in three classes (depending on the size)
17
  The Snag dynamics class uses the following species parameter:
18
  The Snag dynamics class uses the following species parameter:
18
  cnFoliage, cnFineroot, cnWood, snagHalflife, snagKSW
19
  cnFoliage, cnFineroot, cnWood, snagHalflife, snagKSW
19

20

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