Subversion Repositories public iLand

Rev

Rev 215 | Rev 229 | 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"
111 Werner 11
#include "speciesset.h"
12
#include "species.h"
113 Werner 13
#include "production3pg.h"
200 werner 14
#include "model.h"
208 werner 15
#include "climate.h"
92 Werner 16
 
111 Werner 17
 
189 iland 18
ResourceUnit::ResourceUnit(const int index)
92 Werner 19
{
94 Werner 20
    mSpeciesSet = 0;
208 werner 21
    mClimate = 0;
113 Werner 22
    mIndex = index;
157 werner 23
    mTrees.reserve(100); // start with space for 100 trees.
92 Werner 24
}
105 Werner 25
 
111 Werner 26
/// set species and setup the species-per-RU-data
189 iland 27
void ResourceUnit::setSpeciesSet(SpeciesSet *set)
111 Werner 28
{
29
    mSpeciesSet = set;
30
    mRUSpecies.clear();
31
    for (int i=0;i<set->count();i++) {
32
        Species *s = const_cast<Species*>(mSpeciesSet->species(i));
33
        if (!s)
189 iland 34
            throw IException("ResourceUnit::setSpeciesSet: invalid index!");
35
        ResourceUnitSpecies rus(s, this);
111 Werner 36
        mRUSpecies.append(rus);
37
    }
38
}
39
 
200 werner 40
ResourceUnitSpecies &ResourceUnit::resourceUnitSpecies(const Species *species)
111 Werner 41
{
42
    return mRUSpecies[species->index()];
43
}
44
 
189 iland 45
Tree &ResourceUnit::newTree()
105 Werner 46
{
47
    // start simple: just append to the vector...
48
    mTrees.append(Tree());
49
    return mTrees.back();
50
}
107 Werner 51
 
157 werner 52
/// remove dead trees from tree list
53
/// reduce size of vector if lots of space is free
54
/// tests showed that this way of cleanup is very fast,
55
/// because no memory allocations are performed (simple memmove())
56
/// when trees are moved.
189 iland 57
void ResourceUnit::cleanTreeList()
157 werner 58
{
59
    QVector<Tree>::iterator last=mTrees.end()-1;
60
    QVector<Tree>::iterator current = mTrees.begin();
158 werner 61
    while (last>=current && (*last).isDead())
157 werner 62
        --last;
107 Werner 63
 
157 werner 64
    while (current<last) {
158 werner 65
        if ((*current).isDead()) {
157 werner 66
            *current = *last; // copy data!
67
            --last; //
158 werner 68
            while (last>=current && (*last).isDead())
157 werner 69
                --last;
70
        }
71
        ++current;
72
    }
73
    ++last; // last points now to the first dead tree
74
 
75
    // free ressources
76
    mTrees.erase(last, mTrees.end());
77
    if (mTrees.capacity()>100) {
78
        if (mTrees.count() / double(mTrees.capacity()) < 0.2) {
79
            int target_size = mTrees.count()*2;
80
            qDebug() << "reduce size from "<<mTrees.capacity() << "to" << target_size;
81
            mTrees.reserve(qMax(target_size, 100));
82
        }
83
    }
84
}
85
 
189 iland 86
void ResourceUnit::newYear()
107 Werner 87
{
88
    mAggregatedWLA = 0.f;
110 Werner 89
    mAggregatedLA = 0.f;
151 iland 90
    mPixelCount = mStockedPixelCount = 0;
111 Werner 91
    // clear statistics global and per species...
107 Werner 92
}
110 Werner 93
 
112 Werner 94
/** production() is the "stand-level" part of the biomass production (3PG).
95
    - The amount of radiation intercepted by the stand is calculated
96
    - The 3PG production for each species and ressource unit is invoked  */
189 iland 97
void ResourceUnit::production()
110 Werner 98
{
180 werner 99
    mStatistics.clear();
151 iland 100
    if (mAggregatedWLA==0 || mPixelCount==0) {
112 Werner 101
        // nothing to do...
102
        return;
103
    }
151 iland 104
 
105
    // the pixel counters are filled during the height-grid-calculations
215 werner 106
    mStockedArea = 100. * mStockedPixelCount; // m2
107
    //double stocked_fraction = mStockedPixelCount/double(mPixelCount);
112 Werner 108
    // calculate the leaf area index (LAI)
151 iland 109
    double LAI = mAggregatedLA / mStockedArea;
112 Werner 110
    // calculate the intercepted radiation fraction using the law of Beer Lambert
200 werner 111
    const double k = Model::settings().lightExtinctionCoefficient;
112 Werner 112
    double interception_fraction = 1. - exp(-k * LAI);
113
    // calculate the amount of radiation available on this ressource unit
147 werner 114
    mRadiation_m2 = 3140; // incoming radiation sum of year in MJ/m2*year
112 Werner 115
 
215 werner 116
    mRadiation_perWLA = interception_fraction *  mRadiation_m2 / mAggregatedWLA;
205 werner 117
 
215 werner 118
    DBGMODE(qDebug() << QString("production: LAI: %1 avg. WLA: %4 intercepted-fraction: %2 radiation per WLA: %3 stocked area: %4")
119
            .arg(LAI).arg(interception_fraction).arg(mRadiation_perWLA).arg(mStockedArea); );
112 Werner 120
 
121
    // invoke species specific calculation (3PG)
189 iland 122
    QVector<ResourceUnitSpecies>::iterator i;
123
    QVector<ResourceUnitSpecies>::iterator iend = mRUSpecies.end();
113 Werner 124
 
112 Werner 125
    for (i=mRUSpecies.begin(); i!=iend; ++i) {
226 werner 126
        (*i).calculate();
180 werner 127
        (*i).statistics().clear();
113 Werner 128
//        qDebug() << "species" << (*i).species()->id() << "raw_gpp_per_rad" << raw_gpp_per_rad;
112 Werner 129
    }
110 Werner 130
}
131
 
189 iland 132
void ResourceUnit::yearEnd()
180 werner 133
{
134
    // calculate statistics for all tree species of the ressource unit
135
    int c = mRUSpecies.count();
136
    for (int i=0;i<c; i++) {
137
        mRUSpecies[i].statistics().calculate();
138
        mStatistics.add(mRUSpecies[i].statistics());
139
    }
140
    mStatistics.calculate(); // aggreagte on stand level
141
}
142