Subversion Repositories public iLand

Rev

Rev 265 | Rev 278 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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