Rev 1064 | Rev 1073 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1064 | Rev 1068 | ||
---|---|---|---|
Line 27... | Line 27... | ||
27 | GrassCover::GrassCover() |
27 | GrassCover::GrassCover() |
28 | {
|
28 | {
|
29 | mLayers = new GrassCoverLayers(); |
29 | mLayers = new GrassCoverLayers(); |
30 | mLayers->setGrid(mGrid, this); |
30 | mLayers->setGrid(mGrid, this); |
31 | mEnabled = false; |
31 | mEnabled = false; |
- | 32 | mType = Invalid; |
|
32 | }
|
33 | }
|
33 | 34 | ||
34 | GrassCover::~GrassCover() |
35 | GrassCover::~GrassCover() |
35 | {
|
36 | {
|
36 | delete mLayers; |
37 | delete mLayers; |
Line 48... | Line 49... | ||
48 | return; |
49 | return; |
49 | }
|
50 | }
|
50 | // create the grid
|
51 | // create the grid
|
51 | mGrid.setup(GlobalSettings::instance()->model()->grid()->metricRect(), GlobalSettings::instance()->model()->grid()->cellsize()); |
52 | mGrid.setup(GlobalSettings::instance()->model()->grid()->metricRect(), GlobalSettings::instance()->model()->grid()->cellsize()); |
52 | mGrid.wipe(); |
53 | mGrid.wipe(); |
53 | QString formula = xml.value("model.settings.grass.grassPotential"); |
- | |
54 | if (formula.isEmpty()) |
- | |
55 | throw IException("setup of 'grass': required expression 'grassPotential' is missing."); |
- | |
56 | mGrassPotential.setExpression(formula); |
- | |
57 | mGrassPotential.linearize(0.,1., qMin(GRASSCOVERSTEPS, 1000)); |
- | |
58 | 54 | ||
59 | formula = xml.value("model.settings.grass.grassEffect"); |
- | |
60 | if (formula.isEmpty()) |
- | |
61 | throw IException("setup of 'grass': required expression 'grassEffect' is missing."); |
- | |
62 | mGrassEffect.setExpression(formula); |
- | |
63 | mMaxTimeLag = xml.valueDouble("model.settings.grass.maxTimeLag"); |
- | |
64 | if (mMaxTimeLag==0) |
- | |
65 | throw IException("setup of 'grass': value of 'maxTimeLag' is invalid or missing."); |
- | |
66 | mGrowthRate = GRASSCOVERSTEPS / mMaxTimeLag; |
- | |
- | 55 | mType = Invalid; |
|
- | 56 | QString type = xml.value("model.settings.grass.type"); |
|
- | 57 | if (type == QStringLiteral("pixel")) |
|
- | 58 | mType = Pixel; |
|
67 | 59 | ||
68 | // set up the effect on regeneration in NSTEPS steps
|
- | |
69 | for (int i=0;i<GRASSCOVERSTEPS;++i) { |
- | |
70 | double effect = mGrassEffect.calculate(i/double(GRASSCOVERSTEPS-1)); |
- | |
71 | mEffect[i] = limit(effect, 0., 1.); |
- | |
72 | }
|
- | |
- | 60 | if (type==QStringLiteral("continuous")) |
|
- | 61 | mType = Continuous; |
|
73 | 62 | ||
74 | mMaxState = limit(mGrassPotential.calculate(1.f), 0., 1.)*(GRASSCOVERSTEPS-1); // the max value of the potential function |
- | |
- | 63 | if (mType == Invalid) |
|
- | 64 | throw IException("GrassCover::setup: invalid 'grass.type'. Allowed: 'continous' and 'pixel'."); |
|
- | 65 | ||
- | 66 | if (mType == Pixel) { |
|
- | 67 | // setup of pixel based / discrete approach
|
|
- | 68 | QString formula = xml.value("model.settings.grass.grassDuration"); |
|
- | 69 | if (formula.isEmpty()) |
|
- | 70 | throw IException("GrassCover::setup(): missing equation for 'grassDuration'."); |
|
- | 71 | mPDF.setup(formula, 0., 100.); |
|
- | 72 | mGrassLIFThreshold = xml.valueDouble("model.settings.grass.LIFThreshold", 0.2); |
|
- | 73 | ||
- | 74 | // clear array
|
|
- | 75 | for (int i=0;i<GRASSCOVERSTEPS;++i) { |
|
- | 76 | mEffect[i] = 0.; |
|
- | 77 | }
|
|
- | 78 | ||
- | 79 | } else { |
|
- | 80 | ||
- | 81 | // setup of continuous grass concept
|
|
- | 82 | ||
- | 83 | QString formula = xml.value("model.settings.grass.grassPotential"); |
|
- | 84 | if (formula.isEmpty()) |
|
- | 85 | throw IException("setup of 'grass': required expression 'grassPotential' is missing."); |
|
- | 86 | mGrassPotential.setExpression(formula); |
|
- | 87 | mGrassPotential.linearize(0.,1., qMin(GRASSCOVERSTEPS, 1000)); |
|
- | 88 | ||
- | 89 | formula = xml.value("model.settings.grass.grassEffect"); |
|
- | 90 | if (formula.isEmpty()) |
|
- | 91 | throw IException("setup of 'grass': required expression 'grassEffect' is missing."); |
|
- | 92 | mGrassEffect.setExpression(formula); |
|
- | 93 | mMaxTimeLag = xml.valueDouble("model.settings.grass.maxTimeLag"); |
|
- | 94 | if (mMaxTimeLag==0) |
|
- | 95 | throw IException("setup of 'grass': value of 'maxTimeLag' is invalid or missing."); |
|
- | 96 | mGrowthRate = GRASSCOVERSTEPS / mMaxTimeLag; |
|
- | 97 | ||
- | 98 | // set up the effect on regeneration in NSTEPS steps
|
|
- | 99 | for (int i=0;i<GRASSCOVERSTEPS;++i) { |
|
- | 100 | double effect = mGrassEffect.calculate(i/double(GRASSCOVERSTEPS-1)); |
|
- | 101 | mEffect[i] = limit(effect, 0., 1.); |
|
- | 102 | }
|
|
- | 103 | ||
- | 104 | mMaxState = limit(mGrassPotential.calculate(1.f), 0., 1.)*(GRASSCOVERSTEPS-1); // the max value of the potential function |
|
- | 105 | }
|
|
75 | 106 | ||
76 | GlobalSettings::instance()->controller()->addLayers(mLayers, QStringLiteral("grass cover")); |
107 | GlobalSettings::instance()->controller()->addLayers(mLayers, QStringLiteral("grass cover")); |
77 | mEnabled = true; |
108 | mEnabled = true; |
78 | qDebug() << "setup of grass cover complete."; |
109 | qDebug() << "setup of grass cover complete."; |
79 | 110 | ||
Line 81... | Line 112... | ||
81 | 112 | ||
82 | void GrassCover::setInitialValues(const QVector<float *> &LIFpixels, const int percent) |
113 | void GrassCover::setInitialValues(const QVector<float *> &LIFpixels, const int percent) |
83 | {
|
114 | {
|
84 | if (!enabled()) |
115 | if (!enabled()) |
85 | return; |
116 | return; |
86 | grid_type cval = limit(percent / 100., 0., 1.)*(GRASSCOVERSTEPS-1); |
- | |
87 | if (cval > mMaxState) |
- | |
88 | cval = mMaxState; |
- | |
- | 117 | if (mType == Continuous) { |
|
- | 118 | grass_grid_type cval = limit(percent / 100., 0., 1.)*(GRASSCOVERSTEPS-1); |
|
- | 119 | if (cval > mMaxState) |
|
- | 120 | cval = mMaxState; |
|
89 | 121 | ||
90 | Grid<float> *lif_grid = GlobalSettings::instance()->model()->grid(); |
- | |
91 | for (QVector<float *>::const_iterator it = LIFpixels.constBegin(); it!=LIFpixels.constEnd(); ++it) |
- | |
92 | mGrid.valueAtIndex(lif_grid->indexOf(*it)) = cval; |
- | |
- | 122 | Grid<float> *lif_grid = GlobalSettings::instance()->model()->grid(); |
|
- | 123 | for (QVector<float *>::const_iterator it = LIFpixels.constBegin(); it!=LIFpixels.constEnd(); ++it) |
|
- | 124 | mGrid.valueAtIndex(lif_grid->indexOf(*it)) = cval; |
|
- | 125 | } else { |
|
- | 126 | // mType == Pixel
|
|
- | 127 | Grid<float> *lif_grid = GlobalSettings::instance()->model()->grid(); |
|
- | 128 | for (QVector<float *>::const_iterator it = LIFpixels.constBegin(); it!=LIFpixels.constEnd(); ++it) { |
|
- | 129 | if (percent > irandom(0,100)) |
|
- | 130 | mGrid.valueAtIndex(lif_grid->indexOf(*it)) = mPDF.get(); |
|
- | 131 | else
|
|
- | 132 | mGrid.valueAtIndex(lif_grid->indexOf(*it)) = 0; |
|
- | 133 | }
|
|
- | 134 | ||
- | 135 | }
|
|
93 | }
|
136 | }
|
94 | 137 | ||
95 | void GrassCover::execute() |
138 | void GrassCover::execute() |
96 | {
|
139 | {
|
97 | if (!enabled()) |
140 | if (!enabled()) |
98 | return; |
141 | return; |
99 | 142 | ||
100 | // Main function of the grass submodule
|
143 | // Main function of the grass submodule
|
101 | float *lif = GlobalSettings::instance()->model()->grid()->begin(); |
144 | float *lif = GlobalSettings::instance()->model()->grid()->begin(); |
102 | float *end_lif = GlobalSettings::instance()->model()->grid()->end(); |
145 | float *end_lif = GlobalSettings::instance()->model()->grid()->end(); |
103 | grid_type *gr = mGrid.begin(); |
- | |
- | 146 | grass_grid_type *gr = mGrid.begin(); |
|
104 | 147 | ||
105 | // loop over every LIF pixel
|
- | |
106 | int skipped=0; |
- | |
107 | for (; lif!=end_lif;++lif, ++gr) { |
- | |
108 | // calculate potential grass vegetation cover
|
- | |
109 | if (*lif == 1.f && *gr==mMaxState) { |
- | |
110 | ++skipped; |
- | |
111 | continue; |
- | |
112 | }
|
- | |
- | 148 | if (mType == Continuous) { |
|
- | 149 | // loop over every LIF pixel
|
|
- | 150 | int skipped=0; |
|
- | 151 | for (; lif!=end_lif;++lif, ++gr) { |
|
- | 152 | // calculate potential grass vegetation cover
|
|
- | 153 | if (*lif == 1.f && *gr==mMaxState) { |
|
- | 154 | ++skipped; |
|
- | 155 | continue; |
|
- | 156 | }
|
|
113 | 157 | ||
114 | int potential = limit(mGrassPotential.calculate(*lif), 0., 1.)*(GRASSCOVERSTEPS-1); |
- | |
115 | *gr = qMin( int(*gr) + mGrowthRate, potential); |
- | |
- | 158 | int potential = limit(mGrassPotential.calculate(*lif), 0., 1.)*(GRASSCOVERSTEPS-1); |
|
- | 159 | *gr = qMin( int(*gr) + mGrowthRate, potential); |
|
116 | 160 | ||
- | 161 | }
|
|
- | 162 | //qDebug() << "skipped" << skipped;
|
|
- | 163 | } else { |
|
- | 164 | // type = Pixel
|
|
- | 165 | for (; lif!=end_lif;++lif, ++gr) { |
|
- | 166 | if (*gr>1) |
|
- | 167 | (*gr)--; // count down the years (until gr=1) |
|
- | 168 | ||
- | 169 | if (*gr==0 && *lif>mGrassLIFThreshold) { |
|
- | 170 | // enable grass cover
|
|
- | 171 | double v = qMax(mPDF.get(), 0.); |
|
- | 172 | *gr = v + 1; |
|
- | 173 | }
|
|
- | 174 | if (*gr==1 && *lif<mGrassLIFThreshold) { |
|
- | 175 | // now LIF is below the threshold - this enables the pixel get grassy again
|
|
- | 176 | *gr = 0; |
|
- | 177 | }
|
|
- | 178 | }
|
|
117 | }
|
179 | }
|
118 | qDebug() << "skipped" << skipped; |
- | |
119 | 180 | ||
120 | }
|
181 | }
|
121 | 182 | ||
122 | 183 | ||
123 | 184 | ||
124 | double GrassCoverLayers::value(const grid_type &data, const int index) const |
- | |
- | 185 | double GrassCoverLayers::value(const grass_grid_type &data, const int index) const |
|
125 | {
|
186 | {
|
126 | if (!mGrassCover->enabled()) return 0.; |
187 | if (!mGrassCover->enabled()) return 0.; |
127 | switch(index){ |
188 | switch(index){ |
128 | case 0: return mGrassCover->effect(data); //effect |
189 | case 0: return mGrassCover->effect(data); //effect |
129 | case 1: return data/double(GRASSCOVERSTEPS-1); // state |
- | |
- | 190 | case 1: return mGrassCover->cover(data); // cover |
|
130 | default: throw IException(QString("invalid variable index for a GrassCoverLayers: %1").arg(index)); |
191 | default: throw IException(QString("invalid variable index for a GrassCoverLayers: %1").arg(index)); |
131 | }
|
192 | }
|
132 | }
|
193 | }
|
133 | 194 | ||
134 | const QVector<LayeredGridBase::LayerElement> &GrassCoverLayers::names() |
195 | const QVector<LayeredGridBase::LayerElement> &GrassCoverLayers::names() |
135 | {
|
196 | {
|
136 | if (mNames.isEmpty()) |
197 | if (mNames.isEmpty()) |
137 | mNames = QVector<LayeredGridBase::LayerElement>() |
198 | mNames = QVector<LayeredGridBase::LayerElement>() |
138 | << LayeredGridBase::LayerElement(QLatin1Literal("effect"), QLatin1Literal("prohibiting effect on regeneration [0..1]"), GridViewGreens) |
199 | << LayeredGridBase::LayerElement(QLatin1Literal("effect"), QLatin1Literal("prohibiting effect on regeneration [0..1]"), GridViewGreens) |
139 | << LayeredGridBase::LayerElement(QLatin1Literal("cover"), QLatin1Literal("current grass cover on pixels [0..1]"), GridViewGreens); |
- | |
- | 200 | << LayeredGridBase::LayerElement(QLatin1Literal("cover"), QLatin1Literal("current grass cover on pixels [0..1 for continuous, or #years for pixel mode]"), GridViewGreens); |
|
140 | return mNames; |
201 | return mNames; |
141 | 202 | ||
142 | }
|
203 | }
|