Subversion Repositories public iLand

Rev

Rev 1157 | Rev 1202 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1
 
671 werner 2
/********************************************************************************************
3
**    iLand - an individual based forest landscape and disturbance model
4
**    http://iland.boku.ac.at
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
6
**
7
**    This program is free software: you can redistribute it and/or modify
8
**    it under the terms of the GNU General Public License as published by
9
**    the Free Software Foundation, either version 3 of the License, or
10
**    (at your option) any later version.
11
**
12
**    This program is distributed in the hope that it will be useful,
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
**    GNU General Public License for more details.
16
**
17
**    You should have received a copy of the GNU General Public License
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************************************/
20
 
468 werner 21
#include "snag.h"
22
#include "tree.h"
23
#include "species.h"
24
#include "globalsettings.h"
25
#include "expression.h"
490 werner 26
// for calculation of climate decomposition
27
#include "resourceunit.h"
28
#include "watercycle.h"
29
#include "climate.h"
541 werner 30
#include "model.h"
468 werner 31
 
32
/** @class Snag
697 werner 33
  @ingroup core
468 werner 34
  Snag deals with carbon / nitrogen fluxes from the forest until the reach soil pools.
490 werner 35
  Snag lives on the level of the ResourceUnit; carbon fluxes from trees enter Snag, and parts of the biomass of snags
468 werner 36
  is subsequently forwarded to the soil sub model.
522 werner 37
  Carbon is stored in three classes (depending on the size)
528 werner 38
  The Snag dynamics class uses the following species parameter:
39
  cnFoliage, cnFineroot, cnWood, snagHalflife, snagKSW
468 werner 40
 
41
  */
42
// static variables
528 werner 43
double Snag::mDBHLower = -1.;
522 werner 44
double Snag::mDBHHigher = 0.;
45
double Snag::mCarbonThreshold[] = {0., 0., 0.};
46
 
534 werner 47
double CNPair::biomassCFraction = biomassCFraction; // get global from globalsettings.h
468 werner 48
 
534 werner 49
/// add biomass and weigh the parameter_value with the current C-content of the pool
50
void CNPool::addBiomass(const double biomass, const double CNratio, const double parameter_value)
51
{
52
    if (biomass==0.)
53
        return;
54
    double new_c = biomass*biomassCFraction;
55
    double p_old = C / (new_c + C);
56
    mParameter = mParameter*p_old + parameter_value*(1.-p_old);
57
    CNPair::addBiomass(biomass, CNratio);
58
}
59
 
60
// increase pool (and weigh the value)
61
void CNPool::operator+=(const CNPool &s)
62
{
63
    if (s.C==0.)
64
        return;
65
    mParameter = parameter(s); // calculate weighted parameter
66
    C+=s.C;
67
    N+=s.N;
68
}
69
 
70
double CNPool::parameter(const CNPool &s) const
71
{
72
    if (s.C==0.)
73
        return parameter();
74
    double p_old = C / (s.C + C);
75
    double result =  mParameter*p_old + s.parameter()*(1.-p_old);
76
    return result;
77
}
78
 
79
 
522 werner 80
void Snag::setupThresholds(const double lower, const double upper)
81
{
82
    if (mDBHLower == lower)
83
        return;
84
    mDBHLower = lower;
85
    mDBHHigher = upper;
86
    mCarbonThreshold[0] = lower / 2.;
87
    mCarbonThreshold[1] = lower + (upper - lower)/2.;
88
    mCarbonThreshold[2] = upper + (upper - lower)/2.;
89
    //# threshold levels for emptying out the dbh-snag-classes
90
    //# derived from Psme woody allometry, converted to C, with a threshold level set to 10%
91
    //# values in kg!
92
    for (int i=0;i<3;i++)
93
        mCarbonThreshold[i] = 0.10568*pow(mCarbonThreshold[i],2.4247)*0.5*0.1;
94
}
95
 
96
 
468 werner 97
Snag::Snag()
98
{
490 werner 99
    mRU = 0;
534 werner 100
    CNPair::setCFraction(biomassCFraction);
468 werner 101
}
102
 
