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 |