Subversion Repositories public iLand

Rev

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

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

168

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