Subversion Repositories public iLand

Rev

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

Rev 753 Rev 767
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/management.cpp':
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/management.cpp':
2
/********************************************************************************************
2
/********************************************************************************************
3
**    iLand - an individual based forest landscape and disturbance model
3
**    iLand - an individual based forest landscape and disturbance model
4
**    http://iland.boku.ac.at
4
**    http://iland.boku.ac.at
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
6
**
6
**
7
**    This program is free software: you can redistribute it and/or modify
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
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
9
**    the Free Software Foundation, either version 3 of the License, or
10
**    (at your option) any later version.
10
**    (at your option) any later version.
11
**
11
**
12
**    This program is distributed in the hope that it will be useful,
12
**    This program is distributed in the hope that it will be useful,
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
**    GNU General Public License for more details.
15
**    GNU General Public License for more details.
16
**
16
**
17
**    You should have received a copy of the GNU General Public License
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/>.
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************************************/
19
********************************************************************************************/
20
20
21
#include "global.h"
21
#include "global.h"
22
#include "management.h"
22
#include "management.h"
23
#include "helper.h"
23
#include "helper.h"
24
#include "model.h"
24
#include "model.h"
25
#include "resourceunit.h"
25
#include "resourceunit.h"
26
#include "tree.h"
26
#include "tree.h"
27
#include "expressionwrapper.h"
27
#include "expressionwrapper.h"
28
#include "sapling.h"
28
#include "sapling.h"
29
#include "soil.h"
29
#include "soil.h"
30
30
31
#include "climateconverter.h"
-
 
32
#include "csvfile.h"
-
 
-
 
31
//#include "climateconverter.h"
-
 
32
//#include "csvfile.h"
33
#include "scriptglobal.h"
33
#include "scriptglobal.h"
34
#include "mapgrid.h"
34
#include "mapgrid.h"
35
#include "modules.h"
-
 
-
 
35
//#include "modules.h"
36
36
37
#include <QtScript>
37
#include <QtScript>
38
#include <QTextEdit>
-
 
39
QObject *Management::scriptOutput = 0;
-
 
40
38
41
/** @class Management Management executes management routines.
39
/** @class Management Management executes management routines.
42
  @ingroup core
40
  @ingroup core
43
  The actual iLand management is based on Javascript functions. This class provides
41
  The actual iLand management is based on Javascript functions. This class provides
44
  the frame for executing the javascript as well as the functions that are called by scripts and
42
  the frame for executing the javascript as well as the functions that are called by scripts and
45
  that really do the work.
43
  that really do the work.
46
  See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
44
  See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
47
  */
45
  */
48
46
49
QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng)
-
 
50
{
-
 
51
    QString value;
-
 
52
    for (int i = 0; i < ctx->argumentCount(); ++i) {
-
 
53
        if (i > 0)
-
 
54
            value.append(" ");
-
 
55
        value.append(ctx->argument(i).toString());
-
 
56
    }
-
 
57
    if (Management::scriptOutput) {
-
 
58
        QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput);
-
 
59
        if (e)
-
 
60
            e->append(value);
-
 
61
    } else {
-
 
62
        qDebug() << "Script:" << value;
-
 
63
    }
-
 
64
    return eng->undefinedValue();
-
 
65
}
-
 
66
47
67
QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng)
-
 
68
{
-
 
69
-
 
70
    QString fileName = ctx->argument(0).toString();
-
 
71
    QString path =GlobalSettings::instance()->path(fileName, "script") ;
-
 
72
    QString includeFile=Helper::loadTextFile(path);
-
 
73
-
 
74
    ctx->setActivationObject(ctx->parentContext()->activationObject());
-
 
75
    ctx->setThisObject(ctx->parentContext()->thisObject());
-
 
76
-
 
77
    QScriptValue ret = eng->evaluate(includeFile, fileName);
-
 
78
    if (eng->hasUncaughtException())
-
 
79
        qDebug() << "Error in include:" << eng->uncaughtException().toString();
-
 
80
    return ret;
-
 
81
}
-
 
82
-
 
83
QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng)
-
 
84
{
-
 
85
    QString value = ctx->argument(0).toString();
-
 
86
    Helper::msg(value);
-
 
87
    return eng->undefinedValue();
-
 
88
}
-
 