490 werner 103
void Snag::setup( const ResourceUnit *ru)
468 werner 104
{
490 werner 105
    mRU = ru;
106
    mClimateFactor = 0.;
468 werner 107
    // branches
108
    mBranchCounter=0;
109
    for (int i=0;i<3;i++) {
110
        mTimeSinceDeath[i] = 0.;
111
        mNumberOfSnags[i] = 0.;
522 werner 112
        mAvgDbh[i] = 0.;
113
        mAvgHeight[i] = 0.;
114
        mAvgVolume[i] = 0.;
115
        mKSW[i] = 0.;
116
        mCurrentKSW[i] = 0.;
557 werner 117
        mHalfLife[i] = 0.;
468 werner 118
    }
475 werner 119
    mTotalSnagCarbon = 0.;
528 werner 120
    if (mDBHLower<=0)
121
        throw IException("Snag::setupThresholds() not called or called with invalid parameters.");
557 werner 122
 
123
    // Inital values from XML file
124
    XmlHelper xml=GlobalSettings::instance()->settings();
574 werner 125
    double kyr = xml.valueDouble("model.site.youngRefractoryDecompRate", -1);
557 werner 126
    // put carbon of snags to the middle size class
127
    xml.setCurrentNode("model.initialization.snags");
128
    mSWD[1].C = xml.valueDouble(".swdC");
129
    mSWD[1].N = mSWD[1].C / xml.valueDouble(".swdCN", 50.);
130
    mSWD[1].setParameter(kyr);
131
    mKSW[1] = xml.valueDouble(".swdDecompRate");
132
    mNumberOfSnags[1] = xml.valueDouble(".swdCount");
133
    mHalfLife[1] = xml.valueDouble(".swdHalfLife");
134
    // and for the Branch/coarse root pools: split the init value into five chunks
135
    CNPool other(xml.valueDouble(".otherC"), xml.valueDouble(".otherC")/xml.valueDouble(".otherCN", 50.), kyr );
136
 
137
    mTotalSnagCarbon = other.C + mSWD[1].C;
138
 
139
    other *= 0.2;
140
    for (int i=0;i<5;i++)
141
        mOtherWood[i] = other;
468 werner 142
}
143
 
1157 werner 144
void Snag::scaleInitialState()
145
{
146
    double area_factor = mRU->stockableArea() / cRUArea; // fraction stockable area
147
    // avoid huge snag pools on very small resource units (see also soil.cpp)
148
    // area_factor = std::max(area_factor, 0.1);
149
    mSWD[1] *= area_factor;
150
    mNumberOfSnags[1] *= area_factor;
151
    for (int i=0;i<5;i++)
152
        mOtherWood[i]*= area_factor;
153
    mTotalSnagCarbon *= area_factor;
154
 
155
}
156
 
475 werner 157
// debug outputs
158
QList<QVariant> Snag::debugList()
159
{
160
    // list columns
161
    // for three pools
162
    QList<QVariant> list;
163
 
523 werner 164
    // totals
165
    list << mTotalSnagCarbon << mTotalIn.C << mTotalToAtm.C << mSWDtoSoil.C << mSWDtoSoil.N;
477 werner 166
    // fluxes to labile soil pool and to refractory soil pool
524 werner 167
    list << mLabileFlux.C << mLabileFlux.N << mRefractoryFlux.C << mRefractoryFlux.N;
475 werner 168
 
169
    for (int i=0;i<3;i++) {
170
        // pools "swdx_c", "swdx_n", "swdx_count", "swdx_tsd", "toswdx_c", "toswdx_n"
171
        list << mSWD[i].C << mSWD[i].N << mNumberOfSnags[i] << mTimeSinceDeath[i] << mToSWD[i].C << mToSWD[i].N;
524 werner 172
        list << mAvgDbh[i] << mAvgHeight[i] << mAvgVolume[i];
475 werner 173
    }
174
 
540 werner 175
    // branch/coarse wood pools (5 yrs)
176
    for (int i=0;i<5;i++) {
177
        list << mOtherWood[i].C << mOtherWood[i].N;
178
    }
179
//    list << mOtherWood[mBranchCounter].C << mOtherWood[mBranchCounter].N
180
//            << mOtherWood[(mBranchCounter+1)%5].C << mOtherWood[(mBranchCounter+1)%5].N
181
//            << mOtherWood[(mBranchCounter+2)%5].C << mOtherWood[(mBranchCounter+2)%5].N
182
//            << mOtherWood[(mBranchCounter+3)%5].C << mOtherWood[(mBranchCounter+3)%5].N
183
//            << mOtherWood[(mBranchCounter+4)%5].C << mOtherWood[(mBranchCounter+4)%5].N;
475 werner 184
    return list;
185
}
186
 
