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 |