89
// global output function
48
// global output function
90
QString Management::executeScript(QString cmd)
49
QString Management::executeScript(QString cmd)
91
{
50
{
92
    DebugTimer t("execute javascript");
-
 
93
    if (mEngine)
-
 
94
        mEngine->evaluate(cmd);
-
 
95
    if (mEngine->hasUncaughtException()) {
-
 
96
        //int line = mEngine->uncaughtExceptionLineNumber();
-
 
97
        QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString());
-
 
98
        msg+=mEngine->uncaughtExceptionBacktrace().join("\n");
-
 
99
        return msg;
-
 
100
    } else {
-
 
101
        return QString();
-
 
102
    }
-
 
-
 
51
    return ScriptGlobal::executeScript(cmd);
103
}
52
}
104
53
105
Management::Management()
54
Management::Management()
106
{
55
{
107
    // setup the scripting engine
56
    // setup the scripting engine
108
    mEngine = new QScriptEngine();
-
 
-
 
57
    mEngine = GlobalSettings::instance()->scriptEngine();
109
    QScriptValue objectValue = mEngine->newQObject(this);
58
    QScriptValue objectValue = mEngine->newQObject(this);
110
    QScriptValue dbgprint = mEngine->newFunction(script_debug);
-
 
111
    QScriptValue sinclude = mEngine->newFunction(script_include);
-
 
112
    QScriptValue alert = mEngine->newFunction(script_alert);
-
 
113
    mEngine->globalObject().setProperty("management", objectValue);
59
    mEngine->globalObject().setProperty("management", objectValue);
114
    mEngine->globalObject().setProperty("print",dbgprint);
-
 
115
    mEngine->globalObject().setProperty("include",sinclude);
-
 
116
    mEngine->globalObject().setProperty("alert", alert);
-
 
117
-
 
118
    // globals object: instatiate here, but ownership goes to script engine
-
 
119
    ScriptGlobal *global = new ScriptGlobal();
-
 
120
    QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership);
-
 
121
    mEngine->globalObject().setProperty("Globals", glb);
-
 
122
    // other object types
-
 
123
    ClimateConverter::addToScriptEngine(*mEngine);
-
 
124
    CSVFile::addToScriptEngine(*mEngine);
-
 
125
    MapGridWrapper::addToScriptEngine(*mEngine);
-
 
126
    // setup scripting for modules
-
 
127
    GlobalSettings::instance()->model()->modules()->setupScripting(mEngine);
-
 
128
60
129
    // default values for removal fractions
61
    // default values for removal fractions
130
    // 100% of the stem, 0% of foliage and branches
62
    // 100% of the stem, 0% of foliage and branches
131
    mRemoveFoliage = 0.;
63
    mRemoveFoliage = 0.;
132
    mRemoveBranch = 0.;
64
    mRemoveBranch = 0.;
133
    mRemoveStem = 1.;
65
    mRemoveStem = 1.;
134
-
 
135
66
136
}
67
}
137
68
138
Management::~Management()
69
Management::~Management()
139
{
70
{
140
    delete mEngine;
-
 
141
}
71
}
142
72
143
void Management::loadScript(const QString &fileName)
-
 
144
{
-
 
145
    mScriptFile = fileName;
-
 
146
    QString program = Helper::loadTextFile(fileName);
-
 
147
    if (program.isEmpty())
-
 
148
        return;
-
 
149
-
 
150
    mEngine->evaluate(program);
-
 
151
    qDebug() << "management script loaded";
-
 
152
    if (mEngine->hasUncaughtException())
-
 
153
        qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace();
-
 
154
-
 
155
}
-
 
