Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
1
 
468 werner 2
#include "snag.h"
3
#include "tree.h"
4
#include "species.h"
5
#include "globalsettings.h"
6
#include "expression.h"
490 werner 7
// for calculation of climate decomposition
8
#include "resourceunit.h"
9
#include "watercycle.h"
10
#include "climate.h"
468 werner 11
 
12
/** @class Snag
13
  Snag deals with carbon / nitrogen fluxes from the forest until the reach soil pools.
490 werner 14
  Snag lives on the level of the ResourceUnit; carbon fluxes from trees enter Snag, and parts of the biomass of snags
468 werner 15
  is subsequently forwarded to the soil sub model.
16
 
17
  */
18
// static variables
19
double Snag::mDBHLower = 10.;
20
double Snag::mDBHHigher = 30.;
21
double CNPool::biomassCFraction = biomassCFraction; // get global from globalsettings.h
22
 
23
// species specific soil paramters
24
struct SoilParameters
25
{
26
    SoilParameters(): kyl(0.15), kyr(0.0807), ksw(0.015), cnFoliage(75.), cnFineroot(40.), cnWood(300.) {}
27
    double kyl; // litter decomposition rate
28
    double kyr; // downed woody debris (dwd) decomposition rate
29
    double ksw; // standing woody debris (swd) decomposition rate
30
    double cnFoliage; //  C/N foliage litter
31
    double cnFineroot; // C/N ratio fine root
32
    double cnWood; // C/N Wood: used for brances, stem and coarse root
33
    Expression pDWDformula; // expression that calculates annual transition probability for standing to downed deadwood. variable: 'tsd' (time since death)
34
} soilparams;
35
 
36
 
37
Snag::Snag()
38
{
490 werner 39
    mRU = 0;
468 werner 40
    soilparams.pDWDformula.setExpression("1-1/(1+exp(-6.78+0.262*tsd))");
476 werner 41
    CNPool::setCFraction(biomassCFraction);
468 werner 42
}
43
 
490 werner 44
void Snag::setup( const ResourceUnit *ru)
468 werner 45
{
490 werner 46
    mRU = ru;
47
    mClimateFactor = 0.;
468 werner 48
    // branches
49
    mBranchCounter=0;
50
    for (int i=0;i<3;i++) {
51
        mTimeSinceDeath[i] = 0.;
52
        mNumberOfSnags[i] = 0.;
53
    }
475 werner 54
    mTotalSnagCarbon = 0.;
468 werner 55
}
56
 
475 werner 57
// debug outputs
58
QList<QVariant> Snag::debugList()
59
{
60
    // list columns
61
    // for three pools
62
    QList<QVariant> list;
63
 
64
    list << mTotalSnagCarbon;
477 werner 65
    // fluxes to labile soil pool and to refractory soil pool
66
    list << mLabileFlux.C << mLabileFlux.N << mRefractoryFlux.C << mRefractoryFlux.N << mSWDtoSoil.C << mSWDtoSoil.N;
475 werner 67
 
68
    for (int i=0;i<3;i++) {
69
        // pools "swdx_c", "swdx_n", "swdx_count", "swdx_tsd", "toswdx_c", "toswdx_n"
70
        list << mSWD[i].C << mSWD[i].N << mNumberOfSnags[i] << mTimeSinceDeath[i] << mToSWD[i].C << mToSWD[i].N;
71
    }
72
 
73
 
74
    // branch pools (5 yrs)
75
    list << mBranches[mBranchCounter].C << mBranches[mBranchCounter].N
76
            << mBranches[(mBranchCounter+1)%5].C << mBranches[(mBranchCounter+1)%5].N
77
            << mBranches[(mBranchCounter+2)%5].C << mBranches[(mBranchCounter+2)%5].N
78
            << mBranches[(mBranchCounter+3)%5].C << mBranches[(mBranchCounter+3)%5].N
79
            << mBranches[(mBranchCounter+4)%5].C << mBranches[(mBranchCounter+4)%5].N;
80
    return list;
81
}
82
 
