Subversion Repositories public iLand

Rev

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

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

167

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