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 |