Subversion Repositories public iLand

Rev

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

Rev 671 Rev 674
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"
31
#include "climateconverter.h"
32
#include "csvfile.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
36
36
#include <QtScript>
37
#include <QtScript>
37
#include <QTextEdit>
38
#include <QTextEdit>
38
QObject *Management::scriptOutput = 0;
39
QObject *Management::scriptOutput = 0;
39
40
40
QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng)
41
QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng)
41
{
42
{
42
    QString value;
43
    QString value;
43
    for (int i = 0; i < ctx->argumentCount(); ++i) {
44
    for (int i = 0; i < ctx->argumentCount(); ++i) {
44
        if (i > 0)
45
        if (i > 0)
45
            value.append(" ");
46
            value.append(" ");
46
        value.append(ctx->argument(i).toString());
47
        value.append(ctx->argument(i).toString());
47
    }
48
    }
48
    if (Management::scriptOutput) {
49
    if (Management::scriptOutput) {
49
        QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput);
50
        QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput);
50
        if (e)
51
        if (e)
51
            e->append(value);
52
            e->append(value);
52
    } else {
53
    } else {
53
        qDebug() << "Script:" << value;
54
        qDebug() << "Script:" << value;
54
    }
55
    }
55
    return eng->undefinedValue();
56
    return eng->undefinedValue();
56
}
57
}
57
58
58
QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng)
59
QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng)
59
{
60
{
60
61
61
    QString fileName = ctx->argument(0).toString();
62
    QString fileName = ctx->argument(0).toString();
62
    QString path =GlobalSettings::instance()->path(fileName, "script") ;
63
    QString path =GlobalSettings::instance()->path(fileName, "script") ;
63
    QString includeFile=Helper::loadTextFile(path);
64
    QString includeFile=Helper::loadTextFile(path);
64
65
65
    ctx->setActivationObject(ctx->parentContext()->activationObject());
66
    ctx->setActivationObject(ctx->parentContext()->activationObject());
66
    ctx->setThisObject(ctx->parentContext()->thisObject());
67
    ctx->setThisObject(ctx->parentContext()->thisObject());
67
68
68
    QScriptValue ret = eng->evaluate(includeFile, fileName);
69
    QScriptValue ret = eng->evaluate(includeFile, fileName);
69
    if (eng->hasUncaughtException())
70
    if (eng->hasUncaughtException())
70
        qDebug() << "Error in include:" << eng->uncaughtException().toString();
71
        qDebug() << "Error in include:" << eng->uncaughtException().toString();
71
    return ret;
72
    return ret;
72
}
73
}
73
74
74
QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng)
75
QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng)
75
{
76
{
76
    QString value = ctx->argument(0).toString();
77
    QString value = ctx->argument(0).toString();
77
    Helper::msg(value);
78
    Helper::msg(value);
78
    return eng->undefinedValue();
79
    return eng->undefinedValue();
79
}
80
}
80
// global output function
81
// global output function
81
QString Management::executeScript(QString cmd)
82
QString Management::executeScript(QString cmd)
82
{
83
{
83
    DebugTimer t("execute javascript");
84
    DebugTimer t("execute javascript");
84
    if (mEngine)
85
    if (mEngine)
85
        mEngine->evaluate(cmd);
86
        mEngine->evaluate(cmd);
86
    if (mEngine->hasUncaughtException()) {
87
    if (mEngine->hasUncaughtException()) {
87
        //int line = mEngine->uncaughtExceptionLineNumber();
88
        //int line = mEngine->uncaughtExceptionLineNumber();
88
        QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString());
89
        QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString());
89
        msg+=mEngine->uncaughtExceptionBacktrace().join("\n");
90
        msg+=mEngine->uncaughtExceptionBacktrace().join("\n");
90
        return msg;
91
        return msg;
91
    } else {
92
    } else {
92
        return QString();
93
        return QString();
93
    }
94
    }
