Subversion Repositories public iLand

Rev

Rev 451 | Rev 453 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 451 Rev 452
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
/** @class ResourceUnit
2
/** @class ResourceUnit
3
  ResourceUnit is the spatial unit that encapsulates a forest stand and links to several environmental components
3
  ResourceUnit is the spatial unit that encapsulates a forest stand and links to several environmental components
4
  (Climate, Soil, Water, ...).
4
  (Climate, Soil, Water, ...).
5

5

6
  */
6
  */
7
#include <QtCore>
7
#include <QtCore>
8
#include "global.h"
8
#include "global.h"
9
9
10
#include "resourceunit.h"
10
#include "resourceunit.h"
11
#include "resourceunitspecies.h"
11
#include "resourceunitspecies.h"
12
#include "speciesset.h"
12
#include "speciesset.h"
13
#include "species.h"
13
#include "species.h"
14
#include "production3pg.h"
14
#include "production3pg.h"
15
#include "model.h"
15
#include "model.h"
16
#include "climate.h"
16
#include "climate.h"
17
#include "watercycle.h"
17
#include "watercycle.h"
18
#include "helper.h"
18
#include "helper.h"
19
19
20
ResourceUnit::~ResourceUnit()
20
ResourceUnit::~ResourceUnit()
21
{
21
{
22
    if (mWater)
22
    if (mWater)
23
        delete mWater;
23
        delete mWater;
24
}
24
}
25
25
26
ResourceUnit::ResourceUnit(const int index)
26
ResourceUnit::ResourceUnit(const int index)
27
{
27
{
28
    mSpeciesSet = 0;
28
    mSpeciesSet = 0;
29
    mClimate = 0;
29
    mClimate = 0;
30
    mPixelCount=0;
30
    mPixelCount=0;
31
    mIndex = index;
31
    mIndex = index;
32
    mSaplingHeightMap = 0;
32
    mSaplingHeightMap = 0;
33
    mWater = new WaterCycle();
33
    mWater = new WaterCycle();
34
34
35
    mTrees.reserve(100); // start with space for 100 trees.
35
    mTrees.reserve(100); // start with space for 100 trees.
36
}
36
}
37
37
38
void ResourceUnit::setup()
38
void ResourceUnit::setup()
39
{
39
{
40
    mWater->setup(this);
40
    mWater->setup(this);
41
    // setup variables
41
    // setup variables
42
    mUnitVariables.nitrogenAvailable = GlobalSettings::instance()->settings().valueDouble("model.site.availableNitrogen", 40);
42
    mUnitVariables.nitrogenAvailable = GlobalSettings::instance()->settings().valueDouble("model.site.availableNitrogen", 40);
43
    mAverageAging = 0.;
43
    mAverageAging = 0.;
44
44
45
}
45
}
46
void ResourceUnit::setBoundingBox(const QRectF &bb)
46
void ResourceUnit::setBoundingBox(const QRectF &bb)
47
{
47
{
48
    mBoundingBox = bb;
48
    mBoundingBox = bb;
49
    mCornerCoord = GlobalSettings::instance()->model()->grid()->indexAt(bb.topLeft());
49
    mCornerCoord = GlobalSettings::instance()->model()->grid()->indexAt(bb.topLeft());
50
}
50
}
51
51
52
/// set species and setup the species-per-RU-data
52
/// set species and setup the species-per-RU-data
53
void ResourceUnit::setSpeciesSet(SpeciesSet *set)
53
void ResourceUnit::setSpeciesSet(SpeciesSet *set)
54
{
54
{
55
    mSpeciesSet = set;
55
    mSpeciesSet = set;
56
    mRUSpecies.clear();
56
    mRUSpecies.clear();
57
    mRUSpecies.resize(set->count()); // ensure that the vector space is not relocated
57
    mRUSpecies.resize(set->count()); // ensure that the vector space is not relocated
58
    for (int i=0;i<set->count();i++) {
58
    for (int i=0;i<set->count();i++) {
59
        Species *s = const_cast<Species*>(mSpeciesSet->species(i));
59
        Species *s = const_cast<Species*>(mSpeciesSet->species(i));
60
        if (!s)
60
        if (!s)
61
            throw IException("ResourceUnit::setSpeciesSet: invalid index!");
61
            throw IException("ResourceUnit::setSpeciesSet: invalid index!");
62
62
63
        /* be careful: setup() is called with a pointer somewhere to the content of the mRUSpecies container.
63
        /* be careful: setup() is called with a pointer somewhere to the content of the mRUSpecies container.
64
           If the container memory is relocated (QVector), the pointer gets invalid!!!
64
           If the container memory is relocated (QVector), the pointer gets invalid!!!
65
           Therefore, a resize() is called before the loop (no resize()-operations during the loop)! */
65
           Therefore, a resize() is called before the loop (no resize()-operations during the loop)! */
66
        mRUSpecies[i].setup(s,this); // setup this element
66
        mRUSpecies[i].setup(s,this); // setup this element
67
67
68
    }
68
    }
69
}
69
}
70
70
71
ResourceUnitSpecies &ResourceUnit::resourceUnitSpecies(const Species *species)
71
ResourceUnitSpecies &ResourceUnit::resourceUnitSpecies(const Species *species)
72
{
72
{
73
    return mRUSpecies[species->index()];
73
    return mRUSpecies[species->index()];
74
}
74
}
75
75
76
Tree &ResourceUnit::newTree()
76
Tree &ResourceUnit::newTree()
77
{
77
{
78
    // start simple: just append to the vector...
78
    // start simple: just append to the vector...
79
    mTrees.append(Tree());
79
    mTrees.append(Tree());
80
    return mTrees.back();
80
    return mTrees.back();
81
}
81
}
82
int ResourceUnit::newTreeIndex()
82
int ResourceUnit::newTreeIndex()
83
{
83
{
84
    // start simple: just append to the vector...
84
    // start simple: just append to the vector...
85
    mTrees.append(Tree());
85
    mTrees.append(Tree());
86
    return mTrees.count()-1;
86
    return mTrees.count()-1;
87
}
87
}
88
88
89
/// remove dead trees from tree list
89
/// remove dead trees from tree list
90
/// reduce size of vector if lots of space is free
90
/// reduce size of vector if lots of space is free
91
/// tests showed that this way of cleanup is very fast,
91
/// tests showed that this way of cleanup is very fast,
92
/// because no memory allocations are performed (simple memmove())
92
/// because no memory allocations are performed (simple memmove())
93
/// when trees are moved.
93
/// when trees are moved.
94
void ResourceUnit::cleanTreeList()
94
void ResourceUnit::cleanTreeList()
95
{
95
{
96
    QVector<Tree>::iterator last=mTrees.end()-1;
96
    QVector<Tree>::iterator last=mTrees.end()-1;
97
    QVector<Tree>::iterator current = mTrees.begin();
97
    QVector<Tree>::iterator current = mTrees.begin();
98
    while (last>=current && (*last).isDead())
98
    while (last>=current && (*last).isDead())
99
        --last;
99
        --last;
100
100
101
    while (current<last) {
101
    while (current<last) {
102
        if ((*current).isDead()) {
102
        if ((*current).isDead()) {
103
            *current = *last; // copy data!
103
            *current = *last; // copy data!
104
            --last; //
104
            --last; //
105
            while (last>=current && (*last).isDead())
105
            while (last>=current && (*last).isDead())
106
                --last;
106
                --last;
107
        }
107
        }
108
        ++current;
108
        ++current;
109
    }
109
    }
110
    ++last; // last points now to the first dead tree
110
    ++last; // last points now to the first dead tree
111
111
112
    // free ressources
112
    // free ressources
113
    if (last!=mTrees.end()) {
113
    if (last!=mTrees.end()) {
114
        mTrees.erase(last, mTrees.end());
114
        mTrees.erase(last, mTrees.end());
115
        if (mTrees.capacity()>100) {
115
        if (mTrees.capacity()>100) {
116
            if (mTrees.count() / double(mTrees.capacity()) < 0.2) {
116
            if (mTrees.count() / double(mTrees.capacity()) < 0.2) {
117
                int target_size = mTrees.count()*2;
117
                int target_size = mTrees.count()*2;
118
                qDebug() << "reduce size from "<<mTrees.capacity() << "to" << target_size;
118
                qDebug() << "reduce size from "<<mTrees.capacity() << "to" << target_size;
119
                mTrees.reserve(qMax(target_size, 100));
119
                mTrees.reserve(qMax(target_size, 100));
120
            }
120
            }
121
        }
121
        }
122
    }
122
    }
123
}
123
}
124
124
125
void ResourceUnit::newYear()
125
void ResourceUnit::newYear()
126
{
126
{
127
    mAggregatedWLA = 0.;
127
    mAggregatedWLA = 0.;
128
    mAggregatedLA = 0.;
128
    mAggregatedLA = 0.;
129
    mAggregatedLR = 0.;
129
    mAggregatedLR = 0.;
130
    mEffectiveArea = 0.;
130
    mEffectiveArea = 0.;
131
    mPixelCount = mStockedPixelCount = 0;
131
    mPixelCount = mStockedPixelCount = 0;
132
    // clear statistics global and per species...
132
    // clear statistics global and per species...
133
    ResourceUnitSpecies *i;
133
    ResourceUnitSpecies *i;
134
    QVector<ResourceUnitSpecies>::iterator iend = mRUSpecies.end();
134
    QVector<ResourceUnitSpecies>::iterator iend = mRUSpecies.end();
135
    mStatistics.clear();
135
    mStatistics.clear();
136
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
136
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
137
        i->statisticsDead().clear();
137
        i->statisticsDead().clear();
138
        i->statisticsMgmt().clear();
138
        i->statisticsMgmt().clear();
139
    }
139
    }
