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