468 werner 83
void Snag::newYear()
84
{
85
    for (int i=0;i<3;i++) {
86
        mToSWD[i].clear(); // clear transfer pools to standing-woody-debris
87
    }
88
    mLabileFlux.clear();
89
    mRefractoryFlux.clear();
476 werner 90
    mTotalToAtm.clear();
91
    mTotalToExtern.clear();
92
    mTotalIn.clear();
477 werner 93
    mSWDtoSoil.clear();
468 werner 94
}
95
 
490 werner 96
/// calculate the dynamic climate modifier for decomposition 're'
97
double Snag::calculateClimateFactors()
98
{
99
    double rel_wc;
100
    double ft, fw;
101
    double f_sum = 0.;
102
    for (const ClimateDay *day=mRU->climate()->begin(); day!=mRU->climate()->end(); ++day)
103
    {
104
        rel_wc = mRU->waterCycle()->relContent(day->day); // relative water content (0..1) of the day
105
        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)
106
        fw = pow(1.-exp(-0.2*rel_wc),5.); //  #  see Standcarb for the 'stable soil' pool
107
        f_sum += ft*fw;
108
    }
109
    // the climate factor is defined as the arithmentic annual mean value
110
    mClimateFactor = f_sum / double(mRU->climate()->daysOfYear());
111
    return mClimateFactor;
112
}
113
 
468 werner 114
// do the yearly calculation
115
// see http://iland.boku.ac.at/snag+dynamics
116
void Snag::processYear()
117
{
477 werner 118
    if (isEmpty()) // nothing to do
475 werner 119
        return;
120
 
468 werner 121
    const SoilParameters &soil_params = soilparams; // to be updated
122
 
123
    // process branches: every year one of the five baskets is emptied and transfered to the refractory soil pool
124
    mRefractoryFlux+=mBranches[mBranchCounter];
125
    mBranches[mBranchCounter].clear();
126
    mBranchCounter= (mBranchCounter+1) % 5; // increase index, roll over to 0.
127
 
477 werner 128
    mSWDtoSoil.clear();
468 werner 129
    // process standing snags.
130
    // the input of the current year is in the mToSWD-Pools
131
    double tsd;
490 werner 132
    const double climate_factor_re = calculateClimateFactors();
468 werner 133
    for (int i=0;i<3;i++) {
134
        // calculate 'tsd', i.e. time-since-death (see SnagDecay.xls for calculation details)
135
        // time_since_death = tsd_last_year*state_before / (state_before+input) + 1
136
        if (mSWD[i].C>0.)
137
            tsd = mTimeSinceDeath[i]*mSWD[i].C / (mSWD[i].C+mToSWD[i].C) + 1.;
138
        else
139
            tsd = 0.;
140
 
475 werner 141
        // update the swd-pool: move content to the SWD pool
468 werner 142
        mSWD[i] += mToSWD[i];
475 werner 143
 
468 werner 144
        mTimeSinceDeath[i] = tsd;
145
 
146
        if (mSWD[i].C>0.) {
147
            // calculate decay of SWD.
148
            // Eq. (1): mass (C) is lost, N remains unchanged.
149
            double factor = exp(-soil_params.ksw * climate_factor_re * 1.);
150
            mSWD[i].C *= factor;
151
 
152
            // calculate the transition probability of SWD to downed dead wood
153
            double pDWD = soil_params.pDWDformula.calculate(tsd);
154
            pDWD = limit( pDWD * climate_factor_re, 0., 1.); //  modified transition rate with climate decomp factor
155
            // calculate flow to soil pool...
477 werner 156
            mSWDtoSoil += mSWD[i] * pDWD;
468 werner 157
            mRefractoryFlux += mSWD[i] * pDWD;
158
            mSWD[i] *= (1.-pDWD); // reduce pool
159
            // calculate the stem number of remaining snags
160
            mNumberOfSnags[i] = mNumberOfSnags[i] * (1. - pDWD);
161
            if (mNumberOfSnags[i] < 0.5) {
162
                // clear the pool: add the rest to the soil
163
                mRefractoryFlux += mSWD[i];
164
                mSWD[i].clear();
165
            }
166
        }
167
    }
475 werner 168
    // total carbon in the snag *after* processing is the content of the
169
    // standing woody debris pools + the branches
170
    mTotalSnagCarbon = mSWD[0].C + mSWD[1].C + mSWD[2].C +
171
                       mBranches[0].C + mBranches[1].C + mBranches[2].C + mBranches[3].C + mBranches[4].C;
468 werner 172
}
173
 
