Rev 1221 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1221 | Rev 1222 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/resourceunit.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/resourceunit.cpp': |
2 | /********************************************************************************************
|
2 | /********************************************************************************************
|
3 | ** iLand - an individual based forest landscape and disturbance model
|
3 | ** iLand - an individual based forest landscape and disturbance model
|
4 | ** http://iland.boku.ac.at
|
4 | ** http://iland.boku.ac.at
|
5 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl
|
5 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl
|
6 | **
|
6 | **
|
7 | ** This program is free software: you can redistribute it and/or modify
|
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
|
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
|
9 | ** the Free Software Foundation, either version 3 of the License, or
|
10 | ** (at your option) any later version.
|
10 | ** (at your option) any later version.
|
11 | **
|
11 | **
|
12 | ** This program is distributed in the hope that it will be useful,
|
12 | ** This program is distributed in the hope that it will be useful,
|
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 | ** GNU General Public License for more details.
|
15 | ** GNU General Public License for more details.
|
16 | **
|
16 | **
|
17 | ** You should have received a copy of the GNU General Public License
|
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/>.
|
18 | ** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19 | ********************************************************************************************/
|
19 | ********************************************************************************************/
|
20 | 20 | ||
21 | /** @class ResourceUnit
|
21 | /** @class ResourceUnit
|
22 | ResourceUnit is the spatial unit that encapsulates a forest stand and links to several environmental components
|
22 | ResourceUnit is the spatial unit that encapsulates a forest stand and links to several environmental components
|
23 | (Climate, Soil, Water, ...).
|
23 | (Climate, Soil, Water, ...).
|
24 | @ingroup core
|
24 | @ingroup core
|
25 | A resource unit has a size of (currently) 100x100m. Many processes in iLand operate on the level of a ResourceUnit.
|
25 | A resource unit has a size of (currently) 100x100m. Many processes in iLand operate on the level of a ResourceUnit.
|
26 | Each resource unit has the same Climate and other properties (e.g. available nitrogen).
|
26 | Each resource unit has the same Climate and other properties (e.g. available nitrogen).
|
27 | Proceses on this level are, inter alia, NPP Production (see Production3PG), water calculations (WaterCycle), the modeling
|
27 | Proceses on this level are, inter alia, NPP Production (see Production3PG), water calculations (WaterCycle), the modeling
|
28 | of dead trees (Snag) and soil processes (Soil).
|
28 | of dead trees (Snag) and soil processes (Soil).
|
29 | 29 | ||
30 | */
|
30 | */
|
31 | #include <QtCore>
|
31 | #include <QtCore>
|
32 | #include "global.h"
|
32 | #include "global.h"
|
33 | 33 | ||
34 | #include "resourceunit.h"
|
34 | #include "resourceunit.h"
|
35 | #include "resourceunitspecies.h"
|
35 | #include "resourceunitspecies.h"
|
36 | #include "speciesset.h"
|
36 | #include "speciesset.h"
|
37 | #include "species.h"
|
37 | #include "species.h"
|
38 | #include "production3pg.h"
|
38 | #include "production3pg.h"
|
39 | #include "model.h"
|
39 | #include "model.h"
|
40 | #include "climate.h"
|
40 | #include "climate.h"
|
41 | #include "watercycle.h"
|
41 | #include "watercycle.h"
|
42 | #include "snag.h"
|
42 | #include "snag.h"
|
43 | #include "soil.h"
|
43 | #include "soil.h"
|
44 | #include "helper.h"
|
44 | #include "helper.h"
|
45 | 45 | ||
46 | ResourceUnit::~ResourceUnit() |
46 | ResourceUnit::~ResourceUnit() |
47 | {
|
47 | {
|
48 | if (mWater) |
48 | if (mWater) |
49 | delete mWater; |
49 | delete mWater; |
50 | mWater = 0; |
50 | mWater = 0; |
51 | if (mSnag) |
51 | if (mSnag) |
52 | delete mSnag; |
52 | delete mSnag; |
53 | if (mSoil) |
53 | if (mSoil) |
54 | delete mSoil; |
54 | delete mSoil; |
55 | 55 | ||
56 | qDeleteAll(mRUSpecies); |
56 | qDeleteAll(mRUSpecies); |
57 | 57 | ||
58 | if (mSaplings) |
58 | if (mSaplings) |
59 | delete[] mSaplings; |
59 | delete[] mSaplings; |
60 | 60 | ||
61 | mSnag = 0; |
61 | mSnag = 0; |
62 | mSoil = 0; |
62 | mSoil = 0; |
63 | mSaplings = 0; |
63 | mSaplings = 0; |
64 | }
|
64 | }
|
65 | 65 | ||
66 | ResourceUnit::ResourceUnit(const int index) |
66 | ResourceUnit::ResourceUnit(const int index) |
67 | {
|
67 | {
|
68 | qDeleteAll(mRUSpecies); |
68 | qDeleteAll(mRUSpecies); |
69 | mSpeciesSet = 0; |
69 | mSpeciesSet = 0; |
70 | mClimate = 0; |
70 | mClimate = 0; |
71 | mPixelCount=0; |
71 | mPixelCount=0; |
72 | mStockedArea = 0; |
72 | mStockedArea = 0; |
73 | mStockedPixelCount = 0; |
73 | mStockedPixelCount = 0; |
74 | mStockableArea = 0; |
74 | mStockableArea = 0; |
75 | mAggregatedWLA = 0.; |
75 | mAggregatedWLA = 0.; |
76 | mAggregatedLA = 0.; |
76 | mAggregatedLA = 0.; |
77 | mAggregatedLR = 0.; |
77 | mAggregatedLR = 0.; |
78 | mEffectiveArea = 0.; |
78 | mEffectiveArea = 0.; |
79 | mLRI_modification = 0.; |
79 | mLRI_modification = 0.; |
80 | mIndex = index; |
80 | mIndex = index; |
81 | mSaplingHeightMap = 0; |
81 | mSaplingHeightMap = 0; |
82 | mEffectiveArea_perWLA = 0.; |
82 | mEffectiveArea_perWLA = 0.; |
83 | mWater = new WaterCycle(); |
83 | mWater = new WaterCycle(); |
84 | mSnag = 0; |
84 | mSnag = 0; |
85 | mSoil = 0; |
85 | mSoil = 0; |
86 | mSaplings = 0; |
86 | mSaplings = 0; |
87 | mID = 0; |
87 | mID = 0; |
88 | }
|
88 | }
|
89 | 89 | ||
90 | void ResourceUnit::setup() |
90 | void ResourceUnit::setup() |
91 | {
|
91 | {
|
92 | mWater->setup(this); |
92 | mWater->setup(this); |
93 | 93 | ||
94 | if (mSnag) |
94 | if (mSnag) |
95 | delete mSnag; |
95 | delete mSnag; |
96 | mSnag=0; |
96 | mSnag=0; |
97 | if (mSoil) |
97 | if (mSoil) |
98 | delete mSoil; |
98 | delete mSoil; |
99 | mSoil=0; |
99 | mSoil=0; |
100 | if (Model::settings().carbonCycleEnabled) { |
100 | if (Model::settings().carbonCycleEnabled) { |
101 | mSoil = new Soil(this); |
101 | mSoil = new Soil(this); |
102 | mSnag = new Snag; |
102 | mSnag = new Snag; |
103 | mSnag->setup(this); |
103 | mSnag->setup(this); |
104 | const XmlHelper &xml=GlobalSettings::instance()->settings(); |
104 | const XmlHelper &xml=GlobalSettings::instance()->settings(); |
105 | 105 | ||
106 | // setup contents of the soil of the RU; use values for C and N (kg/ha)
|
106 | // setup contents of the soil of the RU; use values for C and N (kg/ha)
|
107 | mSoil->setInitialState(CNPool(xml.valueDouble("model.site.youngLabileC", -1), |
107 | mSoil->setInitialState(CNPool(xml.valueDouble("model.site.youngLabileC", -1), |
108 | xml.valueDouble("model.site.youngLabileN", -1), |
108 | xml.valueDouble("model.site.youngLabileN", -1), |
109 | xml.valueDouble("model.site.youngLabileDecompRate", -1)), |
109 | xml.valueDouble("model.site.youngLabileDecompRate", -1)), |
110 | CNPool(xml.valueDouble("model.site.youngRefractoryC", -1), |
110 | CNPool(xml.valueDouble("model.site.youngRefractoryC", -1), |
111 | xml.valueDouble("model.site.youngRefractoryN", -1), |
111 | xml.valueDouble("model.site.youngRefractoryN", -1), |
112 | xml.valueDouble("model.site.youngRefractoryDecompRate", -1)), |
112 | xml.valueDouble("model.site.youngRefractoryDecompRate", -1)), |
113 | CNPair(xml.valueDouble("model.site.somC", -1), xml.valueDouble("model.site.somN", -1))); |
113 | CNPair(xml.valueDouble("model.site.somC", -1), xml.valueDouble("model.site.somN", -1))); |
114 | }
|
114 | }
|
115 | 115 | ||
116 | if (mSaplings) |
116 | if (mSaplings) |
117 | delete mSaplings; |
117 | delete mSaplings; |
118 | if (Model::settings().regenerationEnabled) { |
118 | if (Model::settings().regenerationEnabled) { |
119 | mSaplings = new SaplingCell[cPxPerHectare]; |
119 | mSaplings = new SaplingCell[cPxPerHectare]; |
120 | }
|
120 | }
|
121 | 121 | ||
122 | // setup variables
|
122 | // setup variables
|
123 | mUnitVariables.nitrogenAvailable = GlobalSettings::instance()->settings().valueDouble("model.site.availableNitrogen", 40); |
123 | mUnitVariables.nitrogenAvailable = GlobalSettings::instance()->settings().valueDouble("model.site.availableNitrogen", 40); |
124 | 124 | ||
125 | // if dynamic coupling of soil nitrogen is enabled, a starting value for available N is calculated
|
125 | // if dynamic coupling of soil nitrogen is enabled, a starting value for available N is calculated
|
126 | if (mSoil && Model::settings().useDynamicAvailableNitrogen && Model::settings().carbonCycleEnabled) { |
126 | if (mSoil && Model::settings().useDynamicAvailableNitrogen && Model::settings().carbonCycleEnabled) { |
127 | mSoil->setClimateFactor(1.); |
127 | mSoil->setClimateFactor(1.); |
128 | mSoil->calculateYear(); |
128 | mSoil->calculateYear(); |
129 | mUnitVariables.nitrogenAvailable = soil()->availableNitrogen(); |
129 | mUnitVariables.nitrogenAvailable = soil()->availableNitrogen(); |
130 | }
|
130 | }
|
131 | mHasDeadTrees = false; |
131 | mHasDeadTrees = false; |
132 | mAverageAging = 0.; |
132 | mAverageAging = 0.; |
133 | 133 | ||
134 | }
|
134 | }
|
135 | void ResourceUnit::setBoundingBox(const QRectF &bb) |
135 | void ResourceUnit::setBoundingBox(const QRectF &bb) |
136 | {
|
136 | {
|
137 | mBoundingBox = bb; |
137 | mBoundingBox = bb; |
138 | mCornerOffset = GlobalSettings::instance()->model()->grid()->indexAt(bb.topLeft()); |
138 | mCornerOffset = GlobalSettings::instance()->model()->grid()->indexAt(bb.topLeft()); |
139 | }
|
139 | }
|
140 | 140 | ||
141 | /// return the sapling cell at given LIF-coordinates
|
141 | /// return the sapling cell at given LIF-coordinates
|
142 | SaplingCell *ResourceUnit::saplingCell(const QPoint &lifCoords) const |
142 | SaplingCell *ResourceUnit::saplingCell(const QPoint &lifCoords) const |
143 | {
|
143 | {
|
144 | // LIF-Coordinates are global, we here need (RU-)local coordinates
|
144 | // LIF-Coordinates are global, we here need (RU-)local coordinates
|
145 | int ix = lifCoords.x() % cPxPerRU; |
145 | int ix = lifCoords.x() % cPxPerRU; |
146 | int iy = lifCoords.y() % cPxPerRU; |
146 | int iy = lifCoords.y() % cPxPerRU; |
147 | int i = iy*cPxPerRU+ix; |
147 | int i = iy*cPxPerRU+ix; |
148 | Q_ASSERT(i>=0 && i<cPxPerHectare); |
148 | Q_ASSERT(i>=0 && i<cPxPerHectare); |
149 | return &mSaplings[i]; |
149 | return &mSaplings[i]; |
150 | }
|
150 | }
|
151 | 151 | ||
152 | /// set species and setup the species-per-RU-data
|
152 | /// set species and setup the species-per-RU-data
|
153 | void ResourceUnit::setSpeciesSet(SpeciesSet *set) |
153 | void ResourceUnit::setSpeciesSet(SpeciesSet *set) |
154 | {
|
154 | {
|
155 | mSpeciesSet = set; |
155 | mSpeciesSet = set; |
156 | qDeleteAll(mRUSpecies); |
156 | qDeleteAll(mRUSpecies); |
157 | 157 | ||
158 | //mRUSpecies.resize(set->count()); // ensure that the vector space is not relocated
|
158 | //mRUSpecies.resize(set->count()); // ensure that the vector space is not relocated
|
159 | for (int i=0;i<set->count();i++) { |
159 | for (int i=0;i<set->count();i++) { |
160 | Species *s = const_cast<Species*>(mSpeciesSet->species(i)); |
160 | Species *s = const_cast<Species*>(mSpeciesSet->species(i)); |
161 | if (!s) |
161 | if (!s) |
162 | throw IException("ResourceUnit::setSpeciesSet: invalid index!"); |
162 | throw IException("ResourceUnit::setSpeciesSet: invalid index!"); |
163 | 163 | ||
164 | ResourceUnitSpecies *rus = new ResourceUnitSpecies(); |
164 | ResourceUnitSpecies *rus = new ResourceUnitSpecies(); |
165 | mRUSpecies.push_back(rus); |
165 | mRUSpecies.push_back(rus); |
166 | rus->setup(s, this); |
166 | rus->setup(s, this); |
167 | /* be careful: setup() is called with a pointer somewhere to the content of the mRUSpecies container.
|
167 | /* be careful: setup() is called with a pointer somewhere to the content of the mRUSpecies container.
|
168 | If the container memory is relocated (QVector), the pointer gets invalid!!!
|
168 | If the container memory is relocated (QVector), the pointer gets invalid!!!
|
169 | Therefore, a resize() is called before the loop (no resize()-operations during the loop)! */
|
169 | Therefore, a resize() is called before the loop (no resize()-operations during the loop)! */
|
170 | //mRUSpecies[i].setup(s,this); // setup this element
|
170 | //mRUSpecies[i].setup(s,this); // setup this element
|
171 | 171 | ||
172 | }
|
172 | }
|
173 | }
|
173 | }
|
174 | 174 | ||
175 | ResourceUnitSpecies &ResourceUnit::resourceUnitSpecies(const Species *species) |
175 | ResourceUnitSpecies &ResourceUnit::resourceUnitSpecies(const Species *species) |
176 | {
|
176 | {
|
177 | return *mRUSpecies[species->index()]; |
177 | return *mRUSpecies[species->index()]; |
178 | }
|
178 | }
|
179 | 179 | ||
180 | const ResourceUnitSpecies *ResourceUnit::constResourceUnitSpecies(const Species *species) const |
180 | const ResourceUnitSpecies *ResourceUnit::constResourceUnitSpecies(const Species *species) const |
181 | {
|
181 | {
|
182 | return mRUSpecies[species->index()]; |
182 | return mRUSpecies[species->index()]; |
183 | }
|
183 | }
|
184 | 184 | ||
185 | Tree &ResourceUnit::newTree() |
185 | Tree &ResourceUnit::newTree() |
186 | {
|
186 | {
|
187 | // start simple: just append to the vector...
|
187 | // start simple: just append to the vector...
|
188 | if (mTrees.isEmpty()) |
188 | if (mTrees.isEmpty()) |
189 | mTrees.reserve(100); // reserve a junk of memory for trees |
189 | mTrees.reserve(100); // reserve a junk of memory for trees |
190 | 190 | ||
191 | mTrees.append(Tree()); |
191 | mTrees.append(Tree()); |
192 | return mTrees.back(); |
192 | return mTrees.back(); |
193 | }
|
193 | }
|
194 | int ResourceUnit::newTreeIndex() |
194 | int ResourceUnit::newTreeIndex() |
195 | {
|
195 | {
|
196 | newTree(); |
196 | newTree(); |
197 | return mTrees.count()-1; // return index of the last tree |
197 | return mTrees.count()-1; // return index of the last tree |
198 | }
|
198 | }
|
199 | 199 | ||
200 | /// remove dead trees from tree list
|
200 | /// remove dead trees from tree list
|
201 | /// reduce size of vector if lots of space is free
|
201 | /// reduce size of vector if lots of space is free
|
202 | /// tests showed that this way of cleanup is very fast,
|
202 | /// tests showed that this way of cleanup is very fast,
|
203 | /// because no memory allocations are performed (simple memmove())
|
203 | /// because no memory allocations are performed (simple memmove())
|
204 | /// when trees are moved.
|
204 | /// when trees are moved.
|
205 | void ResourceUnit::cleanTreeList() |
205 | void ResourceUnit::cleanTreeList() |
206 | {
|
206 | {
|
207 | if (!mHasDeadTrees) |
207 | if (!mHasDeadTrees) |
208 | return; |
208 | return; |
209 | 209 | ||
210 | QVector<Tree>::iterator last=mTrees.end()-1; |
210 | QVector<Tree>::iterator last=mTrees.end()-1; |
211 | QVector<Tree>::iterator current = mTrees.begin(); |
211 | QVector<Tree>::iterator current = mTrees.begin(); |
212 | while (last>=current && (*last).isDead()) |
212 | while (last>=current && (*last).isDead()) |
213 | --last; |
213 | --last; |
214 | 214 | ||
215 | while (current<last) { |
215 | while (current<last) { |
216 | if ((*current).isDead()) { |
216 | if ((*current).isDead()) { |
217 | *current = *last; // copy data! |
217 | *current = *last; // copy data! |
218 | --last; // |
218 | --last; // |
219 | while (last>=current && (*last).isDead()) |
219 | while (last>=current && (*last).isDead()) |
220 | --last; |
220 | --last; |
221 | }
|
221 | }
|
222 | ++current; |
222 | ++current; |
223 | }
|
223 | }
|
224 | ++last; // last points now to the first dead tree |
224 | ++last; // last points now to the first dead tree |
225 | 225 | ||
226 | // free ressources
|
226 | // free ressources
|
227 | if (last!=mTrees.end()) { |
227 | if (last!=mTrees.end()) { |
228 | mTrees.erase(last, mTrees.end()); |
228 | mTrees.erase(last, mTrees.end()); |
229 | if (mTrees.capacity()>100) { |
229 | if (mTrees.capacity()>100) { |
230 | if (mTrees.count() / double(mTrees.capacity()) < 0.2) { |
230 | if (mTrees.count() / double(mTrees.capacity()) < 0.2) { |
231 | //int target_size = mTrees.count()*2;
|
231 | //int target_size = mTrees.count()*2;
|
232 | //qDebug() << "reduce size from "<<mTrees.capacity() << "to" << target_size;
|
232 | //qDebug() << "reduce size from "<<mTrees.capacity() << "to" << target_size;
|
233 | //mTrees.reserve(qMax(target_size, 100));
|
233 | //mTrees.reserve(qMax(target_size, 100));
|
234 | if (logLevelDebug()) |
234 | if (logLevelDebug()) |
235 | qDebug() << "reduce tree storage of RU" << index() << " from " << mTrees.capacity() << "to" << mTrees.count(); |
235 | qDebug() << "reduce tree storage of RU" << index() << " from " << mTrees.capacity() << "to" << mTrees.count(); |
236 | mTrees.squeeze(); |
236 | mTrees.squeeze(); |
237 | }
|
237 | }
|
238 | }
|
238 | }
|
239 | }
|
239 | }
|
240 | mHasDeadTrees = false; // reset flag |
240 | mHasDeadTrees = false; // reset flag |
241 | }
|
241 | }
|
242 | 242 | ||
243 | void ResourceUnit::newYear() |
243 | void ResourceUnit::newYear() |
244 | {
|
244 | {
|
245 | mAggregatedWLA = 0.; |
245 | mAggregatedWLA = 0.; |
246 | mAggregatedLA = 0.; |
246 | mAggregatedLA = 0.; |
247 | mAggregatedLR = 0.; |
247 | mAggregatedLR = 0.; |
248 | mEffectiveArea = 0.; |
248 | mEffectiveArea = 0.; |
249 | mPixelCount = mStockedPixelCount = 0; |
249 | mPixelCount = mStockedPixelCount = 0; |
250 | snagNewYear(); |
250 | snagNewYear(); |
251 | if (mSoil) |
251 | if (mSoil) |
252 | mSoil->newYear(); |
252 | mSoil->newYear(); |
253 | // clear statistics global and per species...
|
253 | // clear statistics global and per species...
|
254 | QList<ResourceUnitSpecies*>::const_iterator i; |
254 | QList<ResourceUnitSpecies*>::const_iterator i; |
255 | QList<ResourceUnitSpecies*>::const_iterator iend = mRUSpecies.constEnd(); |
255 | QList<ResourceUnitSpecies*>::const_iterator iend = mRUSpecies.constEnd(); |
256 | mStatistics.clear(); |
256 | mStatistics.clear(); |
257 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
257 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
258 | (*i)->statisticsDead().clear(); |
258 | (*i)->statisticsDead().clear(); |
259 | (*i)->statisticsMgmt().clear(); |
259 | (*i)->statisticsMgmt().clear(); |
260 | }
|
260 | }
|
261 | 261 | ||
262 | }
|
262 | }
|
263 | 263 | ||
264 | /** production() is the "stand-level" part of the biomass production (3PG).
|
264 | /** production() is the "stand-level" part of the biomass production (3PG).
|
265 | - The amount of radiation intercepted by the stand is calculated
|
265 | - The amount of radiation intercepted by the stand is calculated
|
266 | - the water cycle is calculated
|
266 | - the water cycle is calculated
|
267 | - statistics for each species are cleared
|
267 | - statistics for each species are cleared
|
268 | - The 3PG production for each species and ressource unit is called (calculates species-responses and NPP production)
|
268 | - The 3PG production for each species and ressource unit is called (calculates species-responses and NPP production)
|
269 | see also: http://iland.boku.ac.at/individual+tree+light+availability */
|
269 | see also: http://iland.boku.ac.at/individual+tree+light+availability */
|
270 | void ResourceUnit::production() |
270 | void ResourceUnit::production() |
271 | {
|
271 | {
|
272 | 272 | ||
273 | if (mAggregatedWLA==0. || mPixelCount==0) { |
273 | if (mAggregatedWLA==0. || mPixelCount==0) { |
274 | // clear statistics of resourceunitspecies
|
274 | // clear statistics of resourceunitspecies
|
275 | for ( QList<ResourceUnitSpecies*>::const_iterator i=mRUSpecies.constBegin(); i!=mRUSpecies.constEnd(); ++i) |
275 | for ( QList<ResourceUnitSpecies*>::const_iterator i=mRUSpecies.constBegin(); i!=mRUSpecies.constEnd(); ++i) |
276 | (*i)->statistics().clear(); |
276 | (*i)->statistics().clear(); |
277 | mEffectiveArea = 0.; |
277 | mEffectiveArea = 0.; |
278 | mStockedArea = 0.; |
278 | mStockedArea = 0.; |
279 | return; |
279 | return; |
280 | }
|
280 | }
|
281 | 281 | ||
282 | // the pixel counters are filled during the height-grid-calculations
|
282 | // the pixel counters are filled during the height-grid-calculations
|
283 | mStockedArea = cHeightPerRU*cHeightPerRU * mStockedPixelCount; // m2 (1 height grid pixel = 10x10m) |
283 | mStockedArea = cHeightPerRU*cHeightPerRU * mStockedPixelCount; // m2 (1 height grid pixel = 10x10m) |
284 | if (leafAreaIndex()<3.) { |
284 | if (leafAreaIndex()<3.) { |
285 | // estimate stocked area based on crown projections
|
285 | // estimate stocked area based on crown projections
|
286 | double crown_area = 0.; |
286 | double crown_area = 0.; |
287 | for (int i=0;i<mTrees.count();++i) |
287 | for (int i=0;i<mTrees.count();++i) |
288 | crown_area += mTrees.at(i).isDead() ? 0. : mTrees.at(i).stamp()->reader()->crownArea(); |
288 | crown_area += mTrees.at(i).isDead() ? 0. : mTrees.at(i).stamp()->reader()->crownArea(); |
289 | 289 | ||
290 | if (logLevelDebug()) |
290 | if (logLevelDebug()) |
291 | qDebug() << "crown area: lai" << leafAreaIndex() << "stocked area (pixels)" << mStockedArea << " area (crown)" << crown_area; |
291 | qDebug() << "crown area: lai" << leafAreaIndex() << "stocked area (pixels)" << mStockedArea << " area (crown)" << crown_area; |
292 | if (leafAreaIndex()<1.) { |
292 | if (leafAreaIndex()<1.) { |
293 | mStockedArea = std::min(crown_area, mStockedArea); |
293 | mStockedArea = std::min(crown_area, mStockedArea); |
294 | } else { |
294 | } else { |
295 | // for LAI between 1 and 3:
|
295 | // for LAI between 1 and 3:
|
296 | // interpolate between sum of crown area of trees (at LAI=1) and the pixel-based value (at LAI=3 and above)
|
296 | // interpolate between sum of crown area of trees (at LAI=1) and the pixel-based value (at LAI=3 and above)
|
297 | double px_frac = (leafAreaIndex()-1.)/2.; // 0 at LAI=1, 1 at LAI=3 |
297 | double px_frac = (leafAreaIndex()-1.)/2.; // 0 at LAI=1, 1 at LAI=3 |
298 | mStockedArea = mStockedArea * px_frac + std::min(crown_area, mStockedArea) * (1. - px_frac); |
298 | mStockedArea = mStockedArea * px_frac + std::min(crown_area, mStockedArea) * (1. - px_frac); |
299 | }
|
299 | }
|
300 | if (mStockedArea==0.) |
300 | if (mStockedArea==0.) |
301 | return; |
301 | return; |
302 | }
|
302 | }
|
303 | 303 | ||
304 | // calculate the leaf area index (LAI)
|
304 | // calculate the leaf area index (LAI)
|
305 | double LAI = mAggregatedLA / mStockedArea; |
305 | double LAI = mAggregatedLA / mStockedArea; |
306 | // calculate the intercepted radiation fraction using the law of Beer Lambert
|
306 | // calculate the intercepted radiation fraction using the law of Beer Lambert
|
307 | const double k = Model::settings().lightExtinctionCoefficient; |
307 | const double k = Model::settings().lightExtinctionCoefficient; |
308 | double interception_fraction = 1. - exp(-k * LAI); |
308 | double interception_fraction = 1. - exp(-k * LAI); |
309 | mEffectiveArea = mStockedArea * interception_fraction; // m2 |
309 | mEffectiveArea = mStockedArea * interception_fraction; // m2 |
310 | 310 | ||
311 | // calculate the total weighted leaf area on this RU:
|
311 | // calculate the total weighted leaf area on this RU:
|
312 | mLRI_modification = interception_fraction * mStockedArea / mAggregatedWLA; // p_WLA |
312 | mLRI_modification = interception_fraction * mStockedArea / mAggregatedWLA; // p_WLA |
313 | if (mLRI_modification == 0.) |
313 | if (mLRI_modification == 0.) |
314 | qDebug() << "lri modifaction==0!"; |
314 | qDebug() << "lri modifaction==0!"; |
315 | 315 | ||
316 | if (logLevelDebug()) { |
316 | if (logLevelDebug()) { |
317 | DBGMODE(qDebug() << QString("production: LAI: %1 (intercepted fraction: %2, stocked area: %4). LRI-Multiplier: %3") |
317 | DBGMODE(qDebug() << QString("production: LAI: %1 (intercepted fraction: %2, stocked area: %4). LRI-Multiplier: %3") |
318 | .arg(LAI) |
318 | .arg(LAI) |
319 | .arg(interception_fraction) |
319 | .arg(interception_fraction) |
320 | .arg(mLRI_modification) |
320 | .arg(mLRI_modification) |
321 | .arg(mStockedArea); |
321 | .arg(mStockedArea); |
322 | ); |
322 | ); |
323 | }
|
323 | }
|
324 | 324 | ||
325 | // calculate LAI fractions
|
325 | // calculate LAI fractions
|
326 | QList<ResourceUnitSpecies*>::const_iterator i; |
326 | QList<ResourceUnitSpecies*>::const_iterator i; |
327 | QList<ResourceUnitSpecies*>::const_iterator iend = mRUSpecies.constEnd(); |
327 | QList<ResourceUnitSpecies*>::const_iterator iend = mRUSpecies.constEnd(); |
328 | double ru_lai = leafAreaIndex(); |
328 | double ru_lai = leafAreaIndex(); |
329 | if (ru_lai < 1.) |
329 | if (ru_lai < 1.) |
330 | ru_lai = 1.; |
330 | ru_lai = 1.; |
331 | // note: LAIFactors are only 1 if sum of LAI is > 1. (see WaterCycle)
|
331 | // note: LAIFactors are only 1 if sum of LAI is > 1. (see WaterCycle)
|
332 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
332 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
333 | double lai_factor = (*i)->statistics().leafAreaIndex() / ru_lai; |
333 | double lai_factor = (*i)->statistics().leafAreaIndex() / ru_lai; |
334 | 334 | ||
335 | //DBGMODE(
|
335 | //DBGMODE(
|
336 | if (lai_factor > 1.) { |
336 | if (lai_factor > 1.) { |
337 | const ResourceUnitSpecies* rus=*i; |
337 | const ResourceUnitSpecies* rus=*i; |
338 | qDebug() << "LAI factor > 1: species ru-index:" << rus->species()->name() << rus->ru()->index(); |
338 | qDebug() << "LAI factor > 1: species ru-index:" << rus->species()->name() << rus->ru()->index(); |
339 | }
|
339 | }
|
340 | //);
|
340 | //);
|
341 | (*i)->setLAIfactor( lai_factor ); |
341 | (*i)->setLAIfactor( lai_factor ); |
342 | }
|
342 | }
|
343 | 343 | ||
344 | // soil water model - this determines soil water contents needed for response calculations
|
344 | // soil water model - this determines soil water contents needed for response calculations
|
345 | {
|
345 | {
|
346 | mWater->run(); |
346 | mWater->run(); |
347 | }
|
347 | }
|
348 | 348 | ||
349 | // invoke species specific calculation (3PG)
|
349 | // invoke species specific calculation (3PG)
|
350 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
350 | for (i=mRUSpecies.constBegin(); i!=iend; ++i) { |
351 | //DBGMODE(
|
351 | //DBGMODE(
|
352 | if ((*i)->LAIfactor() > 1.) { |
352 | if ((*i)->LAIfactor() > 1.) { |
353 | const ResourceUnitSpecies* rus=*i; |
353 | const ResourceUnitSpecies* rus=*i; |
354 | qDebug() << "LAI factor > 1: species ru-index value:" << rus->species()->name() << rus->ru()->index() << rus->LAIfactor(); |
354 | qDebug() << "LAI factor > 1: species ru-index value:" << rus->species()->name() << rus->ru()->index() << rus->LAIfactor(); |
355 | }
|
355 | }
|
356 | //);
|
356 | //);
|
357 | (*i)->calculate(); // CALCULATE 3PG |
357 | (*i)->calculate(); // CALCULATE 3PG |
358 | 358 | ||
359 | // debug output related to production
|
359 | // debug output related to production
|
360 | if (GlobalSettings::instance()->isDebugEnabled(GlobalSettings::dStandGPP) && (*i)->LAIfactor()>0.) { |
360 | if (GlobalSettings::instance()->isDebugEnabled(GlobalSettings::dStandGPP) && (*i)->LAIfactor()>0.) { |
361 | DebugList &out = GlobalSettings::instance()->debugList(index(), GlobalSettings::dStandGPP); |
361 | DebugList &out = GlobalSettings::instance()->debugList(index(), GlobalSettings::dStandGPP); |
362 | out << (*i)->species()->id() << index() << id(); |
362 | out << (*i)->species()->id() << index() << id(); |
363 | out << (*i)->LAIfactor() << (*i)->prod3PG().GPPperArea() << productiveArea()*(*i)->LAIfactor()*(*i)->prod3PG().GPPperArea() << averageAging() << (*i)->prod3PG().fEnvYear() ; |
363 | out << (*i)->LAIfactor() << (*i)->prod3PG().GPPperArea() << productiveArea()*(*i)->LAIfactor()*(*i)->prod3PG().GPPperArea() << averageAging() << (*i)->prod3PG().fEnvYear() ; |
364 | 364 | ||
365 | }
|
365 | }
|
366 | }
|
366 | }
|
367 | }
|
367 | }
|
368 | 368 | ||
369 | void ResourceUnit::calculateInterceptedArea() |
369 | void ResourceUnit::calculateInterceptedArea() |
370 | {
|
370 | {
|
371 | if (mAggregatedLR==0) { |
371 | if (mAggregatedLR==0) { |
372 | mEffectiveArea_perWLA = 0.; |
372 | mEffectiveArea_perWLA = 0.; |
373 | return; |
373 | return; |
374 | }
|
374 | }
|
375 | Q_ASSERT(mAggregatedLR>0.); |
375 | Q_ASSERT(mAggregatedLR>0.); |
376 | mEffectiveArea_perWLA = mEffectiveArea / mAggregatedLR; |
376 | mEffectiveArea_perWLA = mEffectiveArea / mAggregatedLR; |
377 | if (logLevelDebug()) qDebug() << "RU: aggregated lightresponse:" << mAggregatedLR << "eff.area./wla:" << mEffectiveArea_perWLA; |
377 | if (logLevelDebug()) qDebug() << "RU: aggregated lightresponse:" << mAggregatedLR << "eff.area./wla:" << mEffectiveArea_perWLA; |
378 | }
|
378 | }
|
379 | 379 | ||
380 | // function is called immediately before the growth of individuals
|
380 | // function is called immediately before the growth of individuals
|
381 | void ResourceUnit::beforeGrow() |
381 | void ResourceUnit::beforeGrow() |
382 | {
|
382 | {
|
383 | mAverageAging = 0.; |
383 | mAverageAging = 0.; |
384 | }
|
384 | }
|
385 | 385 | ||
386 | // function is called after finishing the indivdual growth / mortality.
|
386 | // function is called after finishing the indivdual growth / mortality.
|
387 | void ResourceUnit::afterGrow() |
387 | void ResourceUnit::afterGrow() |
388 | {
|
388 | {
|
389 | mAverageAging = leafArea()>0.?mAverageAging/leafArea():0; // calculate aging value (calls to addAverageAging() by individual trees) |
389 | mAverageAging = leafArea()>0.?mAverageAging/leafArea():0; // calculate aging value (calls to addAverageAging() by individual trees) |
390 | if (mAverageAging>0. && mAverageAging<0.00001) |
390 | if (mAverageAging>0. && mAverageAging<0.00001) |
391 | qDebug() << "ru" << mIndex << "aging <0.00001"; |
391 | qDebug() << "ru" << mIndex << "aging <0.00001"; |
392 | if (mAverageAging<0. || mAverageAging>1.) |
392 | if (mAverageAging<0. || mAverageAging>1.) |
393 | qDebug() << "Average aging invalid: (RU, LAI):" << index() << mStatistics.leafAreaIndex(); |
393 | qDebug() << "Average aging invalid: (RU, LAI):" << index() << mStatistics.leafAreaIndex(); |
394 | }
|
394 | }
|
395 | 395 | ||
396 | void ResourceUnit::yearEnd() |
396 | void ResourceUnit::yearEnd() |
397 | {
|
397 | {
|
398 | // calculate statistics for all tree species of the ressource unit
|
398 | // calculate statistics for all tree species of the ressource unit
|
399 | int c = mRUSpecies.count(); |
399 | int c = mRUSpecies.count(); |
400 | for (int i=0;i<c; i++) { |
400 | for (int i=0;i<c; i++) { |
401 | mRUSpecies[i]->statisticsDead().calculate(); // calculate the dead trees |
401 | mRUSpecies[i]->statisticsDead().calculate(); // calculate the dead trees |
402 | mRUSpecies[i]->statisticsMgmt().calculate(); // stats of removed trees |
402 | mRUSpecies[i]->statisticsMgmt().calculate(); // stats of removed trees |
403 | mRUSpecies[i]->updateGWL(); // get sum of dead trees (died + removed) |
403 | mRUSpecies[i]->updateGWL(); // get sum of dead trees (died + removed) |
404 | mRUSpecies[i]->statistics().calculate(); // calculate the living (and add removed volume to gwl) |
404 | mRUSpecies[i]->statistics().calculate(); // calculate the living (and add removed volume to gwl) |
405 | mStatistics.add(mRUSpecies[i]->statistics()); |
405 | mStatistics.add(mRUSpecies[i]->statistics()); |
406 | }
|
406 | }
|
407 | mStatistics.calculate(); // aggreagte on stand level |
407 | mStatistics.calculate(); // aggreagte on stand level |
408 | 408 | ||
409 | // update carbon flows
|
409 | // update carbon flows
|
410 | if (soil() && GlobalSettings::instance()->model()->settings().carbonCycleEnabled) { |
410 | if (soil() && GlobalSettings::instance()->model()->settings().carbonCycleEnabled) { |
411 | double area_factor = stockableArea() / cRUArea; //conversion factor |
411 | double area_factor = stockableArea() / cRUArea; //conversion factor |
412 | mUnitVariables.carbonUptake = statistics().npp() * biomassCFraction; |
412 | mUnitVariables.carbonUptake = statistics().npp() * biomassCFraction; |
413 | mUnitVariables.carbonUptake += statistics().nppSaplings() * biomassCFraction; |
413 | mUnitVariables.carbonUptake += statistics().nppSaplings() * biomassCFraction; |
414 | 414 | ||
415 | double to_atm = snag()->fluxToAtmosphere().C / area_factor; // from snags, kgC/ha |
415 | double to_atm = snag()->fluxToAtmosphere().C / area_factor; // from snags, kgC/ha |
416 | to_atm += soil()->fluxToAtmosphere().C *cRUArea/10.; // soil: t/ha -> t/m2 -> kg/ha |
416 | to_atm += soil()->fluxToAtmosphere().C *cRUArea/10.; // soil: t/ha -> t/m2 -> kg/ha |
417 | mUnitVariables.carbonToAtm = to_atm; |
417 | mUnitVariables.carbonToAtm = to_atm; |
418 | 418 | ||
419 | double to_dist = snag()->fluxToDisturbance().C / area_factor; |
419 | double to_dist = snag()->fluxToDisturbance().C / area_factor; |
420 | to_dist += soil()->fluxToDisturbance().C * cRUArea/10.; |
420 | to_dist += soil()->fluxToDisturbance().C * cRUArea/10.; |
421 | double to_harvest = snag()->fluxToExtern().C / area_factor; |
421 | double to_harvest = snag()->fluxToExtern().C / area_factor; |
422 | 422 | ||
423 | mUnitVariables.NEP = mUnitVariables.carbonUptake - to_atm - to_dist - to_harvest; // kgC/ha |
423 | mUnitVariables.NEP = mUnitVariables.carbonUptake - to_atm - to_dist - to_harvest; // kgC/ha |
424 | 424 | ||
425 | // incremental values....
|
425 | // incremental values....
|
426 | mUnitVariables.cumCarbonUptake += mUnitVariables.carbonUptake; |
426 | mUnitVariables.cumCarbonUptake += mUnitVariables.carbonUptake; |
427 | mUnitVariables.cumCarbonToAtm += mUnitVariables.carbonToAtm; |
427 | mUnitVariables.cumCarbonToAtm += mUnitVariables.carbonToAtm; |
428 | mUnitVariables.cumNEP += mUnitVariables.NEP; |
428 | mUnitVariables.cumNEP += mUnitVariables.NEP; |
429 | 429 | ||
430 | }
|
430 | }
|
431 | 431 | ||
432 | }
|
432 | }
|
433 | 433 | ||
434 | void ResourceUnit::addTreeAgingForAllTrees() |
434 | void ResourceUnit::addTreeAgingForAllTrees() |
435 | {
|
435 | {
|
436 | mAverageAging = 0.; |
436 | mAverageAging = 0.; |
437 | foreach(const Tree &t, mTrees) { |
437 | foreach(const Tree &t, mTrees) { |
438 | addTreeAging(t.leafArea(), t.species()->aging(t.height(), t.age())); |
438 | addTreeAging(t.leafArea(), t.species()->aging(t.height(), t.age())); |
439 | }
|
439 | }
|
440 | 440 | ||
441 | }
|
441 | }
|
442 | 442 | ||
443 | /// refresh of tree based statistics.
|
443 | /// refresh of tree based statistics.
|
444 | /// WARNING: this function is only called once (during startup).
|
444 | /// WARNING: this function is only called once (during startup).
|
445 | /// see function "yearEnd()" above!!!
|
445 | /// see function "yearEnd()" above!!!
|
446 | void ResourceUnit::createStandStatistics() |
446 | void ResourceUnit::createStandStatistics() |
447 | {
|
447 | {
|
448 | // clear statistics (ru-level and ru-species level)
|
448 | // clear statistics (ru-level and ru-species level)
|
449 | mStatistics.clear(); |
449 | mStatistics.clear(); |
450 | for (int i=0;i<mRUSpecies.count();i++) { |
450 | for (int i=0;i<mRUSpecies.count();i++) { |
451 | mRUSpecies[i]->statistics().clear(); |
451 | mRUSpecies[i]->statistics().clear(); |
452 | mRUSpecies[i]->statisticsDead().clear(); |
452 | mRUSpecies[i]->statisticsDead().clear(); |
453 | mRUSpecies[i]->statisticsMgmt().clear(); |
453 | mRUSpecies[i]->statisticsMgmt().clear(); |
454 | mRUSpecies[i]->saplingStat().clearStatistics(); |
454 | mRUSpecies[i]->saplingStat().clearStatistics(); |
455 | }
|
455 | }
|
456 | 456 | ||
457 | // add all trees to the statistics objects of the species
|
457 | // add all trees to the statistics objects of the species
|
458 | foreach(const Tree &t, mTrees) { |
458 | foreach(const Tree &t, mTrees) { |
459 | if (!t.isDead()) |
459 | if (!t.isDead()) |
460 | resourceUnitSpecies(t.species()).statistics().add(&t, 0); |
460 | resourceUnitSpecies(t.species()).statistics().add(&t, 0); |
461 | }
|
461 | }
|
462 | // summarise sapling stats
|
462 | // summarise sapling stats
|
463 | GlobalSettings::instance()->model()->saplings()->calculateInitialStatistics(this); |
463 | GlobalSettings::instance()->model()->saplings()->calculateInitialStatistics(this); |
464 | 464 | ||
465 | // summarize statistics for the whole resource unit
|
465 | // summarize statistics for the whole resource unit
|
466 | for (int i=0;i<mRUSpecies.count();i++) { |
466 | for (int i=0;i<mRUSpecies.count();i++) { |
467 | mRUSpecies[i]->saplingStat().calculate(mRUSpecies[i]->species(), this); |
467 | mRUSpecies[i]->saplingStat().calculate(mRUSpecies[i]->species(), this); |
468 | mRUSpecies[i]->statistics().add(&mRUSpecies[i]->saplingStat()); |
468 | mRUSpecies[i]->statistics().add(&mRUSpecies[i]->saplingStat()); |
469 | mRUSpecies[i]->statistics().calculate(); |
469 | mRUSpecies[i]->statistics().calculate(); |
470 | mStatistics.add(mRUSpecies[i]->statistics()); |
470 | mStatistics.add(mRUSpecies[i]->statistics()); |
471 | }
|
471 | }
|
472 | mStatistics.calculate(); |
472 | mStatistics.calculate(); |
473 | mAverageAging = mStatistics.leafAreaIndex()>0.?mAverageAging / (mStatistics.leafAreaIndex()*stockableArea()):0.; |
473 | mAverageAging = mStatistics.leafAreaIndex()>0.?mAverageAging / (mStatistics.leafAreaIndex()*stockableArea()):0.; |
474 | if (mAverageAging<0. || mAverageAging>1.) |
474 | if (mAverageAging<0. || mAverageAging>1.) |
475 | qDebug() << "Average aging invalid: (RU, LAI):" << index() << mStatistics.leafAreaIndex(); |
475 | qDebug() << "Average aging invalid: (RU, LAI):" << index() << mStatistics.leafAreaIndex(); |
476 | 476 | ||
477 | }
|
477 | }
|
478 | 478 | ||
479 | /** recreate statistics. This is necessary after events that changed the structure
|
479 | /** recreate statistics. This is necessary after events that changed the structure
|
480 | of the stand *after* the growth of trees (where stand statistics are updated).
|
480 | of the stand *after* the growth of trees (where stand statistics are updated).
|
481 | An example is after disturbances. */
|
481 | An example is after disturbances. */
|
482 | void ResourceUnit::recreateStandStatistics(bool recalculate_stats) |
482 | void ResourceUnit::recreateStandStatistics(bool recalculate_stats) |
483 | {
|
483 | {
|
484 | // when called after disturbances (recalculate_stats=false), we
|
484 | // when called after disturbances (recalculate_stats=false), we
|
485 | // clear only the tree-specific variables in the stats (i.e. we keep NPP, and regen carbon),
|
485 | // clear only the tree-specific variables in the stats (i.e. we keep NPP, and regen carbon),
|
486 | // and then re-add all trees (since TreeGrowthData is NULL no NPP is available).
|
486 | // and then re-add all trees (since TreeGrowthData is NULL no NPP is available).
|
487 | // The statistics are not summarised here, because this happens for all resource units
|
487 | // The statistics are not summarised here, because this happens for all resource units
|
488 | // in the yearEnd function of RU.
|
488 | // in the yearEnd function of RU.
|
489 | for (int i=0;i<mRUSpecies.count();i++) { |
489 | for (int i=0;i<mRUSpecies.count();i++) { |
490 | if (recalculate_stats) |
490 | if (recalculate_stats) |
491 | mRUSpecies[i]->statistics().clear(); |
491 | mRUSpecies[i]->statistics().clear(); |
492 | else
|
492 | else
|
493 | mRUSpecies[i]->statistics().clearOnlyTrees(); |
493 | mRUSpecies[i]->statistics().clearOnlyTrees(); |
494 | }
|
494 | }
|
495 | foreach(const Tree &t, mTrees) { |
495 | foreach(const Tree &t, mTrees) { |
496 | resourceUnitSpecies(t.species()).statistics().add(&t, 0); |
496 | resourceUnitSpecies(t.species()).statistics().add(&t, 0); |
497 | }
|
497 | }
|
498 | 498 | ||
499 | if (recalculate_stats) { |
499 | if (recalculate_stats) { |
500 | for (int i=0;i<mRUSpecies.count();i++) { |
500 | for (int i=0;i<mRUSpecies.count();i++) { |
501 | mRUSpecies[i]->statistics().calculate(); |
501 | mRUSpecies[i]->statistics().calculate(); |
502 | }
|
502 | }
|
503 | }
|
503 | }
|
504 | }
|
504 | }
|
505 | 505 | ||
506 | 506 | ||
507 | 507 | ||
508 | 508 | ||
509 | void ResourceUnit::calculateCarbonCycle() |
509 | void ResourceUnit::calculateCarbonCycle() |
510 | {
|
510 | {
|
511 | if (!snag()) |
511 | if (!snag()) |
512 | return; |
512 | return; |
513 | 513 | ||
514 | // (1) calculate the snag dynamics
|
514 | // (1) calculate the snag dynamics
|
515 | // because all carbon/nitrogen-flows from trees to the soil are routed through the snag-layer,
|
515 | // because all carbon/nitrogen-flows from trees to the soil are routed through the snag-layer,
|
516 | // all soil inputs (litter + deadwood) are collected in the Snag-object.
|
516 | // all soil inputs (litter + deadwood) are collected in the Snag-object.
|
517 | snag()->calculateYear(); |
517 | snag()->calculateYear(); |
518 | soil()->setClimateFactor( snag()->climateFactor() ); // the climate factor is only calculated once |
518 | soil()->setClimateFactor( snag()->climateFactor() ); // the climate factor is only calculated once |
519 | soil()->setSoilInput( snag()->labileFlux(), snag()->refractoryFlux()); |
519 | soil()->setSoilInput( snag()->labileFlux(), snag()->refractoryFlux()); |
520 | soil()->calculateYear(); // update the ICBM/2N model |
520 | soil()->calculateYear(); // update the ICBM/2N model |
521 | // use available nitrogen?
|
521 | // use available nitrogen?
|
522 | if (Model::settings().useDynamicAvailableNitrogen) |
522 | if (Model::settings().useDynamicAvailableNitrogen) |
523 | mUnitVariables.nitrogenAvailable = soil()->availableNitrogen(); |
523 | mUnitVariables.nitrogenAvailable = soil()->availableNitrogen(); |
524 | 524 | ||
525 | // debug output
|
525 | // debug output
|
526 | if (GlobalSettings::instance()->isDebugEnabled(GlobalSettings::dCarbonCycle) && !snag()->isEmpty()) { |
526 | if (GlobalSettings::instance()->isDebugEnabled(GlobalSettings::dCarbonCycle) && !snag()->isEmpty()) { |
527 | DebugList &out = GlobalSettings::instance()->debugList(index(), GlobalSettings::dCarbonCycle); |
527 | DebugList &out = GlobalSettings::instance()->debugList(index(), GlobalSettings::dCarbonCycle); |
528 | out << index() << id(); // resource unit index and id |
528 | out << index() << id(); // resource unit index and id |
529 | out << snag()->debugList(); // snag debug outs |
529 | out << snag()->debugList(); // snag debug outs |
530 | out << soil()->debugList(); // ICBM/2N debug outs |
530 | out << soil()->debugList(); // ICBM/2N debug outs |
531 | }
|
531 | }
|
532 | 532 | ||
533 | }
|
533 | }
|
534 | 534 | ||
535 | 535 | ||
536 | 536 |