713 werner 187
 
468 werner 188
void Snag::newYear()
189
{
190
    for (int i=0;i<3;i++) {
191
        mToSWD[i].clear(); // clear transfer pools to standing-woody-debris
522 werner 192
        mCurrentKSW[i] = 0.;
468 werner 193
    }
194
    mLabileFlux.clear();
195
    mRefractoryFlux.clear();
476 werner 196
    mTotalToAtm.clear();
197
    mTotalToExtern.clear();
609 werner 198
    mTotalToDisturbance.clear();
476 werner 199
    mTotalIn.clear();
477 werner 200
    mSWDtoSoil.clear();
468 werner 201
}
202
 
490 werner 203
/// calculate the dynamic climate modifier for decomposition 're'
522 werner 204
/// calculation is done on the level of ResourceUnit because the water content per day is needed.
490 werner 205
double Snag::calculateClimateFactors()
206
{
770 werner 207
    // the calculation of climate factors requires calculated evapotranspiration. In cases without vegetation (trees or saplings)
208
    // we have to trigger the water cycle calculation for ourselves [ the waterCycle checks if it has already been run in a year and doesn't run twice in that case ]
209
    const_cast<WaterCycle*>(mRU->waterCycle())->run();
490 werner 210
    double ft, fw;
211
    double f_sum = 0.;
552 werner 212
    int iday=0;
553 werner 213
    // calculate the water-factor for each month (see Adair et al 2008)
214
    double fw_month[12];
215
    double ratio;
216
    for (int m=0;m<12;m++) {
562 werner 217
        if (mRU->waterCycle()->referenceEvapotranspiration()[m]>0.)
218
            ratio = mRU->climate()->precipitationMonth()[m] /  mRU->waterCycle()->referenceEvapotranspiration()[m];
553 werner 219
        else
220
            ratio = 0;
221
        fw_month[m] = 1. / (1. + 30.*exp(-8.5*ratio));
564 werner 222
        if (logLevelDebug()) qDebug() <<"month"<< m << "PET" << mRU->waterCycle()->referenceEvapotranspiration()[m] << "prec" <<mRU->climate()->precipitationMonth()[m];
553 werner 223
    }
224
 
552 werner 225
    for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day, ++iday)
490 werner 226
    {
227
        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)
553 werner 228
        fw = fw_month[day->month-1];
540 werner 229
 
490 werner 230
        f_sum += ft*fw;
231
    }
232
    // the climate factor is defined as the arithmentic annual mean value
233
    mClimateFactor = f_sum / double(mRU->climate()->daysOfYear());
234
    return mClimateFactor;
235
}
236
 
