Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
1
 
1062 werner 2
/********************************************************************************************
3
**    iLand - an individual based forest landscape and disturbance model
4
**    http://iland.boku.ac.at
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
6
**
7
**    This program is free software: you can redistribute it and/or modify
8
**    it under the terms of the GNU General Public License as published by
9
**    the Free Software Foundation, either version 3 of the License, or
10
**    (at your option) any later version.
11
**
12
**    This program is distributed in the hope that it will be useful,
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
**    GNU General Public License for more details.
16
**
17
**    You should have received a copy of the GNU General Public License
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************************************/
20
#include "grasscover.h"
21
 
22
#include "globalsettings.h"
1079 werner 23
#include "debugtimer.h"
1062 werner 24
#include "xmlhelper.h"
25
#include "model.h"
26
#include "modelcontroller.h"
27
 
28
GrassCover::GrassCover()
29
{
30
    mLayers = new GrassCoverLayers();
31
    mLayers->setGrid(mGrid, this);
32
    mEnabled = false;
1068 werner 33
    mType = Invalid;
1062 werner 34
}
35
 
36
GrassCover::~GrassCover()
37
{
38
    delete mLayers;
39
}
40
 
41
void GrassCover::setup()
42
{
43
    XmlHelper xml=GlobalSettings::instance()->settings();
44
    if (!xml.valueBool("model.settings.grass.enabled")) {
45
        // clear grid
46
        mGrid.clear();
47
        GlobalSettings::instance()->controller()->removeLayers(mLayers);
48
        mEnabled=false;
49
        qDebug() << "grass module not enabled";
50
        return;
51
    }
52
    // create the grid
53
    mGrid.setup(GlobalSettings::instance()->model()->grid()->metricRect(), GlobalSettings::instance()->model()->grid()->cellsize());
54
    mGrid.wipe();
1082 werner 55
    // mask out out-of-project areas
56
    HeightGrid *hg = GlobalSettings::instance()->model()->heightGrid();
57
    for (int i=0;i<mGrid.count();++i)
58
        if (!hg->valueAtIndex(mGrid.index5(i)).isValid())
59
            mGrid[i] = -1;
1062 werner 60
 
1068 werner 61
    mType = Invalid;
62
    QString type = xml.value("model.settings.grass.type");
63
    if (type == QStringLiteral("pixel"))
64
        mType = Pixel;
1062 werner 65
 
1068 werner 66
    if (type==QStringLiteral("continuous"))
67
        mType = Continuous;
68
 
69
    if (mType == Invalid)
70
        throw IException("GrassCover::setup: invalid 'grass.type'. Allowed: 'continous' and 'pixel'.");
71
 
72
    if (mType == Pixel) {
73
        // setup of pixel based / discrete approach
74
        QString formula = xml.value("model.settings.grass.grassDuration");
75
        if (formula.isEmpty())
76
            throw IException("GrassCover::setup(): missing equation for 'grassDuration'.");
1096 werner 77
        mPDF.setup(formula, 0., 100.);
78
        //mGrassEffect.setExpression(formula);
1079 werner 79
 
1096 werner 80
        mGrassLIFThreshold = static_cast<float>( xml.valueDouble("model.settings.grass.LIFThreshold", 0.2) );
1068 werner 81
 
82
        // clear array
1099 werner 83
        for (int i=0;i<GRASSCOVERSTEPS;++i) {
1068 werner 84
            mEffect[i] = 0.;
85
        }
86
 
87
    } else {
88
 
89
        // setup of continuous grass concept
90
 
91
        QString formula = xml.value("model.settings.grass.grassPotential");
92
        if (formula.isEmpty())
93
            throw IException("setup of 'grass': required expression 'grassPotential' is missing.");
94
        mGrassPotential.setExpression(formula);
1099 werner 95
        mGrassPotential.linearize(0.,1., qMin(GRASSCOVERSTEPS, 1000));
1068 werner 96
 
97
        formula = xml.value("model.settings.grass.grassEffect");
98
        if (formula.isEmpty())
99
            throw IException("setup of 'grass': required expression 'grassEffect' is missing.");
100
        mGrassEffect.setExpression(formula);
1096 werner 101
        mMaxTimeLag = static_cast<int>( xml.valueDouble("model.settings.grass.maxTimeLag") );
1068 werner 102
        if (mMaxTimeLag==0)
103
            throw IException("setup of 'grass': value of 'maxTimeLag' is invalid or missing.");
1099 werner 104
        mGrowthRate = GRASSCOVERSTEPS / mMaxTimeLag;
1068 werner 105
 
106
        // set up the effect on regeneration in NSTEPS steps
1099 werner 107
        for (int i=0;i<GRASSCOVERSTEPS;++i) {
108
            double effect = mGrassEffect.calculate(i/double(GRASSCOVERSTEPS-1));
1068 werner 109
            mEffect[i] = limit(effect, 0., 1.);
110
        }
111
 
1099 werner 112
        mMaxState = static_cast<qint16>( limit(mGrassPotential.calculate(1.f), 0., 1.)*(GRASSCOVERSTEPS-1)  ); // the max value of the potential function
1062 werner 113
    }
114
 
115
    GlobalSettings::instance()->controller()->addLayers(mLayers, QStringLiteral("grass cover"));
116
    mEnabled = true;
117
    qDebug() << "setup of grass cover complete.";
118
 
119
}
120
 
