Subversion Repositories public iLand

Rev

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

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