156
73
157
int Management::remain(int number)
74
int Management::remain(int number)
158
{
75
{
159
    qDebug() << "remain called (number): " << number;
76
    qDebug() << "remain called (number): " << number;
160
    Model *m = GlobalSettings::instance()->model();
77
    Model *m = GlobalSettings::instance()->model();
161
    AllTreeIterator at(m);
78
    AllTreeIterator at(m);
162
    QList<Tree*> trees;
79
    QList<Tree*> trees;
163
    while (Tree *t=at.next())
80
    while (Tree *t=at.next())
164
        trees.push_back(t);
81
        trees.push_back(t);
165
    int to_kill = trees.count() - number;
82
    int to_kill = trees.count() - number;
166
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
83
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
167
    for (int i=0;i<to_kill;i++) {
84
    for (int i=0;i<to_kill;i++) {
168
        int index = irandom(0, trees.count()-1);
85
        int index = irandom(0, trees.count()-1);
169
        trees[index]->remove();
86
        trees[index]->remove();
170
        trees.removeAt(index);
87
        trees.removeAt(index);
171
    }
88
    }
172
    mRemoved += to_kill;
89
    mRemoved += to_kill;
173
    return to_kill;
90
    return to_kill;
174
}
91
}
175
92
176
93
177
int Management::kill()
94
int Management::kill()
178
{
95
{
179
    int c = mTrees.count();
96
    int c = mTrees.count();
180
    for (int i=0;i<mTrees.count();i++)
97
    for (int i=0;i<mTrees.count();i++)
181
        mTrees[i].first->remove();
98
        mTrees[i].first->remove();
182
    mTrees.clear();
99
    mTrees.clear();
183
    return c;
100
    return c;
184
}
101
}
185
102
186
int Management::kill(QString filter, double fraction)
103
int Management::kill(QString filter, double fraction)
187
{
104
{
188
   return remove_trees(filter, fraction, false);
105
   return remove_trees(filter, fraction, false);
189
}
106
}
190
int Management::manage(QString filter, double fraction)
107
int Management::manage(QString filter, double fraction)
191
{
108
{
192
    return remove_trees(filter, fraction, true);
109
    return remove_trees(filter, fraction, true);
193
}
110
}
194
111
195
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
112
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
196
{
113
{
197
    if (mTrees.isEmpty())
114
    if (mTrees.isEmpty())
198
        return 0;
115
        return 0;
199
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
116
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
200
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
117
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
201
    if (index_from>=index_to)
118
    if (index_from>=index_to)
202
        return 0;
119
        return 0;
203
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
120
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
204
    int i;
121
    int i;
205
    int count = number;
122
    int count = number;
206
    if (index_to-index_from <= number)  {
123
    if (index_to-index_from <= number)  {
207
        // kill all
124
        // kill all
208
        if (management) {
125
        if (management) {
209
            // management
126
            // management
210
            for (i=index_from; i<index_to; i++)
127
            for (i=index_from; i<index_to; i++)
211
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
128
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
212
        } else {
129
        } else {
213
            // just kill...
130
            // just kill...
214
            for (i=index_from; i<index_to; i++)
131
            for (i=index_from; i<index_to; i++)
215
                mTrees.at(i).first->remove();
132
                mTrees.at(i).first->remove();
216
        }
133
        }
217
        count = index_to - index_from;
134
        count = index_to - index_from;
218
    } else {
135
    } else {
219
        // kill randomly the provided number
136
        // kill randomly the provided number
220
        int cancel = 1000;
137
        int cancel = 1000;
221
        while(number>=0) {
138
        while(number>=0) {
222
            int rnd_index = irandom(index_from, index_to);
139
            int rnd_index = irandom(index_from, index_to);
223
            if (mTrees[rnd_index].first->isDead()) {
140
            if (mTrees[rnd_index].first->isDead()) {
224
                if (--cancel<0) {
141
                if (--cancel<0) {
225
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
142
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
226
                    count-=number; // not all trees were killed
143
                    count-=number; // not all trees were killed
227
                    break;
144
                    break;
228
                }
145
                }
229
                continue;
146
                continue;
230
            }
147
            }
231
            cancel = 1000;
148
            cancel = 1000;
232
            number--;
149
            number--;
233
            if (management) {
150
            if (management) {
234
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
151
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
235
            } else {
152
            } else {
236
                mTrees[rnd_index].first->remove();
153
                mTrees[rnd_index].first->remove();
237
            }
154
            }
238
        }
155
        }
239
    }
156
    }
240
    qDebug() << count << "removed.";
157
    qDebug() << count << "removed.";
241
    // clean up the tree list...
158
    // clean up the tree list...
242
    for (int i=mTrees.count()-1; i>=0; --i) {
159
    for (int i=mTrees.count()-1; i>=0; --i) {
243
        if (mTrees[i].first->isDead())
160
        if (mTrees[i].first->isDead())
244
            mTrees.removeAt(i);
161
            mTrees.removeAt(i);
245
    }
162
    }
246
    return count; // killed or manages
163
    return count; // killed or manages
247
}
164
}
248
165
249
/** remove trees from a list and reduce the list.
166
/** remove trees from a list and reduce the list.
250

167

251
  */
168
  */
