Subversion Repositories public iLand

Rev

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

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