121
void GrassCover::setInitialValues(const QVector<float *> &LIFpixels, const int percent)
122
{
123
    if (!enabled())
124
        return;
1068 werner 125
    if (mType == Continuous) {
1099 werner 126
        grass_grid_type cval = static_cast<grass_grid_type>( limit(percent / 100., 0., 1.)*(GRASSCOVERSTEPS-1) );
1068 werner 127
        if (cval > mMaxState)
128
            cval = mMaxState;
1064 werner 129
 
1068 werner 130
        Grid<float> *lif_grid = GlobalSettings::instance()->model()->grid();
131
        for (QVector<float *>::const_iterator it = LIFpixels.constBegin(); it!=LIFpixels.constEnd(); ++it)
132
            mGrid.valueAtIndex(lif_grid->indexOf(*it)) = cval;
133
    } else {
134
        // mType == Pixel
135
        Grid<float> *lif_grid = GlobalSettings::instance()->model()->grid();
136
        for (QVector<float *>::const_iterator it = LIFpixels.constBegin(); it!=LIFpixels.constEnd(); ++it) {
137
            if (percent > irandom(0,100))
1096 werner 138
                mGrid.valueAtIndex(lif_grid->indexOf(*it)) = static_cast<qint16>( mPDF.get() );
1068 werner 139
            else
140
                mGrid.valueAtIndex(lif_grid->indexOf(*it)) = 0;
141
        }
142
 
143
    }
1062 werner 144
}
145
 
146
void GrassCover::execute()
147
{
148
    if (!enabled())
149
        return;
150
 
1079 werner 151
    DebugTimer t("GrassCover");
152
 
1062 werner 153
    // Main function of the grass submodule
154
    float *lif = GlobalSettings::instance()->model()->grid()->begin();
155
    float *end_lif = GlobalSettings::instance()->model()->grid()->end();
1068 werner 156
    grass_grid_type *gr = mGrid.begin();
1062 werner 157
 
1068 werner 158
    if (mType == Continuous) {
159
        // loop over every LIF pixel
160
        int skipped=0;
161
        for (; lif!=end_lif;++lif, ++gr) {
162
            // calculate potential grass vegetation cover
163
            if (*lif == 1.f && *gr==mMaxState) {
164
                ++skipped;
165
                continue;
166
            }
167
 
1099 werner 168
            int potential = static_cast<int>( limit(mGrassPotential.calculate(*lif), 0., 1.)*(GRASSCOVERSTEPS-1) );
1096 werner 169
            *gr = static_cast<qint16>( qMin( int(*gr) + mGrowthRate, potential) );
1068 werner 170
 
1064 werner 171
        }
1068 werner 172
        //qDebug() << "skipped" << skipped;
173
    } else {
174
        // type = Pixel
175
        for (; lif!=end_lif;++lif, ++gr) {
1082 werner 176
            if (*gr<0)
177
                continue;
1096 werner 178
            if (*gr>1)
179
                (*gr)--; // count down the years (until gr=1)
1062 werner 180
 
1068 werner 181
            if (*gr==0 && *lif>mGrassLIFThreshold) {
182
                // enable grass cover
1096 werner 183
                qint16 v = static_cast<qint16>( qMax(mPDF.get(), 0.) );
184
                *gr = v + 1; // switch on...
1068 werner 185
            }
186
            if (*gr==1 && *lif<mGrassLIFThreshold) {
1096 werner 187
                // now LIF is below the threshold - this enables the pixel get grassy again
1068 werner 188
                *gr = 0;
189
            }
190
        }
1062 werner 191
    }
192
 
193
}
194
 
195
 
196
 
1068 werner 197
double GrassCoverLayers::value(const grass_grid_type &data, const int index) const
1062 werner 198
{
199
    if (!mGrassCover->enabled()) return 0.;
200
    switch(index){
201
    case 0: return mGrassCover->effect(data); //effect
1068 werner 202
    case 1: return mGrassCover->cover(data); // cover
1062 werner 203
    default: throw IException(QString("invalid variable index for a GrassCoverLayers: %1").arg(index));
204
    }
205
}
206
 
207
const QVector<LayeredGridBase::LayerElement> &GrassCoverLayers::names()
208
{
209
    if (mNames.isEmpty())
210
        mNames = QVector<LayeredGridBase::LayerElement>()
211
                << LayeredGridBase::LayerElement(QLatin1Literal("effect"), QLatin1Literal("prohibiting effect on regeneration [0..1]"), GridViewGreens)
1073 werner 212
                << LayeredGridBase::LayerElement(QLatin1Literal("cover"), QLatin1Literal("current grass cover on pixels [0..1 for continuous, or #(years+2) for pixel mode]"), GridViewGreens);
1062 werner 213
    return mNames;
214
 
215
}