252
int Management::remove_trees(QString expression, double fraction, bool management)
169
int Management::remove_trees(QString expression, double fraction, bool management)
253
{
170
{
254
    TreeWrapper tw;
171
    TreeWrapper tw;
255
    Expression expr(expression,&tw);
172
    Expression expr(expression,&tw);
256
    expr.enableIncSum();
173
    expr.enableIncSum();
257
    int n = 0;
174
    int n = 0;
258
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
175
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
259
    try {
176
    try {
260
        while (tp!=mTrees.end()) {
177
        while (tp!=mTrees.end()) {
261
            tw.setTree(tp->first);
178
            tw.setTree(tp->first);
262
            // if expression evaluates to true and if random number below threshold...
179
            // if expression evaluates to true and if random number below threshold...
263
            if (expr.calculate(tw) && drandom() <=fraction) {
180
            if (expr.calculate(tw) && drandom() <=fraction) {
264
                // remove from system
181
                // remove from system
265
                if (management)
182
                if (management)
266
                    tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions
183
                    tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions
267
                else
184
                else
268
                    tp->first->remove(); // kill
185
                    tp->first->remove(); // kill
269
                // remove from tree list
186
                // remove from tree list
270
                tp = mTrees.erase(tp);
187
                tp = mTrees.erase(tp);
271
                n++;
188
                n++;
272
            } else {
189
            } else {
273
                ++tp;
190
                ++tp;
274
            }
191
            }
275
        }
192
        }
276
    } catch(const IException &e) {
193
    } catch(const IException &e) {
277
        context()->throwError(e.message());
194
        context()->throwError(e.message());
278
    }
195
    }
279
    return n;
196
    return n;
280
}
197
}
281
198
282
// calculate aggregates for all trees in the internal list
199
// calculate aggregates for all trees in the internal list
283
double Management::aggregate_function(QString expression, QString filter, QString type)
200
double Management::aggregate_function(QString expression, QString filter, QString type)
284
{
201
{
285
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
202
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
286
    TreeWrapper tw;
203
    TreeWrapper tw;
287
    Expression expr(expression,&tw);
204
    Expression expr(expression,&tw);
288
205
289
    double sum = 0.;
206
    double sum = 0.;
290
    int n=0;
207
    int n=0;
291
    try {
208
    try {
292
209
293
        if (filter.isEmpty()) {
210
        if (filter.isEmpty()) {
294
            // without filtering
211
            // without filtering
295
            while (tp!=mTrees.end()) {
212
            while (tp!=mTrees.end()) {
296
                tw.setTree(tp->first);
213
                tw.setTree(tp->first);
297
                sum += expr.calculate();
214
                sum += expr.calculate();
298
                ++n;
215
                ++n;
299
                ++tp;
216
                ++tp;
300
            }
217
            }
301
        } else {
218
        } else {
302
            // with filtering
219
            // with filtering
303
            Expression filter_expr(filter,&tw);
220
            Expression filter_expr(filter,&tw);
304
            filter_expr.enableIncSum();
221
            filter_expr.enableIncSum();
305
            while (tp!=mTrees.end()) {
222
            while (tp!=mTrees.end()) {
306
                tw.setTree(tp->first);
223
                tw.setTree(tp->first);
307
                if (filter_expr.calculate()) {
224
                if (filter_expr.calculate()) {
308
                    sum += expr.calculate();
225
                    sum += expr.calculate();
309
                    ++n;
226
                    ++n;
310
                }
227
                }
311
                ++tp;
228
                ++tp;
312
            }
229
            }
313
        }
230
        }
314
231
315
    } catch(const IException &e) {
232
    } catch(const IException &e) {
316
        context()->throwError(e.message());
233
        context()->throwError(e.message());
317
    }
234
    }
318
    if (type=="sum")
235
    if (type=="sum")
319
        return sum;
236
        return sum;
320
    if (type=="mean")
237
    if (type=="mean")
321
        return n>0?sum/double(n):0.;
238
        return n>0?sum/double(n):0.;
322
    return 0.;
239
    return 0.;
323
}
240
}
324
241
325
242
326
// from the range percentile range pctfrom to pctto (each 1..100)
243
// from the range percentile range pctfrom to pctto (each 1..100)
327
int Management::kill(int pctfrom, int pctto, int number)
244
int Management::kill(int pctfrom, int pctto, int number)
328
{
245
{
329
    return remove_percentiles(pctfrom, pctto, number, false);
246
    return remove_percentiles(pctfrom, pctto, number, false);
330
}
247
}
331
248
332
// from the range percentile range pctfrom to pctto (each 1..100)
249
// from the range percentile range pctfrom to pctto (each 1..100)
333
int Management::manage(int pctfrom, int pctto, int number)
250
int Management::manage(int pctfrom, int pctto, int number)
334
{
251
{
335
    return remove_percentiles(pctfrom, pctto, number, true);
252
    return remove_percentiles(pctfrom, pctto, number, true);
336
}
253
}
337
254
338
int Management::manage()
255
int Management::manage()
339
{
256
{
340
    int c = mTrees.count();
257
    int c = mTrees.count();
341
    for (int i=0;i<mTrees.count();i++)
258
    for (int i=0;i<mTrees.count();i++)
342
        mTrees[i].first->remove(removeFoliage(),
259
        mTrees[i].first->remove(removeFoliage(),
343
                                removeBranch(),
260
                                removeBranch(),
344
                                removeStem()); // remove with current removal fractions
261
                                removeStem()); // remove with current removal fractions
345
    mTrees.clear();
262
    mTrees.clear();
346
    return c;
263
    return c;
347
}
264
}
348
265
349
266
350
267
351
void Management::run()
268
void Management::run()
352
{
269
{
353
    mTrees.clear();
270
    mTrees.clear();
354
    mRemoved=0;
271
    mRemoved=0;
355
    qDebug() << "Management::run() called";
272
    qDebug() << "Management::run() called";
356
    QScriptValue mgmt = mEngine->globalObject().property("manage");
273
    QScriptValue mgmt = mEngine->globalObject().property("manage");
357
    int year = GlobalSettings::instance()->currentYear();
274
    int year = GlobalSettings::instance()->currentYear();
358
    mgmt.call(QScriptValue(), QScriptValueList()<<year);
275
    mgmt.call(QScriptValue(), QScriptValueList()<<year);
359
    if (mEngine->hasUncaughtException())
276
    if (mEngine->hasUncaughtException())
360
        qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace();
277
        qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace();
361
278
362
    if (mRemoved>0) {
279
    if (mRemoved>0) {
363
        foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList())
280
        foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList())
364
           ru->cleanTreeList();
281
           ru->cleanTreeList();
365
   }
-
 
-
 
282
    }