174
/// foliage and fineroot litter is transferred during tree growth.
175
void Snag::addTurnoverLitter(const Tree *tree, const double litter_foliage, const double litter_fineroot)
176
{
177
    const SoilParameters &soil_params = soilparams; // to be updated
178
    mLabileFlux.addBiomass(litter_foliage, soil_params.cnFoliage);
179
    mLabileFlux.addBiomass(litter_fineroot, soil_params.cnFineroot);
180
}
181
 
182
/// after the death of the tree the five biomass compartments are processed.
183
void Snag::addMortality(const Tree *tree)
184
{
185
    const SoilParameters &soil_params = soilparams; // to be updated
186
 
187
    // immediate flows: 100% of foliage, 100% of fine roots: they go to the labile pool
188
    // 100% of coarse root biomass: that goes to the refractory pool
189
    mLabileFlux.addBiomass(tree->biomassFoliage(), soil_params.cnFoliage);
190
    mLabileFlux.addBiomass(tree->biomassFineRoot(), soil_params.cnFineroot);
191
    mRefractoryFlux.addBiomass(tree->biomassCoarseRoot(), soil_params.cnWood);
192
 
193
    // branches are equally distributed over five years:
477 werner 194
    double biomass_branch = tree->biomassBranch() * 0.2;
468 werner 195
    for (int i=0;i<5; i++)
477 werner 196
        mBranches[i].addBiomass(biomass_branch, soil_params.cnWood);
468 werner 197
 
198
    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
199
    CNPool &swd = mToSWD[poolIndex(tree->dbh())]; // get right transfer pool
200
    swd.addBiomass(tree->biomassStem(), soil_params.cnWood);
201
    mNumberOfSnags[poolIndex(tree->dbh())]++;
202
}
203
 
204
/// add residual biomass of 'tree' after harvesting.
475 werner 205
/// remove_(stem, branch, foliage)_fraction: percentage of biomass compartment that is *removed* by the harvest operation.
468 werner 206
/// the harvested biomass is collected.
207
void Snag::addHarvest(const Tree* tree, const double remove_stem_fraction, const double remove_branch_fraction, const double remove_foliage_fraction )
208
{
209
    const SoilParameters &soil_params = soilparams; // to be updated
210
 
211
    // immediate flows: 100% of residual foliage, 100% of fine roots: they go to the labile pool
212
    // 100% of coarse root biomass: that goes to the refractory pool
213
    mLabileFlux.addBiomass(tree->biomassFoliage() * (1. - remove_foliage_fraction), soil_params.cnFoliage);
214
    mLabileFlux.addBiomass(tree->biomassFineRoot(), soil_params.cnFineroot);
215
    mRefractoryFlux.addBiomass(tree->biomassCoarseRoot(), soil_params.cnWood);
216
 
217
    // residual branches are equally distributed over five years:
218
    for (int i=0;i<5; i++)
219
        mBranches[i].addBiomass(tree->biomassBranch() * remove_branch_fraction * 0.2, soil_params.cnWood);
220
 
221
    // stem biomass is transferred to the standing woody debris pool (SWD), increase stem number of pool
222
    CNPool &swd = mToSWD[poolIndex(tree->dbh())]; // get right transfer pool
223
    swd.addBiomass(tree->biomassStem() * remove_stem_fraction, soil_params.cnWood);
224
    if (remove_stem_fraction < 1.)
225
        mNumberOfSnags[poolIndex(tree->dbh())]++;
226
}
227