Rev 753 | Rev 779 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 753 | Rev 767 | ||
---|---|---|---|
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"
|
- | |
32 | #include "csvfile.h"
|
- | |
- | 31 | //#include "climateconverter.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 | #include <QTextEdit>
|
- | |
39 | QObject *Management::scriptOutput = 0; |
- | |
40 | 38 | ||
41 | /** @class Management Management executes management routines.
|
39 | /** @class Management Management executes management routines.
|
42 | @ingroup core
|
40 | @ingroup core
|
43 | 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
|
44 | 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
|
45 | that really do the work.
|
43 | that really do the work.
|
46 | 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.
|
47 | */
|
45 | */
|
48 | 46 | ||
49 | QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng) |
- | |
50 | {
|
- | |
51 | QString value;
|
- | |
52 | for (int i = 0; i < ctx->argumentCount(); ++i) { |
- | |
53 | if (i > 0) |
- | |
54 | value.append(" "); |
- | |
55 | value.append(ctx->argument(i).toString()); |
- | |
56 | }
|
- | |
57 | if (Management::scriptOutput) { |
- | |
58 | QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput); |
- | |
59 | if (e) |
- | |
60 | e->append(value); |
- | |
61 | } else { |
- | |
62 | qDebug() << "Script:" << value; |
- | |
63 | }
|
- | |
64 | return eng->undefinedValue(); |
- | |
65 | }
|
- | |
66 | 47 | ||
67 | QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng) |
- | |
68 | {
|
- | |
69 | - | ||
70 | QString fileName = ctx->argument(0).toString(); |
- | |
71 | QString path =GlobalSettings::instance()->path(fileName, "script") ; |
- | |
72 | QString includeFile=Helper::loadTextFile(path); |
- | |
73 | - | ||
74 | ctx->setActivationObject(ctx->parentContext()->activationObject()); |
- | |
75 | ctx->setThisObject(ctx->parentContext()->thisObject()); |
- | |
76 | - | ||
77 | QScriptValue ret = eng->evaluate(includeFile, fileName); |
- | |
78 | if (eng->hasUncaughtException()) |
- | |
79 | qDebug() << "Error in include:" << eng->uncaughtException().toString(); |
- | |
80 | return ret; |
- | |
81 | }
|
- | |
82 | - | ||
83 | QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng) |
- | |
84 | {
|
- | |
85 | QString value = ctx->argument(0).toString(); |
- | |
86 | Helper::msg(value); |
- | |
87 | return eng->undefinedValue(); |
- | |
88 | }
|
- | |
89 | // global output function
|
48 | // global output function
|
90 | QString Management::executeScript(QString cmd) |
49 | QString Management::executeScript(QString cmd) |
91 | {
|
50 | {
|
92 | DebugTimer t("execute javascript"); |
- | |
93 | if (mEngine) |
- | |
94 | mEngine->evaluate(cmd); |
- | |
95 | if (mEngine->hasUncaughtException()) { |
- | |
96 | //int line = mEngine->uncaughtExceptionLineNumber();
|
- | |
97 | QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString()); |
- | |
98 | msg+=mEngine->uncaughtExceptionBacktrace().join("\n"); |
- | |
99 | return msg; |
- | |
100 | } else { |
- | |
101 | return QString(); |
- | |
102 | }
|
- | |
- | 51 | return ScriptGlobal::executeScript(cmd); |
|
103 | }
|
52 | }
|
104 | 53 | ||
105 | Management::Management() |
54 | Management::Management() |
106 | {
|
55 | {
|
107 | // setup the scripting engine
|
56 | // setup the scripting engine
|
108 | mEngine = new QScriptEngine(); |
- | |
- | 57 | mEngine = GlobalSettings::instance()->scriptEngine(); |
|
109 | QScriptValue objectValue = mEngine->newQObject(this); |
58 | QScriptValue objectValue = mEngine->newQObject(this); |
110 | QScriptValue dbgprint = mEngine->newFunction(script_debug); |
- | |
111 | QScriptValue sinclude = mEngine->newFunction(script_include); |
- | |
112 | QScriptValue alert = mEngine->newFunction(script_alert); |
- | |
113 | mEngine->globalObject().setProperty("management", objectValue); |
59 | mEngine->globalObject().setProperty("management", objectValue); |
114 | mEngine->globalObject().setProperty("print",dbgprint); |
- | |
115 | mEngine->globalObject().setProperty("include",sinclude); |
- | |
116 | mEngine->globalObject().setProperty("alert", alert); |
- | |
117 | - | ||
118 | // globals object: instatiate here, but ownership goes to script engine
|
- | |
119 | ScriptGlobal *global = new ScriptGlobal(); |
- | |
120 | QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership); |
- | |
121 | mEngine->globalObject().setProperty("Globals", glb); |
- | |
122 | // other object types
|
- | |
123 | ClimateConverter::addToScriptEngine(*mEngine); |
- | |
124 | CSVFile::addToScriptEngine(*mEngine); |
- | |
125 | MapGridWrapper::addToScriptEngine(*mEngine); |
- | |
126 | // setup scripting for modules
|
- | |
127 | GlobalSettings::instance()->model()->modules()->setupScripting(mEngine); |
- | |
128 | 60 | ||
129 | // default values for removal fractions
|
61 | // default values for removal fractions
|
130 | // 100% of the stem, 0% of foliage and branches
|
62 | // 100% of the stem, 0% of foliage and branches
|
131 | mRemoveFoliage = 0.; |
63 | mRemoveFoliage = 0.; |
132 | mRemoveBranch = 0.; |
64 | mRemoveBranch = 0.; |
133 | mRemoveStem = 1.; |
65 | mRemoveStem = 1.; |
134 | - | ||
135 | 66 | ||
136 | }
|
67 | }
|
137 | 68 | ||
138 | Management::~Management() |
69 | Management::~Management() |
139 | {
|
70 | {
|
140 | delete mEngine; |
- | |
141 | }
|
71 | }
|
142 | 72 | ||
143 | void Management::loadScript(const QString &fileName) |
- | |
144 | {
|
- | |
145 | mScriptFile = fileName; |
- | |
146 | QString program = Helper::loadTextFile(fileName); |
- | |
147 | if (program.isEmpty()) |
- | |
148 | return; |
- | |
149 | - | ||
150 | mEngine->evaluate(program); |
- | |
151 | qDebug() << "management script loaded"; |
- | |
152 | if (mEngine->hasUncaughtException()) |
- | |
153 | qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace(); |
- | |
154 | - | ||
155 | }
|
- | |
156 | 73 | ||
157 | int Management::remain(int number) |
74 | int Management::remain(int number) |
158 | {
|
75 | {
|
159 | qDebug() << "remain called (number): " << number; |
76 | qDebug() << "remain called (number): " << number; |
160 | Model *m = GlobalSettings::instance()->model(); |
77 | Model *m = GlobalSettings::instance()->model(); |
161 | AllTreeIterator at(m); |
78 | AllTreeIterator at(m); |
162 | QList<Tree*> trees; |
79 | QList<Tree*> trees; |
163 | while (Tree *t=at.next()) |
80 | while (Tree *t=at.next()) |
164 | trees.push_back(t); |
81 | trees.push_back(t); |
165 | int to_kill = trees.count() - number; |
82 | int to_kill = trees.count() - number; |
166 | 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"; |
167 | for (int i=0;i<to_kill;i++) { |
84 | for (int i=0;i<to_kill;i++) { |
168 | int index = irandom(0, trees.count()-1); |
85 | int index = irandom(0, trees.count()-1); |
169 | trees[index]->remove(); |
86 | trees[index]->remove(); |
170 | trees.removeAt(index); |
87 | trees.removeAt(index); |
171 | }
|
88 | }
|
172 | mRemoved += to_kill; |
89 | mRemoved += to_kill; |
173 | return to_kill; |
90 | return to_kill; |
174 | }
|
91 | }
|
175 | 92 | ||
176 | 93 | ||
177 | int Management::kill() |
94 | int Management::kill() |
178 | {
|
95 | {
|
179 | int c = mTrees.count(); |
96 | int c = mTrees.count(); |
180 | for (int i=0;i<mTrees.count();i++) |
97 | for (int i=0;i<mTrees.count();i++) |
181 | mTrees[i].first->remove(); |
98 | mTrees[i].first->remove(); |
182 | mTrees.clear(); |
99 | mTrees.clear(); |
183 | return c; |
100 | return c; |
184 | }
|
101 | }
|
185 | 102 | ||
186 | int Management::kill(QString filter, double fraction) |
103 | int Management::kill(QString filter, double fraction) |
187 | {
|
104 | {
|
188 | return remove_trees(filter, fraction, false); |
105 | return remove_trees(filter, fraction, false); |
189 | }
|
106 | }
|
190 | int Management::manage(QString filter, double fraction) |
107 | int Management::manage(QString filter, double fraction) |
191 | {
|
108 | {
|
192 | return remove_trees(filter, fraction, true); |
109 | return remove_trees(filter, fraction, true); |
193 | }
|
110 | }
|
194 | 111 | ||
195 | 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) |
196 | {
|
113 | {
|
197 | if (mTrees.isEmpty()) |
114 | if (mTrees.isEmpty()) |
198 | return 0; |
115 | return 0; |
199 | 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()); |
200 | 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); |
201 | if (index_from>=index_to) |
118 | if (index_from>=index_to) |
202 | return 0; |
119 | return 0; |
203 | 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; |
204 | int i; |
121 | int i; |
205 | int count = number; |
122 | int count = number; |
206 | if (index_to-index_from <= number) { |
123 | if (index_to-index_from <= number) { |
207 | // kill all
|
124 | // kill all
|
208 | if (management) { |
125 | if (management) { |
209 | // management
|
126 | // management
|
210 | for (i=index_from; i<index_to; i++) |
127 | for (i=index_from; i<index_to; i++) |
211 | mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem()); |
128 | mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem()); |
212 | } else { |
129 | } else { |
213 | // just kill...
|
130 | // just kill...
|
214 | for (i=index_from; i<index_to; i++) |
131 | for (i=index_from; i<index_to; i++) |
215 | mTrees.at(i).first->remove(); |
132 | mTrees.at(i).first->remove(); |
216 | }
|
133 | }
|
217 | count = index_to - index_from; |
134 | count = index_to - index_from; |
218 | } else { |
135 | } else { |
219 | // kill randomly the provided number
|
136 | // kill randomly the provided number
|
220 | int cancel = 1000; |
137 | int cancel = 1000; |
221 | while(number>=0) { |
138 | while(number>=0) { |
222 | int rnd_index = irandom(index_from, index_to); |
139 | int rnd_index = irandom(index_from, index_to); |
223 | if (mTrees[rnd_index].first->isDead()) { |
140 | if (mTrees[rnd_index].first->isDead()) { |
224 | if (--cancel<0) { |
141 | if (--cancel<0) { |
225 | qDebug() << "Management::kill: canceling search." << number << "trees left."; |
142 | qDebug() << "Management::kill: canceling search." << number << "trees left."; |
226 | count-=number; // not all trees were killed |
143 | count-=number; // not all trees were killed |
227 | break; |
144 | break; |
228 | }
|
145 | }
|
229 | continue; |
146 | continue; |
230 | }
|
147 | }
|
231 | cancel = 1000; |
148 | cancel = 1000; |
232 | number--; |
149 | number--; |
233 | if (management) { |
150 | if (management) { |
234 | mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() ); |
151 | mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() ); |
235 | } else { |
152 | } else { |
236 | mTrees[rnd_index].first->remove(); |
153 | mTrees[rnd_index].first->remove(); |
237 | }
|
154 | }
|
238 | }
|
155 | }
|
239 | }
|
156 | }
|
240 | qDebug() << count << "removed."; |
157 | qDebug() << count << "removed."; |
241 | // clean up the tree list...
|
158 | // clean up the tree list...
|
242 | for (int i=mTrees.count()-1; i>=0; --i) { |
159 | for (int i=mTrees.count()-1; i>=0; --i) { |
243 | if (mTrees[i].first->isDead()) |
160 | if (mTrees[i].first->isDead()) |
244 | mTrees.removeAt(i); |
161 | mTrees.removeAt(i); |
245 | }
|
162 | }
|
246 | return count; // killed or manages |
163 | return count; // killed or manages |
247 | }
|
164 | }
|
248 | 165 | ||
249 | /** remove trees from a list and reduce the list.
|
166 | /** remove trees from a list and reduce the list.
|
250 | 167 | ||
251 | */
|
168 | */
|
252 | int Management::remove_trees(QString expression, double fraction, bool management) |
169 | int Management::remove_trees(QString expression, double fraction, bool management) |
253 | {
|
170 | {
|
254 | TreeWrapper tw;
|
171 | TreeWrapper tw;
|
255 | Expression expr(expression,&tw); |
172 | Expression expr(expression,&tw); |
256 | expr.enableIncSum(); |
173 | expr.enableIncSum(); |
257 | int n = 0; |
174 | int n = 0; |
258 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
175 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
259 | try { |
176 | try { |
260 | while (tp!=mTrees.end()) { |
177 | while (tp!=mTrees.end()) { |
261 | tw.setTree(tp->first); |
178 | tw.setTree(tp->first); |
262 | // if expression evaluates to true and if random number below threshold...
|
179 | // if expression evaluates to true and if random number below threshold...
|
263 | if (expr.calculate(tw) && drandom() <=fraction) { |
180 | if (expr.calculate(tw) && drandom() <=fraction) { |
264 | // remove from system
|
181 | // remove from system
|
265 | if (management) |
182 | if (management) |
266 | tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions |
183 | tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions |
267 | else
|
184 | else
|
268 | tp->first->remove(); // kill |
185 | tp->first->remove(); // kill |
269 | // remove from tree list
|
186 | // remove from tree list
|
270 | tp = mTrees.erase(tp); |
187 | tp = mTrees.erase(tp); |
271 | n++; |
188 | n++; |
272 | } else { |
189 | } else { |
273 | ++tp; |
190 | ++tp; |
274 | }
|
191 | }
|
275 | }
|
192 | }
|
276 | } catch(const IException &e) { |
193 | } catch(const IException &e) { |
277 | context()->throwError(e.message()); |
194 | context()->throwError(e.message()); |
278 | }
|
195 | }
|
279 | return n; |
196 | return n; |
280 | }
|
197 | }
|
281 | 198 | ||
282 | // calculate aggregates for all trees in the internal list
|
199 | // calculate aggregates for all trees in the internal list
|
283 | double Management::aggregate_function(QString expression, QString filter, QString type) |
200 | double Management::aggregate_function(QString expression, QString filter, QString type) |
284 | {
|
201 | {
|
285 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
202 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
286 | TreeWrapper tw;
|
203 | TreeWrapper tw;
|
287 | Expression expr(expression,&tw); |
204 | Expression expr(expression,&tw); |
288 | 205 | ||
289 | double sum = 0.; |
206 | double sum = 0.; |
290 | int n=0; |
207 | int n=0; |
291 | try { |
208 | try { |
292 | 209 | ||
293 | if (filter.isEmpty()) { |
210 | if (filter.isEmpty()) { |
294 | // without filtering
|
211 | // without filtering
|
295 | while (tp!=mTrees.end()) { |
212 | while (tp!=mTrees.end()) { |
296 | tw.setTree(tp->first); |
213 | tw.setTree(tp->first); |
297 | sum += expr.calculate(); |
214 | sum += expr.calculate(); |
298 | ++n; |
215 | ++n; |
299 | ++tp; |
216 | ++tp; |
300 | }
|
217 | }
|
301 | } else { |
218 | } else { |
302 | // with filtering
|
219 | // with filtering
|
303 | Expression filter_expr(filter,&tw); |
220 | Expression filter_expr(filter,&tw); |
304 | filter_expr.enableIncSum(); |
221 | filter_expr.enableIncSum(); |
305 | while (tp!=mTrees.end()) { |
222 | while (tp!=mTrees.end()) { |
306 | tw.setTree(tp->first); |
223 | tw.setTree(tp->first); |
307 | if (filter_expr.calculate()) { |
224 | if (filter_expr.calculate()) { |
308 | sum += expr.calculate(); |
225 | sum += expr.calculate(); |
309 | ++n; |
226 | ++n; |
310 | }
|
227 | }
|
311 | ++tp; |
228 | ++tp; |
312 | }
|
229 | }
|
313 | }
|
230 | }
|
314 | 231 | ||
315 | } catch(const IException &e) { |
232 | } catch(const IException &e) { |
316 | context()->throwError(e.message()); |
233 | context()->throwError(e.message()); |
317 | }
|
234 | }
|
318 | if (type=="sum") |
235 | if (type=="sum") |
319 | return sum; |
236 | return sum; |
320 | if (type=="mean") |
237 | if (type=="mean") |
321 | return n>0?sum/double(n):0.; |
238 | return n>0?sum/double(n):0.; |
322 | return 0.; |
239 | return 0.; |
323 | }
|
240 | }
|
324 | 241 | ||
325 | 242 | ||
326 | // from the range percentile range pctfrom to pctto (each 1..100)
|
243 | // from the range percentile range pctfrom to pctto (each 1..100)
|
327 | int Management::kill(int pctfrom, int pctto, int number) |
244 | int Management::kill(int pctfrom, int pctto, int number) |
328 | {
|
245 | {
|
329 | return remove_percentiles(pctfrom, pctto, number, false); |
246 | return remove_percentiles(pctfrom, pctto, number, false); |
330 | }
|
247 | }
|
331 | 248 | ||
332 | // from the range percentile range pctfrom to pctto (each 1..100)
|
249 | // from the range percentile range pctfrom to pctto (each 1..100)
|
333 | int Management::manage(int pctfrom, int pctto, int number) |
250 | int Management::manage(int pctfrom, int pctto, int number) |
334 | {
|
251 | {
|
335 | return remove_percentiles(pctfrom, pctto, number, true); |
252 | return remove_percentiles(pctfrom, pctto, number, true); |
336 | }
|
253 | }
|
337 | 254 | ||
338 | int Management::manage() |
255 | int Management::manage() |
339 | {
|
256 | {
|
340 | int c = mTrees.count(); |
257 | int c = mTrees.count(); |
341 | for (int i=0;i<mTrees.count();i++) |
258 | for (int i=0;i<mTrees.count();i++) |
342 | mTrees[i].first->remove(removeFoliage(), |
259 | mTrees[i].first->remove(removeFoliage(), |
343 | removeBranch(), |
260 | removeBranch(), |
344 | removeStem()); // remove with current removal fractions |
261 | removeStem()); // remove with current removal fractions |
345 | mTrees.clear(); |
262 | mTrees.clear(); |
346 | return c; |
263 | return c; |
347 | }
|
264 | }
|
348 | 265 | ||
349 | 266 | ||
350 | 267 | ||
351 | void Management::run() |
268 | void Management::run() |
352 | {
|
269 | {
|
353 | mTrees.clear(); |
270 | mTrees.clear(); |
354 | mRemoved=0; |
271 | mRemoved=0; |
355 | qDebug() << "Management::run() called"; |
272 | qDebug() << "Management::run() called"; |
356 | QScriptValue mgmt = mEngine->globalObject().property("manage"); |
273 | QScriptValue mgmt = mEngine->globalObject().property("manage"); |
357 | int year = GlobalSettings::instance()->currentYear(); |
274 | int year = GlobalSettings::instance()->currentYear(); |
358 | mgmt.call(QScriptValue(), QScriptValueList()<<year); |
275 | mgmt.call(QScriptValue(), QScriptValueList()<<year); |
359 | if (mEngine->hasUncaughtException()) |
276 | if (mEngine->hasUncaughtException()) |
360 | qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace(); |
277 | qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace(); |
361 | 278 | ||
362 | if (mRemoved>0) { |
279 | if (mRemoved>0) { |
363 | foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) |
280 | foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) |
364 | ru->cleanTreeList(); |
281 | ru->cleanTreeList(); |
365 | }
|
- | |
- | 282 | }
|
|
- | 283 | }
|
|
- | 284 | ||
- | 285 | void Management::loadScript(const QString &fileName) |
|
- | 286 | {
|
|
- | 287 | mScriptFile = fileName; |
|
- | 288 | ScriptGlobal::loadScript(fileName); |
|
366 | }
|
289 | }
|
367 | 290 | ||
368 | int Management::filter(QVariantList idList) |
291 | int Management::filter(QVariantList idList) |
369 | {
|
292 | {
|
370 | QVector<int> ids; |
293 | QVector<int> ids; |
371 | foreach(const QVariant &v, idList) |
294 | foreach(const QVariant &v, idList) |
372 | if (!v.isNull()) |
295 | if (!v.isNull()) |
373 | ids << v.toInt(); |
296 | ids << v.toInt(); |
374 | // QHash<int, int> ids;
|
297 | // QHash<int, int> ids;
|
375 | // foreach(const QVariant &v, idList)
|
298 | // foreach(const QVariant &v, idList)
|
376 | // ids[v.toInt()] = 1;
|
299 | // ids[v.toInt()] = 1;
|
377 | 300 | ||
378 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
301 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
379 | while (tp!=mTrees.end()) { |
302 | while (tp!=mTrees.end()) { |
380 | if (!ids.contains(tp->first->id()) ) |
303 | if (!ids.contains(tp->first->id()) ) |
381 | tp = mTrees.erase(tp); |
304 | tp = mTrees.erase(tp); |
382 | else
|
305 | else
|
383 | ++tp; |
306 | ++tp; |
384 | }
|
307 | }
|
385 | qDebug() << "Management::filter by id-list:" << mTrees.count(); |
308 | qDebug() << "Management::filter by id-list:" << mTrees.count(); |
386 | return mTrees.count(); |
309 | return mTrees.count(); |
387 | }
|
310 | }
|
388 | 311 | ||
389 | int Management::filter(QString filter) |
312 | int Management::filter(QString filter) |
390 | {
|
313 | {
|
391 | TreeWrapper tw;
|
314 | TreeWrapper tw;
|
392 | Expression expr(filter,&tw); |
315 | Expression expr(filter,&tw); |
393 | expr.enableIncSum(); |
316 | expr.enableIncSum(); |
394 | int n_before = mTrees.count(); |
317 | int n_before = mTrees.count(); |
395 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
318 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
396 | try { |
319 | try { |
397 | while (tp!=mTrees.end()) { |
320 | while (tp!=mTrees.end()) { |
398 | tw.setTree(tp->first); |
321 | tw.setTree(tp->first); |
399 | if (expr.calculate(tw)) |
322 | if (expr.calculate(tw)) |
400 | tp = mTrees.erase(tp); |
323 | tp = mTrees.erase(tp); |
401 | else
|
324 | else
|
402 | ++tp; |
325 | ++tp; |
403 | }
|
326 | }
|
404 | } catch(const IException &e) { |
327 | } catch(const IException &e) { |
405 | context()->throwError(e.message()); |
328 | context()->throwError(e.message()); |
406 | }
|
329 | }
|
407 | 330 | ||
408 | 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)."; |
409 | return mTrees.count(); |
332 | return mTrees.count(); |
410 | }
|
333 | }
|
411 | 334 | ||
412 | int Management::load(int ruindex) |
335 | int Management::load(int ruindex) |
413 | {
|
336 | {
|
414 | Model *m = GlobalSettings::instance()->model(); |
337 | Model *m = GlobalSettings::instance()->model(); |
415 | ResourceUnit *ru = m->ru(ruindex); |
338 | ResourceUnit *ru = m->ru(ruindex); |
416 | if (!ru) |
339 | if (!ru) |
417 | return -1; |
340 | return -1; |
418 | mTrees.clear(); |
341 | mTrees.clear(); |
419 | for (int i=0;i<ru->trees().count();i++) |
342 | for (int i=0;i<ru->trees().count();i++) |
420 | if (!ru->tree(i)->isDead()) |
343 | if (!ru->tree(i)->isDead()) |
421 | mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.)); |
344 | mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.)); |
422 | return mTrees.count(); |
345 | return mTrees.count(); |
423 | }
|
346 | }
|
424 | 347 | ||
425 | int Management::load(QString filter) |
348 | int Management::load(QString filter) |
426 | {
|
349 | {
|
427 | TreeWrapper tw;
|
350 | TreeWrapper tw;
|
428 | Model *m = GlobalSettings::instance()->model(); |
351 | Model *m = GlobalSettings::instance()->model(); |
429 | mTrees.clear(); |
352 | mTrees.clear(); |
430 | AllTreeIterator at(m); |
353 | AllTreeIterator at(m); |
431 | if (filter.isEmpty()) { |
354 | if (filter.isEmpty()) { |
432 | while (Tree *t=at.nextLiving()) |
355 | while (Tree *t=at.nextLiving()) |
433 | if (!t->isDead()) |
356 | if (!t->isDead()) |
434 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
357 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
435 | } else { |
358 | } else { |
436 | Expression expr(filter,&tw); |
359 | Expression expr(filter,&tw); |
437 | expr.enableIncSum(); |
360 | expr.enableIncSum(); |
438 | qDebug() << "filtering with" << filter; |
361 | qDebug() << "filtering with" << filter; |
439 | while (Tree *t=at.nextLiving()) { |
362 | while (Tree *t=at.nextLiving()) { |
440 | tw.setTree(t); |
363 | tw.setTree(t); |
441 | if (!t->isDead() && expr.execute()) |
364 | if (!t->isDead() && expr.execute()) |
442 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
365 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
443 | }
|
366 | }
|
444 | }
|
367 | }
|
445 | return mTrees.count(); |
368 | return mTrees.count(); |
446 | }
|
369 | }
|
447 | 370 | ||
448 | /**
|
371 | /**
|
449 | */
|
372 | */
|
450 | void Management::loadFromTreeList(QList<Tree*>tree_list) |
373 | void Management::loadFromTreeList(QList<Tree*>tree_list) |
451 | {
|
374 | {
|
452 | mTrees.clear(); |
375 | mTrees.clear(); |
453 | for (int i=0;i<tree_list.count();++i) |
376 | for (int i=0;i<tree_list.count();++i) |
454 | mTrees.append(QPair<Tree*, double>(tree_list[i], 0.)); |
377 | mTrees.append(QPair<Tree*, double>(tree_list[i], 0.)); |
455 | }
|
378 | }
|
456 | 379 | ||
457 | // loadFromMap: script access
|
380 | // loadFromMap: script access
|
458 | void Management::loadFromMap(MapGridWrapper *wrap, int key) |
381 | void Management::loadFromMap(MapGridWrapper *wrap, int key) |
459 | {
|
382 | {
|
460 | if (!wrap) { |
383 | if (!wrap) { |
461 | context()->throwError("loadFromMap called with invalid map object!"); |
384 | context()->throwError("loadFromMap called with invalid map object!"); |
462 | return; |
385 | return; |
463 | }
|
386 | }
|
464 | loadFromMap(wrap->map(), key); |
387 | loadFromMap(wrap->map(), key); |
465 | }
|
388 | }
|
466 | 389 | ||
467 | void Management::killSaplings(MapGridWrapper *wrap, int key) |
390 | void Management::killSaplings(MapGridWrapper *wrap, int key) |
468 | {
|
391 | {
|
469 | //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
|
392 | //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
|
470 | //if (!wrap) {
|
393 | //if (!wrap) {
|
471 | // context()->throwError("loadFromMap called with invalid map object!");
|
394 | // context()->throwError("loadFromMap called with invalid map object!");
|
472 | // return;
|
395 | // return;
|
473 | //}
|
396 | //}
|
474 | //loadFromMap(wrap->map(), key);
|
397 | //loadFromMap(wrap->map(), key);
|
475 | // retrieve all sapling trees on the stand:
|
398 | // retrieve all sapling trees on the stand:
|
476 | QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key); |
399 | QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key); |
477 | // for now, just kill em all...
|
400 | // for now, just kill em all...
|
478 | 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) { |
479 | // (*it).second->pixel = 0;
|
402 | // (*it).second->pixel = 0;
|
480 | (*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 |
481 | }
|
404 | }
|
482 | 405 | ||
483 | // 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)
|
484 | }
|
407 | }
|
485 | 408 | ||
486 | /// specify removal fractions
|
409 | /// specify removal fractions
|
487 | /// @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
|
488 | /// @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
|
489 | /// @param litterFrac 0: no change, 1: remove all of soil litter
|
412 | /// @param litterFrac 0: no change, 1: remove all of soil litter
|
490 | /// @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
|
491 | 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) |
492 | {
|
415 | {
|
493 | 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.)) { |
494 | 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())); |
495 | return; |
418 | return; |
496 | }
|
419 | }
|
497 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
420 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
498 | double total_area = 0.; |
421 | double total_area = 0.; |
499 | for (int i=0;i<ru_areas.size();++i) { |
422 | for (int i=0;i<ru_areas.size();++i) { |
500 | ResourceUnit *ru = ru_areas[i].first; |
423 | ResourceUnit *ru = ru_areas[i].first; |
501 | double area_factor = ru_areas[i].second; // 0..1 |
424 | double area_factor = ru_areas[i].second; // 0..1 |
502 | total_area += area_factor; |
425 | total_area += area_factor; |
503 | // swd
|
426 | // swd
|
504 | if (SWDfrac>0.) |
427 | if (SWDfrac>0.) |
505 | ru->snag()->removeCarbon(SWDfrac*area_factor); |
428 | ru->snag()->removeCarbon(SWDfrac*area_factor); |
506 | // soil pools
|
429 | // soil pools
|
507 | 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); |
508 | // qDebug() << ru->index() << area_factor;
|
431 | // qDebug() << ru->index() << area_factor;
|
509 | }
|
432 | }
|
510 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
433 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
511 | }
|
434 | }
|
512 | 435 | ||
513 | /** 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.
|
514 | 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.
|
515 | @param wrap MapGrid to use together with \p key
|
438 | @param wrap MapGrid to use together with \p key
|
516 | @param key ID of the polygon.
|
439 | @param key ID of the polygon.
|
517 | @param slash_fraction 0: no change, 1: 100%
|
440 | @param slash_fraction 0: no change, 1: 100%
|
518 | */
|
441 | */
|
519 | void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction) |
442 | void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction) |
520 | {
|
443 | {
|
521 | if (slash_fraction<0 || slash_fraction>1) { |
444 | if (slash_fraction<0 || slash_fraction>1) { |
522 | 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())); |
523 | return; |
446 | return; |
524 | }
|
447 | }
|
525 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
448 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
526 | double total_area = 0.; |
449 | double total_area = 0.; |
527 | for (int i=0;i<ru_areas.size();++i) { |
450 | for (int i=0;i<ru_areas.size();++i) { |
528 | ResourceUnit *ru = ru_areas[i].first; |
451 | ResourceUnit *ru = ru_areas[i].first; |
529 | double area_factor = ru_areas[i].second; // 0..1 |
452 | double area_factor = ru_areas[i].second; // 0..1 |
530 | total_area += area_factor; |
453 | total_area += area_factor; |
531 | ru->snag()->management(slash_fraction * area_factor); |
454 | ru->snag()->management(slash_fraction * area_factor); |
532 | // qDebug() << ru->index() << area_factor;
|
455 | // qDebug() << ru->index() << area_factor;
|
533 | }
|
456 | }
|
534 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
457 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
535 | 458 | ||
536 | }
|
459 | }
|
537 | 460 | ||
538 | /** 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'.
|
539 | */
|
462 | */
|
540 | void Management::loadFromMap(const MapGrid *map_grid, int key) |
463 | void Management::loadFromMap(const MapGrid *map_grid, int key) |
541 | {
|
464 | {
|
542 | if (!map_grid) { |
465 | if (!map_grid) { |
543 | qDebug() << "invalid parameter for Management::loadFromMap: Map expected!"; |
466 | qDebug() << "invalid parameter for Management::loadFromMap: Map expected!"; |
544 | return; |
467 | return; |
545 | }
|
468 | }
|
546 | if (map_grid->isValid()) { |
469 | if (map_grid->isValid()) { |
547 | QList<Tree*> tree_list = map_grid->trees(key); |
470 | QList<Tree*> tree_list = map_grid->trees(key); |
548 | loadFromTreeList( tree_list ); |
471 | loadFromTreeList( tree_list ); |
549 | } else { |
472 | } else { |
550 | qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded"; |
473 | qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded"; |
551 | }
|
474 | }
|
552 | 475 | ||
553 | }
|
476 | }
|
554 | 477 | ||
555 | 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) |
556 | {
|
479 | {
|
557 | return p1.second < p2.second; |
480 | return p1.second < p2.second; |
558 | }
|
481 | }
|
559 | 482 | ||
560 | void Management::sort(QString statement) |
483 | void Management::sort(QString statement) |
561 | {
|
484 | {
|
562 | TreeWrapper tw;
|
485 | TreeWrapper tw;
|
563 | Expression sorter(statement, &tw); |
486 | Expression sorter(statement, &tw); |
564 | // 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
|
565 | for (int i=0;i<mTrees.count(); ++i) { |
488 | for (int i=0;i<mTrees.count(); ++i) { |
566 | tw.setTree(mTrees.at(i).first); |
489 | tw.setTree(mTrees.at(i).first); |
567 | mTrees[i].second = sorter.execute(); |
490 | mTrees[i].second = sorter.execute(); |
568 | }
|
491 | }
|
569 | // now sort the list....
|
492 | // now sort the list....
|
570 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
493 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
571 | }
|
494 | }
|
572 | 495 | ||
573 | double Management::percentile(int pct) |
496 | double Management::percentile(int pct) |
574 | {
|
497 | {
|
575 | if (mTrees.count()==0) |
498 | if (mTrees.count()==0) |
576 | return -1.; |
499 | return -1.; |
577 | int idx = int( (pct/100.) * mTrees.count()); |
500 | int idx = int( (pct/100.) * mTrees.count()); |
578 | if (idx>=0 && idx<mTrees.count()) |
501 | if (idx>=0 && idx<mTrees.count()) |
579 | return mTrees.at(idx).second; |
502 | return mTrees.at(idx).second; |
580 | else
|
503 | else
|
581 | return -1; |
504 | return -1; |
582 | }
|
505 | }
|
583 | 506 | ||
584 | /// random shuffle of all trees in the list
|
507 | /// random shuffle of all trees in the list
|
585 | void Management::randomize() |
508 | void Management::randomize() |
586 | {
|
509 | {
|
587 | // 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
|
588 | for (int i=0;i<mTrees.count(); ++i) { |
511 | for (int i=0;i<mTrees.count(); ++i) { |
589 | mTrees[i].second = drandom(); |
512 | mTrees[i].second = drandom(); |
590 | }
|
513 | }
|
591 | // now sort the list....
|
514 | // now sort the list....
|
592 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
515 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
593 | 516 | ||
594 | }
|
517 | }
|
595 | 518 | ||
596 | 519 | ||
597 | 520 | ||
598 | 521 | ||
599 | 522 | ||
600 | 523 |