140
140
141
}
141
}
142
142
143
/** production() is the "stand-level" part of the biomass production (3PG).
143
/** production() is the "stand-level" part of the biomass production (3PG).
144
    - The amount of radiation intercepted by the stand is calculated
144
    - The amount of radiation intercepted by the stand is calculated
145
    - the water cycle is calculated
145
    - the water cycle is calculated
146
    - statistics for each species are cleared
146
    - statistics for each species are cleared
147
    - The 3PG production for each species and ressource unit is called (calculates species-responses and NPP production)
147
    - The 3PG production for each species and ressource unit is called (calculates species-responses and NPP production)
148
    see also: http://iland.boku.ac.at/individual+tree+light+availability */
148
    see also: http://iland.boku.ac.at/individual+tree+light+availability */
149
void ResourceUnit::production()
149
void ResourceUnit::production()
150
{
150
{
151
151
152
    if (mAggregatedWLA==0 || mPixelCount==0) {
152
    if (mAggregatedWLA==0 || mPixelCount==0) {
153
        // nothing to do...
153
        // nothing to do...
154
        return;
154
        return;
155
    }
155
    }
156
156
157
    // the pixel counters are filled during the height-grid-calculations
157
    // the pixel counters are filled during the height-grid-calculations
158
    mStockedArea = 100. * mStockedPixelCount; // m2 (1 height grid pixel = 10x10m)
158
    mStockedArea = 100. * mStockedPixelCount; // m2 (1 height grid pixel = 10x10m)
159
159
160
    // calculate the leaf area index (LAI)
160
    // calculate the leaf area index (LAI)
161
    double LAI = mAggregatedLA / mStockedArea;
161
    double LAI = mAggregatedLA / mStockedArea;
162
    // calculate the intercepted radiation fraction using the law of Beer Lambert
162
    // calculate the intercepted radiation fraction using the law of Beer Lambert
163
    const double k = Model::settings().lightExtinctionCoefficient;
163
    const double k = Model::settings().lightExtinctionCoefficient;
164
    double interception_fraction = 1. - exp(-k * LAI);
164
    double interception_fraction = 1. - exp(-k * LAI);
165
    mEffectiveArea = mStockedArea * interception_fraction; // m2
165
    mEffectiveArea = mStockedArea * interception_fraction; // m2
166
166
167
    // calculate the total weighted leaf area on this RU:
167
    // calculate the total weighted leaf area on this RU:
168
    mLRI_modification = interception_fraction *  mStockedArea / mAggregatedWLA;
168
    mLRI_modification = interception_fraction *  mStockedArea / mAggregatedWLA;
169
    if (mLRI_modification == 0.)
169
    if (mLRI_modification == 0.)
170
        qDebug() << "lri modifaction==0!";
170
        qDebug() << "lri modifaction==0!";
171
171
172
172
173
    DBGMODE(qDebug() << QString("production: LAI: %1 (intercepted fraction: %2, stocked area: %4). LRI-Multiplier: %3")
173
    DBGMODE(qDebug() << QString("production: LAI: %1 (intercepted fraction: %2, stocked area: %4). LRI-Multiplier: %3")
174
            .arg(LAI)
174
            .arg(LAI)
175
            .arg(interception_fraction)
175
            .arg(interception_fraction)
176
            .arg(mLRI_modification)
176
            .arg(mLRI_modification)
177
            .arg(mStockedArea);
177
            .arg(mStockedArea);
178
    );
178
    );
179
179
180
    // calculate LAI fractions
180
    // calculate LAI fractions
181
    ResourceUnitSpecies *i;
181
    ResourceUnitSpecies *i;
182
    QVector<ResourceUnitSpecies>::iterator iend = mRUSpecies.end();
182
    QVector<ResourceUnitSpecies>::iterator iend = mRUSpecies.end();
183
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
183
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
184
         i->setLAIfactor(i->statistics().leafAreaIndex() / leafAreaIndex());
184
         i->setLAIfactor(i->statistics().leafAreaIndex() / leafAreaIndex());
185
    }
185
    }
