Subversion Repositories public iLand

Rev

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

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