522 werner 237
/// do the yearly calculation
238
/// see http://iland.boku.ac.at/snag+dynamics
526 werner 239
void Snag::calculateYear()
468 werner 240
{
522 werner 241
    mSWDtoSoil.clear();
925 werner 242
 
243
    // calculate anyway, because also the soil module needs it (and currently one can have Snag and Soil only as a couple)
244
    calculateClimateFactors();
245
    const double climate_factor_re = mClimateFactor;
246
 
477 werner 247
    if (isEmpty()) // nothing to do
475 werner 248
        return;
249
 
468 werner 250
    // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
540 werner 251
    mRefractoryFlux+=mOtherWood[mBranchCounter];
252
 
253
    mOtherWood[mBranchCounter].clear();
468 werner 254
    mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0.
540 werner 255
    // decay of branches/coarse roots
256
    for (int i=0;i<5;i++) {
257
        if (mOtherWood[i].C>0.) {
258
            double survive_rate = exp(- climate_factor_re * mOtherWood[i].parameter() ); // parameter: the "kyr" value...
259
            mOtherWood[i].C *= survive_rate;
260
        }
261
    }
468 werner 262
 
263
    // process standing snags.
264
    // the input of the current year is in the mToSWD-Pools
265
    for (int i=0;i<3;i++) {
266
 
522 werner 267
        // update the swd-pool with this years' input
268
        if (!mToSWD[i].isEmpty()) {
269
            // update decay rate (apply average yearly input to the state parameters)
270
            mKSW[i] = mKSW[i]*(mSWD[i].C/(mSWD[i].C+mToSWD[i].C)) + mCurrentKSW[i]*(mToSWD[i].C/(mSWD[i].C+mToSWD[i].C));
271
            //move content to the SWD pool
272
            mSWD[i] += mToSWD[i];
273
        }
475 werner 274
 
522 werner 275
        if (mSWD[i].C > 0) {
276
            // reduce the Carbon (note: the N stays, thus the CN ratio changes)
277
            // use the decay rate that is derived as a weighted average of all standing woody debris
523 werner 278
            double survive_rate = exp(-mKSW[i] *climate_factor_re * 1. ); // 1: timestep
279
            mTotalToAtm.C += mSWD[i].C * (1. - survive_rate);
280
            mSWD[i].C *= survive_rate;
468 werner 281
 
522 werner 282
            // transition to downed woody debris
283
            // update: use negative exponential decay, species parameter: half-life
284
            // modified for the climatic effect on decomposition, i.e. if decomp is slower, snags stand longer and vice versa
285
            // this is loosely oriented on Standcarb2 (http://andrewsforest.oregonstate.edu/pubs/webdocs/models/standcarb2.htm),
286
            // where lag times for cohort transitions are linearly modified with re although here individual good or bad years have
287
            // an immediate effect, the average climatic influence should come through (and it is inherently transient)
288
            // note that swd.hl is species-specific, and thus a weighted average over the species in the input (=mortality)
289
            // needs to be calculated, followed by a weighted update of the previous swd.hl.
290
            // As weights here we use stem number, as the processes here pertain individual snags
291
            // calculate the transition probability of SWD to downed dead wood
468 werner 292
 
522 werner 293
            double half_life = mHalfLife[i] / climate_factor_re;
294
            double rate = -M_LN2 / half_life; // M_LN2: math. constant
295
 
296
            // higher decay rate for the class with smallest diameters
297
            if (i==0)
298
                rate*=2.;
299
 
523 werner 300
            double transfer = 1. - exp(rate);
522 werner 301
 
468 werner 302
            // calculate flow to soil pool...
522 werner 303
            mSWDtoSoil += mSWD[i] * transfer;
304
            mRefractoryFlux += mSWD[i] * transfer;
305
            mSWD[i] *= (1.-transfer); // reduce pool
468 werner 306
            // calculate the stem number of remaining snags
522 werner 307
            mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - transfer);
523 werner 308
 
309
            mTimeSinceDeath[i] += 1.;
522 werner 310
            // if stems<0.5, empty the whole cohort into DWD, i.e. release the last bit of C and N and clear the stats
311
            // also, if the Carbon of an average snag is less than 10% of the original average tree
312
            // (derived from allometries for the three diameter classes), the whole cohort is emptied out to DWD
313
            if (mNumberOfSnags[i] < 0.5 || mSWD[i].C / mNumberOfSnags[i] < mCarbonThreshold[i]) {
314
                // clear the pool: add the rest to the soil, clear statistics of the pool
468 werner 315
                mRefractoryFlux += mSWD[i];
522 werner 316
                mSWDtoSoil += mSWD[i];
468 werner 317
                mSWD[i].clear();
522 werner 318
                mAvgDbh[i] = 0.;
319
                mAvgHeight[i] = 0.;
320
                mAvgVolume[i] = 0.;
321
                mKSW[i] = 0.;
322
                mCurrentKSW[i] = 0.;
323
                mHalfLife[i] = 0.;
324
                mTimeSinceDeath[i] = 0.;
468 werner 325
            }
522 werner 326
 
468 werner 327
        }
522 werner 328
 
468 werner 329
    }
522 werner 330
    // total carbon in the snag-container on the RU *after* processing is the content of the
475 werner 331
    // standing woody debris pools + the branches
332
    mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C +
540 werner 333
                       mOtherWood[0].C + mOtherWood[1].C + mOtherWood[2].C + mOtherWood[3].C + mOtherWood[4].C;
587 werner 334
    mTotalSWD = mSWD[0] + mSWD[1] + mSWD[2];