-
 
283
}
-
 
284
-
 
285
void Management::loadScript(const QString &fileName)
-
 
286
{
-
 
287
    mScriptFile = fileName;
-
 
288
    ScriptGlobal::loadScript(fileName);
366
}
289
}
367
290
368
int Management::filter(QVariantList idList)
291
int Management::filter(QVariantList idList)
369
{
292
{
370
    QVector<int> ids;
293
    QVector<int> ids;
371
    foreach(const QVariant &v, idList)
294
    foreach(const QVariant &v, idList)
372
        if (!v.isNull())
295
        if (!v.isNull())
373
            ids << v.toInt();
296
            ids << v.toInt();
374
//    QHash<int, int> ids;
297
//    QHash<int, int> ids;
375
//    foreach(const QVariant &v, idList)
298
//    foreach(const QVariant &v, idList)
376
//        ids[v.toInt()] = 1;
299
//        ids[v.toInt()] = 1;
377
300
378
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
301
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
379
    while (tp!=mTrees.end()) {
302
    while (tp!=mTrees.end()) {
380
        if (!ids.contains(tp->first->id()) )
303
        if (!ids.contains(tp->first->id()) )
381
            tp = mTrees.erase(tp);
304
            tp = mTrees.erase(tp);
382
        else
305
        else
383
            ++tp;
306
            ++tp;
384
    }
307
    }
385
    qDebug() << "Management::filter by id-list:" << mTrees.count();
308
    qDebug() << "Management::filter by id-list:" << mTrees.count();
386
    return mTrees.count();
309
    return mTrees.count();
387
}
310
}
388
311
389
int Management::filter(QString filter)
312
int Management::filter(QString filter)
390
{
313
{
391
    TreeWrapper tw;
314
    TreeWrapper tw;
392
    Expression expr(filter,&tw);
315
    Expression expr(filter,&tw);
393
    expr.enableIncSum();
316
    expr.enableIncSum();
394
    int n_before = mTrees.count();
317
    int n_before = mTrees.count();
395
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
318
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
396
    try {
319
    try {
397
        while (tp!=mTrees.end()) {
320
        while (tp!=mTrees.end()) {
398
            tw.setTree(tp->first);
321
            tw.setTree(tp->first);
399
            if (expr.calculate(tw))
322
            if (expr.calculate(tw))
400
                tp = mTrees.erase(tp);
323
                tp = mTrees.erase(tp);
401
            else
324
            else
402
                ++tp;
325
                ++tp;
403
        }
326
        }
404
    } catch(const IException &e) {
327
    } catch(const IException &e) {
405
        context()->throwError(e.message());
328
        context()->throwError(e.message());
406
    }
329
    }
407
330
408
    qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count()  << "trees (before/after filtering).";
331
    qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count()  << "trees (before/after filtering).";
409
    return mTrees.count();
332
    return mTrees.count();
410
}
333
}
411
334
412
int Management::load(int ruindex)
335
int Management::load(int ruindex)
413
{
336
{
414
    Model *m = GlobalSettings::instance()->model();
337
    Model *m = GlobalSettings::instance()->model();
415
    ResourceUnit *ru = m->ru(ruindex);
338
    ResourceUnit *ru = m->ru(ruindex);
416
    if (!ru)
339
    if (!ru)
417
        return -1;
340
        return -1;
418
    mTrees.clear();
341
    mTrees.clear();
419
    for (int i=0;i<ru->trees().count();i++)
342
    for (int i=0;i<ru->trees().count();i++)
420
        if (!ru->tree(i)->isDead())
343
        if (!ru->tree(i)->isDead())
421
            mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.));
