Subversion Repositories public iLand

Rev

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

Rev 779 Rev 793
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
//#include "modules.h"
36
36
37
#include <QtScript>
-
 
-
 
37
#include <QJSEngine>
-
 
38
#include <QJSValue>
38
39
39
/** @class Management Management executes management routines.
40
/** @class Management Management executes management routines.
40
  @ingroup core
41
  @ingroup core
41
  The actual iLand management is based on Javascript functions. This class provides
42
  The actual iLand management is based on Javascript functions. This class provides
42
  the frame for executing the javascript as well as the functions that are called by scripts and
43
  the frame for executing the javascript as well as the functions that are called by scripts and
43
  that really do the work.
44
  that really do the work.
44
  See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
45
  See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
45
  */
46
  */
46
47
47
48
48
// global output function
49
// global output function
49
QString Management::executeScript(QString cmd)
50
QString Management::executeScript(QString cmd)
50
{
51
{
51
    return ScriptGlobal::executeScript(cmd);
52
    return ScriptGlobal::executeScript(cmd);
52
}
53
}
53
54
54
Management::Management()
55
Management::Management()
55
{
56
{
56
    // setup the scripting engine
57
    // setup the scripting engine
57
    mEngine = GlobalSettings::instance()->scriptEngine();
58
    mEngine = GlobalSettings::instance()->scriptEngine();
58
    QScriptValue objectValue = mEngine->newQObject(this);
-
 
-
 
59
    QJSValue objectValue = mEngine->newQObject(this);
59
    mEngine->globalObject().setProperty("management", objectValue);
60
    mEngine->globalObject().setProperty("management", objectValue);
60
61
61
    // default values for removal fractions
62
    // default values for removal fractions
62
    // 100% of the stem, 0% of foliage and branches
63
    // 100% of the stem, 0% of foliage and branches
63
    mRemoveFoliage = 0.;
64
    mRemoveFoliage = 0.;
64
    mRemoveBranch = 0.;
65
    mRemoveBranch = 0.;
65
    mRemoveStem = 1.;
66
    mRemoveStem = 1.;
66
67
67
}
68
}
68
69
69
Management::~Management()
70
Management::~Management()
70
{
71
{
71
}
72
}
72
73
73
74
74
int Management::remain(int number)
75
int Management::remain(int number)
75
{
76
{
76
    qDebug() << "remain called (number): " << number;
77
    qDebug() << "remain called (number): " << number;
77
    Model *m = GlobalSettings::instance()->model();
78
    Model *m = GlobalSettings::instance()->model();
78
    AllTreeIterator at(m);
79
    AllTreeIterator at(m);
79
    QList<Tree*> trees;
80
    QList<Tree*> trees;
80
    while (Tree *t=at.next())
81
    while (Tree *t=at.next())
81
        trees.push_back(t);
82
        trees.push_back(t);
82
    int to_kill = trees.count() - number;
83
    int to_kill = trees.count() - number;
83
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
84
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
84
    for (int i=0;i<to_kill;i++) {
85
    for (int i=0;i<to_kill;i++) {
85
        int index = irandom(0, trees.count()-1);
86
        int index = irandom(0, trees.count()-1);
86
        trees[index]->remove();
87
        trees[index]->remove();
87
        trees.removeAt(index);
88
        trees.removeAt(index);
88
    }
89
    }
89
    mRemoved += to_kill;
90
    mRemoved += to_kill;
90
    return to_kill;
91
    return to_kill;
91
}
92
}
92
93
93
94
94
int Management::kill()
95
int Management::kill()
95
{
96
{
96
    int c = mTrees.count();
97
    int c = mTrees.count();
97
    for (int i=0;i<mTrees.count();i++)
98
    for (int i=0;i<mTrees.count();i++)
98
        mTrees[i].first->remove();
99
        mTrees[i].first->remove();
99
    mTrees.clear();
100
    mTrees.clear();
100
    return c;
101
    return c;
101
}
102
}
102
103
103
int Management::kill(QString filter, double fraction)
104
int Management::kill(QString filter, double fraction)
104
{
105
{
105
   return remove_trees(filter, fraction, false);
106
   return remove_trees(filter, fraction, false);
106
}
107
}
107
int Management::manage(QString filter, double fraction)
108
int Management::manage(QString filter, double fraction)
108
{
109
{
109
    return remove_trees(filter, fraction, true);
110
    return remove_trees(filter, fraction, true);
110
}
111
}
111
112
112
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
113
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
113
{
114
{
114
    if (mTrees.isEmpty())
115
    if (mTrees.isEmpty())
115
        return 0;
116
        return 0;
116
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
117
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
117
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
118
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
118
    if (index_from>=index_to)
119
    if (index_from>=index_to)
119
        return 0;
120
        return 0;
120
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
121
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
121
    int i;
122
    int i;
122
    int count = number;
123
    int count = number;
123
    if (index_to-index_from <= number)  {
124
    if (index_to-index_from <= number)  {
124
        // kill all
125
        // kill all
125
        if (management) {
126
        if (management) {
126
            // management
127
            // management
127
            for (i=index_from; i<index_to; i++)
128
            for (i=index_from; i<index_to; i++)
128
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
129
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
129
        } else {
130
        } else {
130
            // just kill...
131
            // just kill...
131
            for (i=index_from; i<index_to; i++)
132
            for (i=index_from; i<index_to; i++)
132
                mTrees.at(i).first->remove();
133
                mTrees.at(i).first->remove();
133
        }
134
        }
134
        count = index_to - index_from;
135
        count = index_to - index_from;
135
    } else {
136
    } else {
136
        // kill randomly the provided number
137
        // kill randomly the provided number
137
        int cancel = 1000;
138
        int cancel = 1000;
138
        while(number>=0) {
139
        while(number>=0) {
139
            int rnd_index = irandom(index_from, index_to);
140
            int rnd_index = irandom(index_from, index_to);
140
            if (mTrees[rnd_index].first->isDead()) {
141
            if (mTrees[rnd_index].first->isDead()) {
141
                if (--cancel<0) {
142
                if (--cancel<0) {
142
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
143
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
143
                    count-=number; // not all trees were killed
144
                    count-=number; // not all trees were killed
144
                    break;
145
                    break;
145
                }
146
                }
146
                continue;
147
                continue;
147
            }
148
            }
148
            cancel = 1000;
149
            cancel = 1000;
149
            number--;
150
            number--;
150
            if (management) {
151
            if (management) {
151
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
152
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
152
            } else {
153
            } else {
153
                mTrees[rnd_index].first->remove();
154
                mTrees[rnd_index].first->remove();
154
            }
155
            }
155
        }
156
        }
156
    }
157
    }
157
    qDebug() << count << "removed.";
158
    qDebug() << count << "removed.";
158
    // clean up the tree list...
159
    // clean up the tree list...
159
    for (int i=mTrees.count()-1; i>=0; --i) {
160
    for (int i=mTrees.count()-1; i>=0; --i) {
160
        if (mTrees[i].first->isDead())
161
        if (mTrees[i].first->isDead())
161
            mTrees.removeAt(i);
162
            mTrees.removeAt(i);
162
    }
163
    }
163
    return count; // killed or manages
164
    return count; // killed or manages
164
}
165
}
165
166
166
/** remove trees from a list and reduce the list.
167
/** remove trees from a list and reduce the list.
167

168

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