335
    mTotalOther = mOtherWood[0] + mOtherWood[1] + mOtherWood[2] + mOtherWood[3] + mOtherWood[4];
468 werner 336
}
337
 
338
/// foliage and fineroot litter is transferred during tree growth.
588 werner 339
void Snag::addTurnoverLitter(const Species *species, const double litter_foliage, const double litter_fineroot)
468 werner 340
{
588 werner 341
    mLabileFlux.addBiomass(litter_foliage, species->cnFoliage(), species->snagKyl());
342
    mLabileFlux.addBiomass(litter_fineroot, species->cnFineroot(), species->snagKyl());
1160 werner 343
    DBGMODE(
344
    if (isnan(mLabileFlux.C))
345
        qDebug("Snag::addTurnoverLitter: NaN");
346
                );
468 werner 347
}
348
 
595 werner 349
void Snag::addTurnoverWood(const Species *species, const double woody_biomass)
350
{
351
    mRefractoryFlux.addBiomass(woody_biomass, species->cnWood(), species->snagKyr());
1160 werner 352
    DBGMODE(
353
    if (isnan(mRefractoryFlux.C))
354
        qDebug("Snag::addTurnoverWood: NaN");
355
                );
356
 
595 werner 357
}
358
 
713 werner 359
 
360
/** process the remnants of a single tree.
361
    The part of the stem / branch not covered by snag/soil fraction is removed from the system (e.g. harvest, fire)
362
  @param tree the tree to process
363
  @param stem_to_snag fraction (0..1) of the stem biomass that should be moved to a standing snag
364
  @param stem_to_soil fraction (0..1) of the stem biomass that should go directly to the soil
365
  @param branch_to_snag fraction (0..1) of the branch biomass that should be moved to a standing snag
366
  @param branch_to_soil fraction (0..1) of the branch biomass that should go directly to the soil
367
  @param foliage_to_soil fraction (0..1) of the foliage biomass that should go directly to the soil
368
 
369
*/
370
void Snag::addBiomassPools(const Tree *tree,
371
                           const double stem_to_snag, const double stem_to_soil,
372
                           const double branch_to_snag, const double branch_to_soil,
373
                           const double foliage_to_soil)
468 werner 374
{
528 werner 375
    const Species *species = tree->species();
468 werner 376
 
713 werner 377
    double branch_biomass = tree->biomassBranch();
378
    // fine roots go to the labile pool
379
    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), species->snagKyl());
468 werner 380
 
713 werner 381
    // a part of the foliage goes to the soil
382
    mLabileFlux.addBiomass(tree->biomassFoliage() * foliage_to_soil, species->cnFoliage(), species->snagKyl());
383
 
384
    //coarse roots and a part of branches are equally distributed over five years:
385
    double biomass_rest = (tree->biomassCoarseRoot() + branch_to_snag*branch_biomass) * 0.2;
468 werner 386
    for (int i=0;i<5; i++)
713 werner 387
        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), species->snagKyr());
468 werner 388
 
713 werner 389
    // the other part of the branches goes directly to the soil
390
    mRefractoryFlux.addBiomass(branch_biomass*branch_to_soil, species->cnWood(), species->snagKyr() );
391
    // a part of the stem wood goes directly to the soil
392
    mRefractoryFlux.addBiomass(tree->biomassStem()*stem_to_soil, species->cnWood(), species->snagKyr() );
393
 
394
    // just for book-keeping: keep track of all inputs of branches / roots / swd into the "snag" pools
395
    mTotalIn.addBiomass(tree->biomassBranch()*branch_to_snag + tree->biomassCoarseRoot() + tree->biomassStem()*stem_to_snag, species->cnWood());
468 werner 396
    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
522 werner 397
    int pi = poolIndex(tree->dbh()); // get right transfer pool
398
 
713 werner 399
    if (stem_to_snag>0.) {
400
        // update statistics - stemnumber-weighted averages
401
        // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
402
        double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers)
403
        double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1).
404
        mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new;
405
        mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new;
406
        mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new;
407
        mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new;
408
        mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new;
522 werner 409
 
713 werner 410
        // average the decay rate (ksw); this is done based on the carbon content
411
        // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
412
        p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
413
        p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
414
        mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new;
415
        mNumberOfSnags[pi]++;
416
    }
523 werner 417
 
713 werner 418
    // finally add the biomass of the stem to the standing snag pool