344
            mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.));
422
    return mTrees.count();
345
    return mTrees.count();
423
}
346
}
424
347
425
int Management::load(QString filter)
348
int Management::load(QString filter)
426
{
349
{
427
    TreeWrapper tw;
350
    TreeWrapper tw;
428
    Model *m = GlobalSettings::instance()->model();
351
    Model *m = GlobalSettings::instance()->model();
429
    mTrees.clear();
352
    mTrees.clear();
430
    AllTreeIterator at(m);
353
    AllTreeIterator at(m);
431
    if (filter.isEmpty()) {
354
    if (filter.isEmpty()) {
432
        while (Tree *t=at.nextLiving())
355
        while (Tree *t=at.nextLiving())
433
            if (!t->isDead())
356
            if (!t->isDead())
434
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
357
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
435
    } else {
358
    } else {
436
        Expression expr(filter,&tw);
359
        Expression expr(filter,&tw);
437
        expr.enableIncSum();
360
        expr.enableIncSum();
438
        qDebug() << "filtering with" << filter;
361
        qDebug() << "filtering with" << filter;
439
        while (Tree *t=at.nextLiving()) {
362
        while (Tree *t=at.nextLiving()) {
440
            tw.setTree(t);
363
            tw.setTree(t);
441
            if (!t->isDead() && expr.execute())
364
            if (!t->isDead() && expr.execute())
442
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
365
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
443
        }
366
        }
444
    }
367
    }
445
    return mTrees.count();
368
    return mTrees.count();
446
}
369
}
447
370
448
/**
371
/**
449
*/
372
*/
450
void Management::loadFromTreeList(QList<Tree*>tree_list)
373
void Management::loadFromTreeList(QList<Tree*>tree_list)
451
{
374
{
452
    mTrees.clear();
375
    mTrees.clear();
453
    for (int i=0;i<tree_list.count();++i)
376
    for (int i=0;i<tree_list.count();++i)
454
        mTrees.append(QPair<Tree*, double>(tree_list[i], 0.));
377
        mTrees.append(QPair<Tree*, double>(tree_list[i], 0.));
455
}
378
}
456
379
457
// loadFromMap: script access
380
// loadFromMap: script access
458
void Management::loadFromMap(MapGridWrapper *wrap, int key)
381
void Management::loadFromMap(MapGridWrapper *wrap, int key)
459
{
382
{
460
    if (!wrap) {
383
    if (!wrap) {
461
        context()->throwError("loadFromMap called with invalid map object!");
384
        context()->throwError("loadFromMap called with invalid map object!");
462
        return;
385
        return;
463
    }
386
    }
464
    loadFromMap(wrap->map(), key);
387
    loadFromMap(wrap->map(), key);
465
}
388
}
466
389
467
void Management::killSaplings(MapGridWrapper *wrap, int key)
390
void Management::killSaplings(MapGridWrapper *wrap, int key)
468
{
391
{
469
    //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
392
    //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
470
    //if (!wrap) {
393
    //if (!wrap) {
471
    //    context()->throwError("loadFromMap called with invalid map object!");
394
    //    context()->throwError("loadFromMap called with invalid map object!");
472
    //    return;
395
    //    return;
473
    //}
396
    //}
474
    //loadFromMap(wrap->map(), key);
397
    //loadFromMap(wrap->map(), key);
475
    // retrieve all sapling trees on the stand:
398
    // retrieve all sapling trees on the stand:
476
    QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key);
399
    QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key);