94
}
95
}
95
96
96
Management::Management()
97
Management::Management()
97
{
98
{
98
    // setup the scripting engine
99
    // setup the scripting engine
99
    mEngine = new QScriptEngine();
100
    mEngine = new QScriptEngine();
100
    QScriptValue objectValue = mEngine->newQObject(this);
101
    QScriptValue objectValue = mEngine->newQObject(this);
101
    QScriptValue dbgprint = mEngine->newFunction(script_debug);
102
    QScriptValue dbgprint = mEngine->newFunction(script_debug);
102
    QScriptValue sinclude = mEngine->newFunction(script_include);
103
    QScriptValue sinclude = mEngine->newFunction(script_include);
103
    QScriptValue alert = mEngine->newFunction(script_alert);
104
    QScriptValue alert = mEngine->newFunction(script_alert);
104
    mEngine->globalObject().setProperty("management", objectValue);
105
    mEngine->globalObject().setProperty("management", objectValue);
105
    mEngine->globalObject().setProperty("print",dbgprint);
106
    mEngine->globalObject().setProperty("print",dbgprint);
106
    mEngine->globalObject().setProperty("include",sinclude);
107
    mEngine->globalObject().setProperty("include",sinclude);
107
    mEngine->globalObject().setProperty("alert", alert);
108
    mEngine->globalObject().setProperty("alert", alert);
108
109
109
    // globals object: instatiate here, but ownership goes to script engine
110
    // globals object: instatiate here, but ownership goes to script engine
110
    ScriptGlobal *global = new ScriptGlobal();
111
    ScriptGlobal *global = new ScriptGlobal();
111
    QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership);
112
    QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership);
112
    mEngine->globalObject().setProperty("Globals", glb);
113
    mEngine->globalObject().setProperty("Globals", glb);
113
    // other object types
114
    // other object types
114
    ClimateConverter::addToScriptEngine(*mEngine);
115
    ClimateConverter::addToScriptEngine(*mEngine);
115
    CSVFile::addToScriptEngine(*mEngine);
116
    CSVFile::addToScriptEngine(*mEngine);
116
    MapGridWrapper::addToScriptEngine(*mEngine);
117
    MapGridWrapper::addToScriptEngine(*mEngine);
-
 
118
    // setup scripting for modules
-
 
119
    GlobalSettings::instance()->model()->modules()->setupScripting(mEngine);
117
120
118
    // default values for removal fractions
121
    // default values for removal fractions
119
    // 100% of the stem, 0% of foliage and branches
122
    // 100% of the stem, 0% of foliage and branches
120
    mRemoveFoliage = 0.;
123
    mRemoveFoliage = 0.;
121
    mRemoveBranch = 0.;
124
    mRemoveBranch = 0.;
122
    mRemoveStem = 1.;
125
    mRemoveStem = 1.;