534 werner 419
    CNPool &to_swd = mToSWD[pi];
713 werner 420
    to_swd.addBiomass(tree->biomassStem()*stem_to_snag, species->cnWood(), species->snagKyr());
421
 
422
    // the biomass that is not routed to snags or directly to the soil
423
    // is removed from the system (to atmosphere or harvested)
424
    mTotalToExtern.addBiomass(tree->biomassFoliage()* (1. - foliage_to_soil) +
425
                              branch_biomass*(1. - branch_to_snag - branch_to_soil) +
426
                              tree->biomassStem()*(1. - stem_to_snag - stem_to_soil), species->cnWood());
427
 
468 werner 428
}
429
 
713 werner 430
 
431
/// after the death of the tree the five biomass compartments are processed.
432
void Snag::addMortality(const Tree *tree)
433
{
434
    addBiomassPools(tree, 1., 0.,  // all stem biomass goes to snag
435
                    1., 0.,        // all branch biomass to snag
436
                    1.);           // all foliage to soil
437
 
438
//    const Species *species = tree->species();
439
 
440
//    // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
441
//    mLabileFlux.addBiomass(tree->biomassFoliage(), species->cnFoliage(), tree->species()->snagKyl());
442
//    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
443
 
444
//    // branches and coarse roots are equally distributed over five years:
445
//    double biomass_rest = (tree->biomassBranch()+tree->biomassCoarseRoot()) * 0.2;
446
//    for (int i=0;i<5; i++)
447
//        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
448
 
449
//    // just for book-keeping: keep track of all inputs into branches / roots / swd
450
//    mTotalIn.addBiomass(tree->biomassBranch() + tree->biomassCoarseRoot() + tree->biomassStem(), species->cnWood());
451
//    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
452
//    int pi = poolIndex(tree->dbh()); // get right transfer pool
453
 
454
//    // update statistics - stemnumber-weighted averages
455
//    // note: here the calculations are repeated for every died trees (i.e. consecutive weighting ... but delivers the same results)
456
//    double p_old = mNumberOfSnags[pi] / (mNumberOfSnags[pi] + 1); // weighting factor for state vars (based on stem numbers)
457
//    double p_new = 1. / (mNumberOfSnags[pi] + 1); // weighting factor for added tree (p_old + p_new = 1).
458
//    mAvgDbh[pi] = mAvgDbh[pi]*p_old + tree->dbh()*p_new;
459
//    mAvgHeight[pi] = mAvgHeight[pi]*p_old + tree->height()*p_new;
460
//    mAvgVolume[pi] = mAvgVolume[pi]*p_old + tree->volume()*p_new;
461
//    mTimeSinceDeath[pi] = mTimeSinceDeath[pi]*p_old + 1.*p_new;
462
//    mHalfLife[pi] = mHalfLife[pi]*p_old + species->snagHalflife()* p_new;
463
 
464
//    // average the decay rate (ksw); this is done based on the carbon content
465
//    // aggregate all trees that die in the current year (and save weighted decay rates to CurrentKSW)
466
//    if (tree->biomassStem()==0)
467
//        throw IException("Snag::addMortality: tree without stem biomass!!");
468
//    p_old = mToSWD[pi].C / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
469
//    p_new =tree->biomassStem()* biomassCFraction / (mToSWD[pi].C + tree->biomassStem()* biomassCFraction);
470
//    mCurrentKSW[pi] = mCurrentKSW[pi]*p_old + species->snagKsw() * p_new;
471
//    mNumberOfSnags[pi]++;
472
 
473
//    // finally add the biomass
474
//    CNPool &to_swd = mToSWD[pi];
475
//    to_swd.addBiomass(tree->biomassStem(), species->cnWood(), tree->species()->snagKyr());
476
}
477
 