477
    // for now, just kill em all...
400
    // for now, just kill em all...
478
    for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it) {
401
    for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it) {
479
        // (*it).second->pixel = 0;
402
        // (*it).second->pixel = 0;
480
        (*it).first->changeSapling().clearSapling( *(*it).second, false); // kill and move biomass to soil
403
        (*it).first->changeSapling().clearSapling( *(*it).second, false); // kill and move biomass to soil
481
    }
404
    }
482
405
483
    // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
406
    // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
484
}
407
}
485
408
486
/// specify removal fractions
409
/// specify removal fractions
487
/// @param SWDFrac 0: no change, 1: remove all of standing woody debris
410
/// @param SWDFrac 0: no change, 1: remove all of standing woody debris
488
/// @param DWDfrac 0: no change, 1: remove all of downled woody debris
411
/// @param DWDfrac 0: no change, 1: remove all of downled woody debris
489
/// @param litterFrac 0: no change, 1: remove all of soil litter
412
/// @param litterFrac 0: no change, 1: remove all of soil litter
490
/// @param soilFrac 0: no change, 1: remove all of soil organic matter
413
/// @param soilFrac 0: no change, 1: remove all of soil organic matter
491
void Management::removeSoilCarbon(MapGridWrapper *wrap, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac)
414
void Management::removeSoilCarbon(MapGridWrapper *wrap, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac)
492
{
415
{
493
    if (!(SWDfrac>=0. && SWDfrac<=1. && DWDfrac>=0. && DWDfrac<=1. && soilFrac>=0. && soilFrac<=1. && litterFrac>=0. && litterFrac<=1.)) {
416
    if (!(SWDfrac>=0. && SWDfrac<=1. && DWDfrac>=0. && DWDfrac<=1. && soilFrac>=0. && soilFrac<=1. && litterFrac>=0. && litterFrac<=1.)) {
494
        context()->throwError(QString("removeSoilCarbon called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString()));
417
        context()->throwError(QString("removeSoilCarbon called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString()));
495
        return;
418
        return;
496
    }
419
    }
497
    QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key);
420
    QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key);
498
    double total_area = 0.;
421
    double total_area = 0.;
499
    for (int i=0;i<ru_areas.size();++i) {
422
    for (int i=0;i<ru_areas.size();++i) {
500
        ResourceUnit *ru = ru_areas[i].first;
423
        ResourceUnit *ru = ru_areas[i].first;
501
        double area_factor = ru_areas[i].second; // 0..1
424
        double area_factor = ru_areas[i].second; // 0..1
502
        total_area += area_factor;
425
        total_area += area_factor;
503
        // swd
426
        // swd
504
        if (SWDfrac>0.)
427
        if (SWDfrac>0.)
505
            ru->snag()->removeCarbon(SWDfrac*area_factor);
428
            ru->snag()->removeCarbon(SWDfrac*area_factor);
506
        // soil pools
429
        // soil pools
507
        ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor);
430
        ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor);
508
        // qDebug() << ru->index() << area_factor;
431
        // qDebug() << ru->index() << area_factor;
509
    }
432
    }
510
    qDebug() << "total area" << total_area << "of" << wrap->map()->area(key);
433
    qDebug() << "total area" << total_area << "of" << wrap->map()->area(key);
511
}
434
}
512
435
513
/** slash snags (SWD and otherWood-Pools) of polygon \p key on the map \p wrap.
436
/** slash snags (SWD and otherWood-Pools) of polygon \p key on the map \p wrap.
514
  The factor is scaled to the overlapping area of \p key on the resource unit.
437
  The factor is scaled to the overlapping area of \p key on the resource unit.
515
  @param wrap MapGrid to use together with \p key
438
  @param wrap MapGrid to use together with \p key
516
  @param key ID of the polygon.
439
  @param key ID of the polygon.
517
  @param slash_fraction 0: no change, 1: 100%
440
  @param slash_fraction 0: no change, 1: 100%
518
   */
441
   */