186
186
187
    // soil water model - this determines soil water contents needed for response calculations
187
    // soil water model - this determines soil water contents needed for response calculations
188
    {
188
    {
189
    DebugTimer tw("water:run");
189
    DebugTimer tw("water:run");
190
    mWater->run();
190
    mWater->run();
191
    }
191
    }
192
192
193
    // invoke species specific calculation (3PG)
193
    // invoke species specific calculation (3PG)
194
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
194
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
195
        i->calculate();
195
        i->calculate();
196
        if (logLevelInfo() &&  i->LAIfactor()>0)
196
        if (logLevelInfo() &&  i->LAIfactor()>0)
197
            qDebug() << "ru" << mIndex << "species" << (*i).species()->id() << "LAIfraction" << i->LAIfactor() << "raw_gpp_m2"
197
            qDebug() << "ru" << mIndex << "species" << (*i).species()->id() << "LAIfraction" << i->LAIfactor() << "raw_gpp_m2"
198
                     << i->prod3PG().GPPperArea() << "area:" << productiveArea() << "gpp:"
198
                     << i->prod3PG().GPPperArea() << "area:" << productiveArea() << "gpp:"
199
                     << productiveArea()*i->prod3PG().GPPperArea()
199
                     << productiveArea()*i->prod3PG().GPPperArea()