468 werner 478
/// add residual biomass of 'tree' after harvesting.
1088 werner 479
/// remove_{stem, branch, foliage}_fraction: percentage of biomass compartment that is *removed* by the harvest operation [0..1] (i.e.: not to stay in the system)
528 werner 480
/// records on harvested biomass is collected (mTotalToExtern-pool).
468 werner 481
void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction )
482
{
713 werner 483
    addBiomassPools(tree,
484
                    0., 1.-remove_stem_fraction, // "remove_stem_fraction" is removed -> the rest goes to soil
485
                    0., 1.-remove_branch_fraction, // "remove_branch_fraction" is removed -> the rest goes directly to the soil
486
                    1.-remove_foliage_fraction); // the rest of foliage is routed to the soil
487
//    const Species *species = tree->species();
468 werner 488
 
713 werner 489
//    // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
490
//    mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), species->cnFoliage(), tree->species()->snagKyl());
491
//    mLabileFlux.addBiomass(tree->biomassFineRoot(), species->cnFineroot(), tree->species()->snagKyl());
540 werner 492
 
713 werner 493
//    // for branches, add all biomass that remains in the forest to the soil
494
//    mRefractoryFlux.addBiomass(tree->biomassBranch()*(1.-remove_branch_fraction), species->cnWood(), tree->species()->snagKyr());
495
//    // the same treatment for stem residuals
496
//    mRefractoryFlux.addBiomass(tree->biomassStem() * (1. - remove_stem_fraction), species->cnWood(), tree->species()->snagKyr());
468 werner 497
 
713 werner 498
//    // split the corase wood biomass into parts (slower decay)
499
//    double biomass_rest = (tree->biomassCoarseRoot()) * 0.2;
500
//    for (int i=0;i<5; i++)
501
//        mOtherWood[i].addBiomass(biomass_rest, species->cnWood(), tree->species()->snagKyr());
540 werner 502
 
503
 
713 werner 504
//    // for book-keeping...
505
//    mTotalToExtern.addBiomass(tree->biomassFoliage()*remove_foliage_fraction +
506
//                              tree->biomassBranch()*remove_branch_fraction +
507
//                              tree->biomassStem()*remove_stem_fraction, species->cnWood());
468 werner 508
}
509
 
588 werner 510
// add flow from regeneration layer (dead trees) to soil
595 werner 511
void Snag::addToSoil(const Species *species, const CNPair &woody_pool, const CNPair &litter_pool)
588 werner 512
{
513
    mLabileFlux.add(litter_pool, species->snagKyl());
514
    mRefractoryFlux.add(woody_pool, species->snagKyr());
1160 werner 515
    DBGMODE(
516
    if (isnan(mLabileFlux.C) || isnan(mRefractoryFlux.C))
517
        qDebug("Snag::addToSoil: NaN in C Pool");
518
    );
588 werner 519
}
534 werner 520
 
607 werner 521
/// disturbance function: remove the fraction of 'factor' of biomass from the SWD pools; 0: remove nothing, 1: remove all
522
/// biomass removed by this function goes to the atmosphere
523
void Snag::removeCarbon(const double factor)
524
{
525
    // reduce pools of currently standing dead wood and also of pools that are added
526
    // during (previous) management operations of the current year
527
    for (int i=0;i<3;i++) {
609 werner 528
        mTotalToDisturbance += (mSWD[i] + mToSWD[i]) * factor;
607 werner 529
        mSWD[i] *= (1. - factor);
530
        mToSWD[i] *= (1. - factor);
531
    }
534 werner 532
 
607 werner 533
    for (int i=0;i<5;i++) {
609 werner 534
        mTotalToDisturbance += mOtherWood[i]*factor;
607 werner 535
        mOtherWood[i] *= (1. - factor);
536
    }
537
}
538
 
539
 
540
/// cut down swd (and branches) and move to soil pools
541
/// @param factor 0: cut 0%, 1: cut and slash 100% of the wood
542
void Snag::management(const double factor)
543
{
544
    if (factor<0. || factor>1.)
545
        throw IException(QString("Invalid factor in Snag::management: '%1'").arg(factor));
546
    // swd pools
547
    for (int i=0;i<3;i++) {
548
        mSWDtoSoil += mSWD[i] * factor;
549
        mSWD[i] *= (1. - factor);
550
        mSWDtoSoil += mToSWD[i] * factor;
551
        mToSWD[i] *= (1. - factor);
552
    }
553
    // what to do with the branches: now move also all wood to soil (note: this is note
554
    // very good w.r.t the coarse roots...
555
    for (int i=0;i<5;i++) {
556
        mRefractoryFlux+=mOtherWood[i]*factor;
557
        mOtherWood[i]*=(1. - factor);
558
    }
559
 
560
}
561
 
562