123
126
124
127
125
}
128
}
126
129
127
Management::~Management()
130
Management::~Management()
128
{
131
{
129
    delete mEngine;
132
    delete mEngine;
130
}
133
}
131
134
132
void Management::loadScript(const QString &fileName)
135
void Management::loadScript(const QString &fileName)
133
{
136
{
134
    mScriptFile = fileName;
137
    mScriptFile = fileName;
135
    QString program = Helper::loadTextFile(fileName);
138
    QString program = Helper::loadTextFile(fileName);
136
    if (program.isEmpty())
139
    if (program.isEmpty())
137
        return;
140
        return;
138
141
139
    mEngine->evaluate(program);
142
    mEngine->evaluate(program);
140
    qDebug() << "management script loaded";
143
    qDebug() << "management script loaded";
141
    if (mEngine->hasUncaughtException())
144
    if (mEngine->hasUncaughtException())
142
        qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace();
145
        qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace();
143
146
144
}
147
}
145
148
146
int Management::remain(int number)
149
int Management::remain(int number)
147
{
150
{
148
    qDebug() << "remain called (number): " << number;
151
    qDebug() << "remain called (number): " << number;
149
    Model *m = GlobalSettings::instance()->model();
152
    Model *m = GlobalSettings::instance()->model();
150
    AllTreeIterator at(m);
153
    AllTreeIterator at(m);
151
    QList<Tree*> trees;
154
    QList<Tree*> trees;
152
    while (Tree *t=at.next())
155
    while (Tree *t=at.next())
153
        trees.push_back(t);
156
        trees.push_back(t);
154
    int to_kill = trees.count() - number;
157
    int to_kill = trees.count() - number;
155
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
158
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
156
    for (int i=0;i<to_kill;i++) {
159
    for (int i=0;i<to_kill;i++) {
157
        int index = irandom(0, trees.count()-1);
160
        int index = irandom(0, trees.count()-1);
158
        trees[index]->remove();
161
        trees[index]->remove();
159
        trees.removeAt(index);
162
        trees.removeAt(index);
160
    }
163
    }
161
    mRemoved += to_kill;
164
    mRemoved += to_kill;
162
    return to_kill;
165
    return to_kill;
163
}
166
}
164
167
165
168
166
int Management::kill()
169
int Management::kill()
167
{
170
{
168
    int c = mTrees.count();
171
    int c = mTrees.count();
169
    for (int i=0;i<mTrees.count();i++)
172
    for (int i=0;i<mTrees.count();i++)
170
        mTrees[i].first->remove();
173
        mTrees[i].first->remove();
171
    mTrees.clear();
174
    mTrees.clear();
172
    return c;
175
    return c;
173
}
176
}
174
177
175
int Management::kill(QString filter, double fraction)
178
int Management::kill(QString filter, double fraction)
176
{
179
{
177
   return remove_trees(filter, fraction, false);
180
   return remove_trees(filter, fraction, false);
178
}
181
}
179
int Management::manage(QString filter, double fraction)
182
int Management::manage(QString filter, double fraction)
180
{
183
{
181
    return remove_trees(filter, fraction, true);
184
    return remove_trees(filter, fraction, true);
182
}
185
}
183
186
184
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
187
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
185
{
188
{
186
    if (mTrees.isEmpty())
189
    if (mTrees.isEmpty())
187
        return 0;
190
        return 0;
188
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
191
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
189
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
192
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
190
    if (index_from>=index_to)
193
    if (index_from>=index_to)
191
        return 0;
194
        return 0;
192
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
195
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
193
    int i;
196
    int i;
194
    int count = number;
197
    int count = number;
195
    if (index_to-index_from <= number)  {
198
    if (index_to-index_from <= number)  {
196
        // kill all
199
        // kill all
197
        if (management) {
200
        if (management) {
198
            // management
201
            // management
199
            for (i=index_from; i<index_to; i++)
202
            for (i=index_from; i<index_to; i++)
200
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
203
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
201
        } else {
204
        } else {
202
            // just kill...
205
            // just kill...
203
            for (i=index_from; i<index_to; i++)
206
            for (i=index_from; i<index_to; i++)
204
                mTrees.at(i).first->remove();
207
                mTrees.at(i).first->remove();
205
        }
208
        }
206
        count = index_to - index_from;
209
        count = index_to - index_from;
207
    } else {
210
    } else {
208
        // kill randomly the provided number
211
        // kill randomly the provided number
209
        int cancel = 1000;
212
        int cancel = 1000;
210
        while(number>=0) {
213
        while(number>=0) {
211
            int rnd_index = irandom(index_from, index_to);
214
            int rnd_index = irandom(index_from, index_to);
212
            if (mTrees[rnd_index].first->isDead()) {
215
            if (mTrees[rnd_index].first->isDead()) {
213
                if (--cancel<0) {
216
                if (--cancel<0) {
214
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
217
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
215
                    count-=number; // not all trees were killed
218
                    count-=number; // not all trees were killed
216
                    break;
219
                    break;
217
                }
220
                }
218
                continue;
221
                continue;
219
            }
222
            }
220
            cancel = 1000;
223
            cancel = 1000;
221
            number--;
224
            number--;
222
            if (management) {
225
            if (management) {
223
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
226
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
224
            } else {
227
            } else {
225
                mTrees[rnd_index].first->remove();
228
                mTrees[rnd_index].first->remove();
226
            }
229
            }
227
        }
230
        }
228
    }
231
    }
229
    qDebug() << count << "removed.";
232
    qDebug() << count << "removed.";
230
    // clean up the tree list...
233
    // clean up the tree list...
231
    for (int i=mTrees.count()-1; i>=0; --i) {
234
    for (int i=mTrees.count()-1; i>=0; --i) {
232
        if (mTrees[i].first->isDead())
235
        if (mTrees[i].first->isDead())
233
            mTrees.removeAt(i);
236
            mTrees.removeAt(i);
234
    }
237
    }
235
    return count; // killed or manages
238
    return count; // killed or manages
236
}
239
}
237
240
238
/** remove trees from a list and reduce the list.
241
/** remove trees from a list and reduce the list.
239

242

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