200
                     << "aging(lastyear):" << averageAging() << "f_env,yr:" << i->prod3PG().fEnvYear();
200
                     << "aging(lastyear):" << averageAging() << "f_env,yr:" << i->prod3PG().fEnvYear();
201
    }
201
    }
202
}
202
}
203
203
204
void ResourceUnit::calculateInterceptedArea()
204
void ResourceUnit::calculateInterceptedArea()
205
{
205
{
206
    if (mAggregatedLR==0) {
206
    if (mAggregatedLR==0) {
207
        mEffectiveArea_perWLA = 0.;
207
        mEffectiveArea_perWLA = 0.;
208
        return;
208
        return;
209
    }
209
    }
210
    Q_ASSERT(mAggregatedLR>0.);
210
    Q_ASSERT(mAggregatedLR>0.);
211
    mEffectiveArea_perWLA = mEffectiveArea / mAggregatedLR;
211
    mEffectiveArea_perWLA = mEffectiveArea / mAggregatedLR;
212
    if (logLevelDebug()) qDebug() << "RU: aggregated lightresponse:" << mAggregatedLR  << "eff.area./wla:" << mEffectiveArea_perWLA;
212
    if (logLevelDebug()) qDebug() << "RU: aggregated lightresponse:" << mAggregatedLR  << "eff.area./wla:" << mEffectiveArea_perWLA;
213
}
213
}
214
214
215
// function is called immediately before the growth of individuals
215
// function is called immediately before the growth of individuals
216
void ResourceUnit::beforeGrow()
216
void ResourceUnit::beforeGrow()
217
{
217
{
218
    mAverageAging = 0.;
218
    mAverageAging = 0.;
219
}
219
}
220
220
221
// function is called after finishing the indivdual growth / mortality.
221
// function is called after finishing the indivdual growth / mortality.
222
void ResourceUnit::afterGrow()
222
void ResourceUnit::afterGrow()
223
{
223
{
224
    mAverageAging = leafArea()>0.?mAverageAging/leafArea():0; // calculate aging value (calls to addAverageAging() by individual trees)
224
    mAverageAging = leafArea()>0.?mAverageAging/leafArea():0; // calculate aging value (calls to addAverageAging() by individual trees)
225
    if (mAverageAging>0. && mAverageAging<0.00001)
225
    if (mAverageAging>0. && mAverageAging<0.00001)
226
        qDebug() << "ru" << mIndex << "aging <0.00001";
226
        qDebug() << "ru" << mIndex << "aging <0.00001";
227
}
227
}
228
228
229
void ResourceUnit::yearEnd()
229
void ResourceUnit::yearEnd()
230
{
230
{
231
    // calculate statistics for all tree species of the ressource unit
231
    // calculate statistics for all tree species of the ressource unit
232
    int c = mRUSpecies.count();
232
    int c = mRUSpecies.count();
233
    for (int i=0;i<c; i++) {
233
    for (int i=0;i<c; i++) {
234
        mRUSpecies[i].statisticsDead().calculate(); // calculate the dead trees
234
        mRUSpecies[i].statisticsDead().calculate(); // calculate the dead trees
235
        mRUSpecies[i].statisticsMgmt().calculate(); // stats of removed trees
235
        mRUSpecies[i].statisticsMgmt().calculate(); // stats of removed trees
236
        mRUSpecies[i].updateGWL(); // get sum of dead trees (died + removed)
236
        mRUSpecies[i].updateGWL(); // get sum of dead trees (died + removed)
237
        mRUSpecies[i].statistics().calculate(); // calculate the living (and add removed volume to gwl)
237
        mRUSpecies[i].statistics().calculate(); // calculate the living (and add removed volume to gwl)
238
        mStatistics.add(mRUSpecies[i].statistics());
238
        mStatistics.add(mRUSpecies[i].statistics());
239
    }
239
    }
240
    mStatistics.calculate(); // aggreagte on stand level
240
    mStatistics.calculate(); // aggreagte on stand level
241
}
241
}
242
242
243
/// refresh of tree based statistics.
243
/// refresh of tree based statistics.
244
void ResourceUnit::createStandStatistics()
244
void ResourceUnit::createStandStatistics()
245
{
245
{
246
    // clear statistics (ru-level and ru-species level)
246
    // clear statistics (ru-level and ru-species level)
247
    mStatistics.clear();
247
    mStatistics.clear();
248
    for (int i=0;i<mRUSpecies.count();i++) {
248
    for (int i=0;i<mRUSpecies.count();i++) {
249
        mRUSpecies[i].statistics().clear();
249
        mRUSpecies[i].statistics().clear();
250
        mRUSpecies[i].statisticsDead().clear();
250
        mRUSpecies[i].statisticsDead().clear();
251
        mRUSpecies[i].statisticsMgmt().clear();
251
        mRUSpecies[i].statisticsMgmt().clear();
252
    }
252
    }
253
253
254
    // add all trees to the statistics objects of the species
254
    // add all trees to the statistics objects of the species
255
    foreach(const Tree &t, mTrees) {
255
    foreach(const Tree &t, mTrees) {
256
        if (!t.isDead())
256
        if (!t.isDead())
257
            resourceUnitSpecies(t.species()).statistics().add(&t, 0);
257
            resourceUnitSpecies(t.species()).statistics().add(&t, 0);
258
    }
258
    }
259
    // summarize statistics for the whole resource unit
259
    // summarize statistics for the whole resource unit
260
    for (int i=0;i<mRUSpecies.count();i++) {
260
    for (int i=0;i<mRUSpecies.count();i++) {
261
        mRUSpecies[i].statistics().calculate();
261
        mRUSpecies[i].statistics().calculate();
262
        mStatistics.add(mRUSpecies[i].statistics());
262
        mStatistics.add(mRUSpecies[i].statistics());
263
    }
263
    }
264
    mStatistics.calculate();
264
    mStatistics.calculate();
265
    mAverageAging = mStatistics.leafAreaIndex()>0.?mAverageAging / (mStatistics.leafAreaIndex()*area()):0.;
265
    mAverageAging = mStatistics.leafAreaIndex()>0.?mAverageAging / (mStatistics.leafAreaIndex()*area()):0.;
266
}
266
}
-
 
267
-
 
268
void ResourceUnit::setSaplingHeightAt(const QPoint &position, const float height)
-
 
269
{
-
 
270
    Q_ASSERT(mSaplingHeightMap);
-
 
271
    int pixel_index = cPxPerRU*(position.x()-mCornerCoord.x())+(position.y()-mCornerCoord.y());
-
 
272
    if (pixel_index<0 || pixel_index>=cPxPerRU*cPxPerRU)
-
 
273
        qDebug() << "setSaplingHeightAt-Error";
-
 
274
    else
-
 
275
        mSaplingHeightMap[pixel_index]=height;
-
 
276
}
-
 
277
267
 
278