519
void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction)
442
void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction)
520
{
443
{
521
    if (slash_fraction<0 || slash_fraction>1) {
444
    if (slash_fraction<0 || slash_fraction>1) {
522
        context()->throwError(QString("slashSnags called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString()));
445
        context()->throwError(QString("slashSnags called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString()));
523
        return;
446
        return;
524
    }
447
    }
525
    QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key);
448
    QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key);
526
    double total_area = 0.;
449
    double total_area = 0.;
527
    for (int i=0;i<ru_areas.size();++i) {
450
    for (int i=0;i<ru_areas.size();++i) {
528
        ResourceUnit *ru = ru_areas[i].first;
451
        ResourceUnit *ru = ru_areas[i].first;
529
        double area_factor = ru_areas[i].second; // 0..1
452
        double area_factor = ru_areas[i].second; // 0..1
530
        total_area += area_factor;
453
        total_area += area_factor;
531
        ru->snag()->management(slash_fraction * area_factor);
454
        ru->snag()->management(slash_fraction * area_factor);
532
        // qDebug() << ru->index() << area_factor;
455
        // qDebug() << ru->index() << area_factor;
533
    }
456
    }
534
    qDebug() << "total area" << total_area << "of" << wrap->map()->area(key);
457
    qDebug() << "total area" << total_area << "of" << wrap->map()->area(key);
535
458
536
}
459
}
537
460
538
/** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
461
/** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
539
*/
462
*/
540
void Management::loadFromMap(const MapGrid *map_grid, int key)
463
void Management::loadFromMap(const MapGrid *map_grid, int key)
541
{
464
{
542
    if (!map_grid) {
465
    if (!map_grid) {
543
        qDebug() << "invalid parameter for Management::loadFromMap: Map expected!";
466
        qDebug() << "invalid parameter for Management::loadFromMap: Map expected!";
544
        return;
467
        return;
545
    }
468
    }
546
    if (map_grid->isValid()) {
469
    if (map_grid->isValid()) {
547
        QList<Tree*> tree_list = map_grid->trees(key);
470
        QList<Tree*> tree_list = map_grid->trees(key);
548
        loadFromTreeList( tree_list );
471
        loadFromTreeList( tree_list );
549
    } else {
472
    } else {
550
        qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded";
473
        qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded";
551
    }
474
    }
552
475
553
}
476
}
554
477
555
bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2)
478
bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2)
556
{
479
{
557
    return p1.second < p2.second;
480
    return p1.second < p2.second;
558
}
481
}
559
482
560
void Management::sort(QString statement)
483
void Management::sort(QString statement)
561
{
484
{
562
    TreeWrapper tw;
485
    TreeWrapper tw;
563
    Expression sorter(statement, &tw);
486
    Expression sorter(statement, &tw);
564
    // fill the "value" part of the tree storage with a value for each tree
487
    // fill the "value" part of the tree storage with a value for each tree
565
    for (int i=0;i<mTrees.count(); ++i) {
488
    for (int i=0;i<mTrees.count(); ++i) {
566
        tw.setTree(mTrees.at(i).first);
489
        tw.setTree(mTrees.at(i).first);
567
        mTrees[i].second = sorter.execute();
490
        mTrees[i].second = sorter.execute();
568
   }
491
   }
569
   // now sort the list....
492
   // now sort the list....
570
   qSort(mTrees.begin(), mTrees.end(), treePairValue);
493
   qSort(mTrees.begin(), mTrees.end(), treePairValue);
571
}
494
}
572
495
573
double Management::percentile(int pct)
496
double Management::percentile(int pct)
574
{
497
{
575
    if (mTrees.count()==0)
498
    if (mTrees.count()==0)
576
        return -1.;
499
        return -1.;
577
    int idx = int( (pct/100.) * mTrees.count());
500
    int idx = int( (pct/100.) * mTrees.count());
578
    if (idx>=0 && idx<mTrees.count())
501
    if (idx>=0 && idx<mTrees.count())
579
        return mTrees.at(idx).second;
502
        return mTrees.at(idx).second;
580
    else
503
    else
581
        return -1;
504
        return -1;
582
}
505
}
583
506
584
/// random shuffle of all trees in the list
507
/// random shuffle of all trees in the list
585
void Management::randomize()
508
void Management::randomize()
586
{
509
{
587
    // fill the "value" part of the tree storage with a random value for each tree
510
    // fill the "value" part of the tree storage with a random value for each tree
588
    for (int i=0;i<mTrees.count(); ++i) {
511
    for (int i=0;i<mTrees.count(); ++i) {
589
        mTrees[i].second = drandom();
512
        mTrees[i].second = drandom();
590
    }
513
    }
591
    // now sort the list....
514
    // now sort the list....
592
    qSort(mTrees.begin(), mTrees.end(), treePairValue);
515
    qSort(mTrees.begin(), mTrees.end(), treePairValue);
593
516
594
}
517
}
595
518
596
519
597
520
598
521
599
522
600
 
523