Rev 767 | Rev 793 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 767 | Rev 779 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/management.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/management.cpp': |
2 | /********************************************************************************************
|
2 | /********************************************************************************************
|
3 | ** iLand - an individual based forest landscape and disturbance model
|
3 | ** iLand - an individual based forest landscape and disturbance model
|
4 | ** http://iland.boku.ac.at
|
4 | ** http://iland.boku.ac.at
|
5 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl
|
5 | ** Copyright (C) 2009- Werner Rammer, Rupert Seidl
|
6 | **
|
6 | **
|
7 | ** This program is free software: you can redistribute it and/or modify
|
7 | ** This program is free software: you can redistribute it and/or modify
|
8 | ** it under the terms of the GNU General Public License as published by
|
8 | ** it under the terms of the GNU General Public License as published by
|
9 | ** the Free Software Foundation, either version 3 of the License, or
|
9 | ** the Free Software Foundation, either version 3 of the License, or
|
10 | ** (at your option) any later version.
|
10 | ** (at your option) any later version.
|
11 | **
|
11 | **
|
12 | ** This program is distributed in the hope that it will be useful,
|
12 | ** This program is distributed in the hope that it will be useful,
|
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 | ** GNU General Public License for more details.
|
15 | ** GNU General Public License for more details.
|
16 | **
|
16 | **
|
17 | ** You should have received a copy of the GNU General Public License
|
17 | ** You should have received a copy of the GNU General Public License
|
18 | ** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18 | ** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19 | ********************************************************************************************/
|
19 | ********************************************************************************************/
|
20 | 20 | ||
21 | #include "global.h"
|
21 | #include "global.h"
|
22 | #include "management.h"
|
22 | #include "management.h"
|
23 | #include "helper.h"
|
23 | #include "helper.h"
|
24 | #include "model.h"
|
24 | #include "model.h"
|
25 | #include "resourceunit.h"
|
25 | #include "resourceunit.h"
|
26 | #include "tree.h"
|
26 | #include "tree.h"
|
27 | #include "expressionwrapper.h"
|
27 | #include "expressionwrapper.h"
|
28 | #include "sapling.h"
|
28 | #include "sapling.h"
|
29 | #include "soil.h"
|
29 | #include "soil.h"
|
30 | 30 | ||
31 | //#include "climateconverter.h"
|
31 | //#include "climateconverter.h"
|
32 | //#include "csvfile.h"
|
32 | //#include "csvfile.h"
|
33 | #include "scriptglobal.h"
|
33 | #include "scriptglobal.h"
|
34 | #include "mapgrid.h"
|
34 | #include "mapgrid.h"
|
35 | //#include "modules.h"
|
35 | //#include "modules.h"
|
36 | 36 | ||
37 | #include <QtScript>
|
37 | #include <QtScript>
|
38 | 38 | ||
39 | /** @class Management Management executes management routines.
|
39 | /** @class Management Management executes management routines.
|
40 | @ingroup core
|
40 | @ingroup core
|
41 | The actual iLand management is based on Javascript functions. This class provides
|
41 | The actual iLand management is based on Javascript functions. This class provides
|
42 | the frame for executing the javascript as well as the functions that are called by scripts and
|
42 | the frame for executing the javascript as well as the functions that are called by scripts and
|
43 | that really do the work.
|
43 | that really do the work.
|
44 | See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
|
44 | See http://iland.boku.ac.at/iLand+scripting, http://iland.boku.ac.at/Object+Management for management Javascript API.
|
45 | */
|
45 | */
|
46 | 46 | ||
47 | 47 | ||
48 | // global output function
|
48 | // global output function
|
49 | QString Management::executeScript(QString cmd) |
49 | QString Management::executeScript(QString cmd) |
50 | {
|
50 | {
|
51 | return ScriptGlobal::executeScript(cmd); |
51 | return ScriptGlobal::executeScript(cmd); |
52 | }
|
52 | }
|
53 | 53 | ||
54 | Management::Management() |
54 | Management::Management() |
55 | {
|
55 | {
|
56 | // setup the scripting engine
|
56 | // setup the scripting engine
|
57 | mEngine = GlobalSettings::instance()->scriptEngine(); |
57 | mEngine = GlobalSettings::instance()->scriptEngine(); |
58 | QScriptValue objectValue = mEngine->newQObject(this); |
58 | QScriptValue objectValue = mEngine->newQObject(this); |
59 | mEngine->globalObject().setProperty("management", objectValue); |
59 | mEngine->globalObject().setProperty("management", objectValue); |
60 | 60 | ||
61 | // default values for removal fractions
|
61 | // default values for removal fractions
|
62 | // 100% of the stem, 0% of foliage and branches
|
62 | // 100% of the stem, 0% of foliage and branches
|
63 | mRemoveFoliage = 0.; |
63 | mRemoveFoliage = 0.; |
64 | mRemoveBranch = 0.; |
64 | mRemoveBranch = 0.; |
65 | mRemoveStem = 1.; |
65 | mRemoveStem = 1.; |
66 | 66 | ||
67 | }
|
67 | }
|
68 | 68 | ||
69 | Management::~Management() |
69 | Management::~Management() |
70 | {
|
70 | {
|
71 | }
|
71 | }
|
72 | 72 | ||
73 | 73 | ||
74 | int Management::remain(int number) |
74 | int Management::remain(int number) |
75 | {
|
75 | {
|
76 | qDebug() << "remain called (number): " << number; |
76 | qDebug() << "remain called (number): " << number; |
77 | Model *m = GlobalSettings::instance()->model(); |
77 | Model *m = GlobalSettings::instance()->model(); |
78 | AllTreeIterator at(m); |
78 | AllTreeIterator at(m); |
79 | QList<Tree*> trees; |
79 | QList<Tree*> trees; |
80 | while (Tree *t=at.next()) |
80 | while (Tree *t=at.next()) |
81 | trees.push_back(t); |
81 | trees.push_back(t); |
82 | int to_kill = trees.count() - number; |
82 | int to_kill = trees.count() - number; |
83 | qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove"; |
83 | qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove"; |
84 | for (int i=0;i<to_kill;i++) { |
84 | for (int i=0;i<to_kill;i++) { |
85 | int index = irandom(0, trees.count()-1); |
85 | int index = irandom(0, trees.count()-1); |
86 | trees[index]->remove(); |
86 | trees[index]->remove(); |
87 | trees.removeAt(index); |
87 | trees.removeAt(index); |
88 | }
|
88 | }
|
89 | mRemoved += to_kill; |
89 | mRemoved += to_kill; |
90 | return to_kill; |
90 | return to_kill; |
91 | }
|
91 | }
|
92 | 92 | ||
93 | 93 | ||
94 | int Management::kill() |
94 | int Management::kill() |
95 | {
|
95 | {
|
96 | int c = mTrees.count(); |
96 | int c = mTrees.count(); |
97 | for (int i=0;i<mTrees.count();i++) |
97 | for (int i=0;i<mTrees.count();i++) |
98 | mTrees[i].first->remove(); |
98 | mTrees[i].first->remove(); |
99 | mTrees.clear(); |
99 | mTrees.clear(); |
100 | return c; |
100 | return c; |
101 | }
|
101 | }
|
102 | 102 | ||
103 | int Management::kill(QString filter, double fraction) |
103 | int Management::kill(QString filter, double fraction) |
104 | {
|
104 | {
|
105 | return remove_trees(filter, fraction, false); |
105 | return remove_trees(filter, fraction, false); |
106 | }
|
106 | }
|
107 | int Management::manage(QString filter, double fraction) |
107 | int Management::manage(QString filter, double fraction) |
108 | {
|
108 | {
|
109 | return remove_trees(filter, fraction, true); |
109 | return remove_trees(filter, fraction, true); |
110 | }
|
110 | }
|
111 | 111 | ||
112 | int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management) |
112 | int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management) |
113 | {
|
113 | {
|
114 | if (mTrees.isEmpty()) |
114 | if (mTrees.isEmpty()) |
115 | return 0; |
115 | return 0; |
116 | int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count()); |
116 | int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count()); |
117 | int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1); |
117 | int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1); |
118 | if (index_from>=index_to) |
118 | if (index_from>=index_to) |
119 | return 0; |
119 | return 0; |
120 | qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to; |
120 | qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to; |
121 | int i; |
121 | int i; |
122 | int count = number; |
122 | int count = number; |
123 | if (index_to-index_from <= number) { |
123 | if (index_to-index_from <= number) { |
124 | // kill all
|
124 | // kill all
|
125 | if (management) { |
125 | if (management) { |
126 | // management
|
126 | // management
|
127 | for (i=index_from; i<index_to; i++) |
127 | for (i=index_from; i<index_to; i++) |
128 | mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem()); |
128 | mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem()); |
129 | } else { |
129 | } else { |
130 | // just kill...
|
130 | // just kill...
|
131 | for (i=index_from; i<index_to; i++) |
131 | for (i=index_from; i<index_to; i++) |
132 | mTrees.at(i).first->remove(); |
132 | mTrees.at(i).first->remove(); |
133 | }
|
133 | }
|
134 | count = index_to - index_from; |
134 | count = index_to - index_from; |
135 | } else { |
135 | } else { |
136 | // kill randomly the provided number
|
136 | // kill randomly the provided number
|
137 | int cancel = 1000; |
137 | int cancel = 1000; |
138 | while(number>=0) { |
138 | while(number>=0) { |
139 | int rnd_index = irandom(index_from, index_to); |
139 | int rnd_index = irandom(index_from, index_to); |
140 | if (mTrees[rnd_index].first->isDead()) { |
140 | if (mTrees[rnd_index].first->isDead()) { |
141 | if (--cancel<0) { |
141 | if (--cancel<0) { |
142 | qDebug() << "Management::kill: canceling search." << number << "trees left."; |
142 | qDebug() << "Management::kill: canceling search." << number << "trees left."; |
143 | count-=number; // not all trees were killed |
143 | count-=number; // not all trees were killed |
144 | break; |
144 | break; |
145 | }
|
145 | }
|
146 | continue; |
146 | continue; |
147 | }
|
147 | }
|
148 | cancel = 1000; |
148 | cancel = 1000; |
149 | number--; |
149 | number--; |
150 | if (management) { |
150 | if (management) { |
151 | mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() ); |
151 | mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() ); |
152 | } else { |
152 | } else { |
153 | mTrees[rnd_index].first->remove(); |
153 | mTrees[rnd_index].first->remove(); |
154 | }
|
154 | }
|
155 | }
|
155 | }
|
156 | }
|
156 | }
|
157 | qDebug() << count << "removed."; |
157 | qDebug() << count << "removed."; |
158 | // clean up the tree list...
|
158 | // clean up the tree list...
|
159 | for (int i=mTrees.count()-1; i>=0; --i) { |
159 | for (int i=mTrees.count()-1; i>=0; --i) { |
160 | if (mTrees[i].first->isDead()) |
160 | if (mTrees[i].first->isDead()) |
161 | mTrees.removeAt(i); |
161 | mTrees.removeAt(i); |
162 | }
|
162 | }
|
163 | return count; // killed or manages |
163 | return count; // killed or manages |
164 | }
|
164 | }
|
165 | 165 | ||
166 | /** remove trees from a list and reduce the list.
|
166 | /** remove trees from a list and reduce the list.
|
167 | 167 | ||
168 | */
|
168 | */
|
169 | int Management::remove_trees(QString expression, double fraction, bool management) |
169 | int Management::remove_trees(QString expression, double fraction, bool management) |
170 | {
|
170 | {
|
171 | TreeWrapper tw;
|
171 | TreeWrapper tw;
|
172 | Expression expr(expression,&tw); |
172 | Expression expr(expression,&tw); |
173 | expr.enableIncSum(); |
173 | expr.enableIncSum(); |
174 | int n = 0; |
174 | int n = 0; |
175 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
175 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
176 | try { |
176 | try { |
177 | while (tp!=mTrees.end()) { |
177 | while (tp!=mTrees.end()) { |
178 | tw.setTree(tp->first); |
178 | tw.setTree(tp->first); |
179 | // if expression evaluates to true and if random number below threshold...
|
179 | // if expression evaluates to true and if random number below threshold...
|
180 | if (expr.calculate(tw) && drandom() <=fraction) { |
180 | if (expr.calculate(tw) && drandom() <=fraction) { |
181 | // remove from system
|
181 | // remove from system
|
182 | if (management) |
182 | if (management) |
183 | tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions |
183 | tp->first->remove(removeFoliage(), removeBranch(), removeStem()); // management with removal fractions |
184 | else
|
184 | else
|
185 | tp->first->remove(); // kill |
185 | tp->first->remove(); // kill |
186 | // remove from tree list
|
186 | // remove from tree list
|
187 | tp = mTrees.erase(tp); |
187 | tp = mTrees.erase(tp); |
188 | n++; |
188 | n++; |
189 | } else { |
189 | } else { |
190 | ++tp; |
190 | ++tp; |
191 | }
|
191 | }
|
192 | }
|
192 | }
|
193 | } catch(const IException &e) { |
193 | } catch(const IException &e) { |
194 | context()->throwError(e.message()); |
194 | context()->throwError(e.message()); |
195 | }
|
195 | }
|
196 | return n; |
196 | return n; |
197 | }
|
197 | }
|
198 | 198 | ||
199 | // calculate aggregates for all trees in the internal list
|
199 | // calculate aggregates for all trees in the internal list
|
200 | double Management::aggregate_function(QString expression, QString filter, QString type) |
200 | double Management::aggregate_function(QString expression, QString filter, QString type) |
201 | {
|
201 | {
|
202 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
202 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
203 | TreeWrapper tw;
|
203 | TreeWrapper tw;
|
204 | Expression expr(expression,&tw); |
204 | Expression expr(expression,&tw); |
205 | 205 | ||
206 | double sum = 0.; |
206 | double sum = 0.; |
207 | int n=0; |
207 | int n=0; |
208 | try { |
208 | try { |
209 | 209 | ||
210 | if (filter.isEmpty()) { |
210 | if (filter.isEmpty()) { |
211 | // without filtering
|
211 | // without filtering
|
212 | while (tp!=mTrees.end()) { |
212 | while (tp!=mTrees.end()) { |
213 | tw.setTree(tp->first); |
213 | tw.setTree(tp->first); |
214 | sum += expr.calculate(); |
214 | sum += expr.calculate(); |
215 | ++n; |
215 | ++n; |
216 | ++tp; |
216 | ++tp; |
217 | }
|
217 | }
|
218 | } else { |
218 | } else { |
219 | // with filtering
|
219 | // with filtering
|
220 | Expression filter_expr(filter,&tw); |
220 | Expression filter_expr(filter,&tw); |
221 | filter_expr.enableIncSum(); |
221 | filter_expr.enableIncSum(); |
222 | while (tp!=mTrees.end()) { |
222 | while (tp!=mTrees.end()) { |
223 | tw.setTree(tp->first); |
223 | tw.setTree(tp->first); |
224 | if (filter_expr.calculate()) { |
224 | if (filter_expr.calculate()) { |
225 | sum += expr.calculate(); |
225 | sum += expr.calculate(); |
226 | ++n; |
226 | ++n; |
227 | }
|
227 | }
|
228 | ++tp; |
228 | ++tp; |
229 | }
|
229 | }
|
230 | }
|
230 | }
|
231 | 231 | ||
232 | } catch(const IException &e) { |
232 | } catch(const IException &e) { |
233 | context()->throwError(e.message()); |
233 | context()->throwError(e.message()); |
234 | }
|
234 | }
|
235 | if (type=="sum") |
235 | if (type=="sum") |
236 | return sum; |
236 | return sum; |
237 | if (type=="mean") |
237 | if (type=="mean") |
238 | return n>0?sum/double(n):0.; |
238 | return n>0?sum/double(n):0.; |
239 | return 0.; |
239 | return 0.; |
240 | }
|
240 | }
|
241 | 241 | ||
242 | 242 | ||
243 | // from the range percentile range pctfrom to pctto (each 1..100)
|
243 | // from the range percentile range pctfrom to pctto (each 1..100)
|
244 | int Management::kill(int pctfrom, int pctto, int number) |
244 | int Management::kill(int pctfrom, int pctto, int number) |
245 | {
|
245 | {
|
246 | return remove_percentiles(pctfrom, pctto, number, false); |
246 | return remove_percentiles(pctfrom, pctto, number, false); |
247 | }
|
247 | }
|
248 | 248 | ||
249 | // from the range percentile range pctfrom to pctto (each 1..100)
|
249 | // from the range percentile range pctfrom to pctto (each 1..100)
|
250 | int Management::manage(int pctfrom, int pctto, int number) |
250 | int Management::manage(int pctfrom, int pctto, int number) |
251 | {
|
251 | {
|
252 | return remove_percentiles(pctfrom, pctto, number, true); |
252 | return remove_percentiles(pctfrom, pctto, number, true); |
253 | }
|
253 | }
|
254 | 254 | ||
255 | int Management::manage() |
255 | int Management::manage() |
256 | {
|
256 | {
|
257 | int c = mTrees.count(); |
257 | int c = mTrees.count(); |
258 | for (int i=0;i<mTrees.count();i++) |
258 | for (int i=0;i<mTrees.count();i++) |
259 | mTrees[i].first->remove(removeFoliage(), |
259 | mTrees[i].first->remove(removeFoliage(), |
260 | removeBranch(), |
260 | removeBranch(), |
261 | removeStem()); // remove with current removal fractions |
261 | removeStem()); // remove with current removal fractions |
262 | mTrees.clear(); |
262 | mTrees.clear(); |
263 | return c; |
263 | return c; |
264 | }
|
264 | }
|
265 | 265 | ||
266 | 266 | ||
267 | 267 | ||
268 | void Management::run() |
268 | void Management::run() |
269 | {
|
269 | {
|
270 | mTrees.clear(); |
270 | mTrees.clear(); |
271 | mRemoved=0; |
271 | mRemoved=0; |
272 | qDebug() << "Management::run() called"; |
272 | qDebug() << "Management::run() called"; |
273 | QScriptValue mgmt = mEngine->globalObject().property("manage"); |
273 | QScriptValue mgmt = mEngine->globalObject().property("manage"); |
274 | int year = GlobalSettings::instance()->currentYear(); |
274 | int year = GlobalSettings::instance()->currentYear(); |
275 | mgmt.call(QScriptValue(), QScriptValueList()<<year); |
275 | mgmt.call(QScriptValue(), QScriptValueList()<<year); |
276 | if (mEngine->hasUncaughtException()) |
276 | if (mEngine->hasUncaughtException()) |
277 | qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace(); |
277 | qDebug() << "Script Error occured: " << mEngine->uncaughtException().toString() << "\n" << mEngine->uncaughtExceptionBacktrace(); |
278 | 278 | ||
279 | if (mRemoved>0) { |
279 | if (mRemoved>0) { |
280 | foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) |
280 | foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) |
281 | ru->cleanTreeList(); |
281 | ru->cleanTreeList(); |
282 | }
|
282 | }
|
283 | }
|
283 | }
|
284 | 284 | ||
285 | void Management::loadScript(const QString &fileName) |
285 | void Management::loadScript(const QString &fileName) |
286 | {
|
286 | {
|
287 | mScriptFile = fileName; |
287 | mScriptFile = fileName; |
288 | ScriptGlobal::loadScript(fileName); |
288 | ScriptGlobal::loadScript(fileName); |
289 | }
|
289 | }
|
290 | 290 | ||
291 | int Management::filter(QVariantList idList) |
291 | int Management::filter(QVariantList idList) |
292 | {
|
292 | {
|
293 | QVector<int> ids; |
293 | QVector<int> ids; |
294 | foreach(const QVariant &v, idList) |
294 | foreach(const QVariant &v, idList) |
295 | if (!v.isNull()) |
295 | if (!v.isNull()) |
296 | ids << v.toInt(); |
296 | ids << v.toInt(); |
297 | // QHash<int, int> ids;
|
297 | // QHash<int, int> ids;
|
298 | // foreach(const QVariant &v, idList)
|
298 | // foreach(const QVariant &v, idList)
|
299 | // ids[v.toInt()] = 1;
|
299 | // ids[v.toInt()] = 1;
|
300 | 300 | ||
301 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
301 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
302 | while (tp!=mTrees.end()) { |
302 | while (tp!=mTrees.end()) { |
303 | if (!ids.contains(tp->first->id()) ) |
303 | if (!ids.contains(tp->first->id()) ) |
304 | tp = mTrees.erase(tp); |
304 | tp = mTrees.erase(tp); |
305 | else
|
305 | else
|
306 | ++tp; |
306 | ++tp; |
307 | }
|
307 | }
|
308 | qDebug() << "Management::filter by id-list:" << mTrees.count(); |
308 | qDebug() << "Management::filter by id-list:" << mTrees.count(); |
309 | return mTrees.count(); |
309 | return mTrees.count(); |
310 | }
|
310 | }
|
311 | 311 | ||
312 | int Management::filter(QString filter) |
312 | int Management::filter(QString filter) |
313 | {
|
313 | {
|
314 | TreeWrapper tw;
|
314 | TreeWrapper tw;
|
315 | Expression expr(filter,&tw); |
315 | Expression expr(filter,&tw); |
316 | expr.enableIncSum(); |
316 | expr.enableIncSum(); |
317 | int n_before = mTrees.count(); |
317 | int n_before = mTrees.count(); |
318 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
318 | QList<QPair<Tree*, double> >::iterator tp=mTrees.begin(); |
319 | try { |
319 | try { |
320 | while (tp!=mTrees.end()) { |
320 | while (tp!=mTrees.end()) { |
321 | tw.setTree(tp->first); |
321 | tw.setTree(tp->first); |
322 | if (expr.calculate(tw)) |
322 | if (expr.calculate(tw)) |
323 | tp = mTrees.erase(tp); |
323 | tp = mTrees.erase(tp); |
324 | else
|
324 | else
|
325 | ++tp; |
325 | ++tp; |
326 | }
|
326 | }
|
327 | } catch(const IException &e) { |
327 | } catch(const IException &e) { |
328 | context()->throwError(e.message()); |
328 | context()->throwError(e.message()); |
329 | }
|
329 | }
|
330 | 330 | ||
331 | qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count() << "trees (before/after filtering)."; |
331 | qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count() << "trees (before/after filtering)."; |
332 | return mTrees.count(); |
332 | return mTrees.count(); |
333 | }
|
333 | }
|
334 | 334 | ||
335 | int Management::load(int ruindex) |
335 | int Management::load(int ruindex) |
336 | {
|
336 | {
|
337 | Model *m = GlobalSettings::instance()->model(); |
337 | Model *m = GlobalSettings::instance()->model(); |
338 | ResourceUnit *ru = m->ru(ruindex); |
338 | ResourceUnit *ru = m->ru(ruindex); |
339 | if (!ru) |
339 | if (!ru) |
340 | return -1; |
340 | return -1; |
341 | mTrees.clear(); |
341 | mTrees.clear(); |
342 | for (int i=0;i<ru->trees().count();i++) |
342 | for (int i=0;i<ru->trees().count();i++) |
343 | if (!ru->tree(i)->isDead()) |
343 | if (!ru->tree(i)->isDead()) |
344 | mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.)); |
344 | mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.)); |
345 | return mTrees.count(); |
345 | return mTrees.count(); |
346 | }
|
346 | }
|
347 | 347 | ||
348 | int Management::load(QString filter) |
348 | int Management::load(QString filter) |
349 | {
|
349 | {
|
350 | TreeWrapper tw;
|
350 | TreeWrapper tw;
|
351 | Model *m = GlobalSettings::instance()->model(); |
351 | Model *m = GlobalSettings::instance()->model(); |
352 | mTrees.clear(); |
352 | mTrees.clear(); |
353 | AllTreeIterator at(m); |
353 | AllTreeIterator at(m); |
354 | if (filter.isEmpty()) { |
354 | if (filter.isEmpty()) { |
355 | while (Tree *t=at.nextLiving()) |
355 | while (Tree *t=at.nextLiving()) |
356 | if (!t->isDead()) |
356 | if (!t->isDead()) |
357 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
357 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
358 | } else { |
358 | } else { |
359 | Expression expr(filter,&tw); |
359 | Expression expr(filter,&tw); |
360 | expr.enableIncSum(); |
360 | expr.enableIncSum(); |
361 | qDebug() << "filtering with" << filter; |
361 | qDebug() << "filtering with" << filter; |
362 | while (Tree *t=at.nextLiving()) { |
362 | while (Tree *t=at.nextLiving()) { |
363 | tw.setTree(t); |
363 | tw.setTree(t); |
364 | if (!t->isDead() && expr.execute()) |
364 | if (!t->isDead() && expr.execute()) |
365 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
365 | mTrees.push_back(QPair<Tree*, double>(t, 0.)); |
366 | }
|
366 | }
|
367 | }
|
367 | }
|
368 | return mTrees.count(); |
368 | return mTrees.count(); |
369 | }
|
369 | }
|
370 | 370 | ||
371 | /**
|
371 | /**
|
372 | */
|
372 | */
|
373 | void Management::loadFromTreeList(QList<Tree*>tree_list) |
373 | void Management::loadFromTreeList(QList<Tree*>tree_list) |
374 | {
|
374 | {
|
375 | mTrees.clear(); |
375 | mTrees.clear(); |
376 | for (int i=0;i<tree_list.count();++i) |
376 | for (int i=0;i<tree_list.count();++i) |
377 | mTrees.append(QPair<Tree*, double>(tree_list[i], 0.)); |
377 | mTrees.append(QPair<Tree*, double>(tree_list[i], 0.)); |
378 | }
|
378 | }
|
379 | 379 | ||
380 | // loadFromMap: script access
|
380 | // loadFromMap: script access
|
381 | void Management::loadFromMap(MapGridWrapper *wrap, int key) |
381 | void Management::loadFromMap(MapGridWrapper *wrap, int key) |
382 | {
|
382 | {
|
383 | if (!wrap) { |
383 | if (!wrap) { |
384 | context()->throwError("loadFromMap called with invalid map object!"); |
384 | context()->throwError("loadFromMap called with invalid map object!"); |
385 | return; |
385 | return; |
386 | }
|
386 | }
|
387 | loadFromMap(wrap->map(), key); |
387 | loadFromMap(wrap->map(), key); |
388 | }
|
388 | }
|
389 | 389 | ||
390 | void Management::killSaplings(MapGridWrapper *wrap, int key) |
390 | void Management::killSaplings(MapGridWrapper *wrap, int key) |
391 | {
|
391 | {
|
392 | //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
|
392 | //MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
|
393 | //if (!wrap) {
|
393 | //if (!wrap) {
|
394 | // context()->throwError("loadFromMap called with invalid map object!");
|
394 | // context()->throwError("loadFromMap called with invalid map object!");
|
395 | // return;
|
395 | // return;
|
396 | //}
|
396 | //}
|
397 | //loadFromMap(wrap->map(), key);
|
397 | //loadFromMap(wrap->map(), key);
|
398 | // retrieve all sapling trees on the stand:
|
398 | // retrieve all sapling trees on the stand:
|
399 | QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key); |
399 | QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key); |
400 | // for now, just kill em all...
|
400 | // for now, just kill em all...
|
401 | for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it) { |
401 | for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it) { |
402 | // (*it).second->pixel = 0;
|
402 | // (*it).second->pixel = 0;
|
403 | (*it).first->changeSapling().clearSapling( *(*it).second, false); // kill and move biomass to soil |
403 | (*it).first->changeSapling().clearSapling( *(*it).second, false); // kill and move biomass to soil |
404 | }
|
404 | }
|
405 | 405 | ||
406 | // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
|
406 | // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
|
407 | }
|
407 | }
|
408 | 408 | ||
409 | /// specify removal fractions
|
409 | /// specify removal fractions
|
410 | /// @param SWDFrac 0: no change, 1: remove all of standing woody debris
|
410 | /// @param SWDFrac 0: no change, 1: remove all of standing woody debris
|
411 | /// @param DWDfrac 0: no change, 1: remove all of downled woody debris
|
411 | /// @param DWDfrac 0: no change, 1: remove all of downled woody debris
|
412 | /// @param litterFrac 0: no change, 1: remove all of soil litter
|
412 | /// @param litterFrac 0: no change, 1: remove all of soil litter
|
413 | /// @param soilFrac 0: no change, 1: remove all of soil organic matter
|
413 | /// @param soilFrac 0: no change, 1: remove all of soil organic matter
|
414 | void Management::removeSoilCarbon(MapGridWrapper *wrap, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac) |
414 | void Management::removeSoilCarbon(MapGridWrapper *wrap, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac) |
415 | {
|
415 | {
|
416 | if (!(SWDfrac>=0. && SWDfrac<=1. && DWDfrac>=0. && DWDfrac<=1. && soilFrac>=0. && soilFrac<=1. && litterFrac>=0. && litterFrac<=1.)) { |
416 | if (!(SWDfrac>=0. && SWDfrac<=1. && DWDfrac>=0. && DWDfrac<=1. && soilFrac>=0. && soilFrac<=1. && litterFrac>=0. && litterFrac<=1.)) { |
417 | context()->throwError(QString("removeSoilCarbon called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString())); |
417 | context()->throwError(QString("removeSoilCarbon called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString())); |
418 | return; |
418 | return; |
419 | }
|
419 | }
|
420 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
420 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
421 | double total_area = 0.; |
421 | double total_area = 0.; |
422 | for (int i=0;i<ru_areas.size();++i) { |
422 | for (int i=0;i<ru_areas.size();++i) { |
423 | ResourceUnit *ru = ru_areas[i].first; |
423 | ResourceUnit *ru = ru_areas[i].first; |
424 | double area_factor = ru_areas[i].second; // 0..1 |
424 | double area_factor = ru_areas[i].second; // 0..1 |
425 | total_area += area_factor; |
425 | total_area += area_factor; |
426 | // swd
|
426 | // swd
|
427 | if (SWDfrac>0.) |
427 | if (SWDfrac>0.) |
428 | ru->snag()->removeCarbon(SWDfrac*area_factor); |
428 | ru->snag()->removeCarbon(SWDfrac*area_factor); |
429 | // soil pools
|
429 | // soil pools
|
430 | ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor); |
430 | ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor); |
431 | // qDebug() << ru->index() << area_factor;
|
431 | // qDebug() << ru->index() << area_factor;
|
432 | }
|
432 | }
|
433 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
433 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
434 | }
|
434 | }
|
435 | 435 | ||
436 | /** slash snags (SWD and otherWood-Pools) of polygon \p key on the map \p wrap.
|
436 | /** slash snags (SWD and otherWood-Pools) of polygon \p key on the map \p wrap.
|
437 | The factor is scaled to the overlapping area of \p key on the resource unit.
|
437 | The factor is scaled to the overlapping area of \p key on the resource unit.
|
438 | @param wrap MapGrid to use together with \p key
|
438 | @param wrap MapGrid to use together with \p key
|
439 | @param key ID of the polygon.
|
439 | @param key ID of the polygon.
|
440 | @param slash_fraction 0: no change, 1: 100%
|
440 | @param slash_fraction 0: no change, 1: 100%
|
441 | */
|
441 | */
|
442 | void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction) |
442 | void Management::slashSnags(MapGridWrapper *wrap, int key, double slash_fraction) |
443 | {
|
443 | {
|
444 | if (slash_fraction<0 || slash_fraction>1) { |
444 | if (slash_fraction<0 || slash_fraction>1) { |
445 | context()->throwError(QString("slashSnags called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString())); |
445 | context()->throwError(QString("slashSnags called with invalid parameters!!\nArgs: %1").arg(context()->argumentsObject().toString())); |
446 | return; |
446 | return; |
447 | }
|
447 | }
|
448 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
448 | QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key); |
449 | double total_area = 0.; |
449 | double total_area = 0.; |
450 | for (int i=0;i<ru_areas.size();++i) { |
450 | for (int i=0;i<ru_areas.size();++i) { |
451 | ResourceUnit *ru = ru_areas[i].first; |
451 | ResourceUnit *ru = ru_areas[i].first; |
452 | double area_factor = ru_areas[i].second; // 0..1 |
452 | double area_factor = ru_areas[i].second; // 0..1 |
453 | total_area += area_factor; |
453 | total_area += area_factor; |
454 | ru->snag()->management(slash_fraction * area_factor); |
454 | ru->snag()->management(slash_fraction * area_factor); |
455 | // qDebug() << ru->index() << area_factor;
|
455 | // qDebug() << ru->index() << area_factor;
|
456 | }
|
456 | }
|
457 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
457 | qDebug() << "total area" << total_area << "of" << wrap->map()->area(key); |
458 | 458 | ||
459 | }
|
459 | }
|
460 | 460 | ||
461 | /** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
|
461 | /** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
|
462 | */
|
462 | */
|
463 | void Management::loadFromMap(const MapGrid *map_grid, int key) |
463 | void Management::loadFromMap(const MapGrid *map_grid, int key) |
464 | {
|
464 | {
|
465 | if (!map_grid) { |
465 | if (!map_grid) { |
466 | qDebug() << "invalid parameter for Management::loadFromMap: Map expected!"; |
466 | qDebug() << "invalid parameter for Management::loadFromMap: Map expected!"; |
467 | return; |
467 | return; |
468 | }
|
468 | }
|
469 | if (map_grid->isValid()) { |
469 | if (map_grid->isValid()) { |
470 | QList<Tree*> tree_list = map_grid->trees(key); |
470 | QList<Tree*> tree_list = map_grid->trees(key); |
471 | loadFromTreeList( tree_list ); |
471 | loadFromTreeList( tree_list ); |
472 | } else { |
472 | } else { |
473 | qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded"; |
473 | qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded"; |
474 | }
|
474 | }
|
475 | 475 | ||
476 | }
|
476 | }
|
477 | 477 | ||
478 | bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2) |
478 | bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2) |
479 | {
|
479 | {
|
480 | return p1.second < p2.second; |
480 | return p1.second < p2.second; |
481 | }
|
481 | }
|
482 | 482 | ||
483 | void Management::sort(QString statement) |
483 | void Management::sort(QString statement) |
484 | {
|
484 | {
|
485 | TreeWrapper tw;
|
485 | TreeWrapper tw;
|
486 | Expression sorter(statement, &tw); |
486 | Expression sorter(statement, &tw); |
487 | // fill the "value" part of the tree storage with a value for each tree
|
487 | // fill the "value" part of the tree storage with a value for each tree
|
488 | for (int i=0;i<mTrees.count(); ++i) { |
488 | for (int i=0;i<mTrees.count(); ++i) { |
489 | tw.setTree(mTrees.at(i).first); |
489 | tw.setTree(mTrees.at(i).first); |
490 | mTrees[i].second = sorter.execute(); |
490 | mTrees[i].second = sorter.execute(); |
491 | }
|
491 | }
|
492 | // now sort the list....
|
492 | // now sort the list....
|
493 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
493 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
494 | }
|
494 | }
|
495 | 495 | ||
496 | double Management::percentile(int pct) |
496 | double Management::percentile(int pct) |
497 | {
|
497 | {
|
498 | if (mTrees.count()==0) |
498 | if (mTrees.count()==0) |
499 | return -1.; |
499 | return -1.; |
500 | int idx = int( (pct/100.) * mTrees.count()); |
500 | int idx = int( (pct/100.) * mTrees.count()); |
501 | if (idx>=0 && idx<mTrees.count()) |
501 | if (idx>=0 && idx<mTrees.count()) |
502 | return mTrees.at(idx).second; |
502 | return mTrees.at(idx).second; |
503 | else
|
503 | else
|
504 | return -1; |
504 | return -1; |
505 | }
|
505 | }
|
506 | 506 | ||
507 | /// random shuffle of all trees in the list
|
507 | /// random shuffle of all trees in the list
|
508 | void Management::randomize() |
508 | void Management::randomize() |
509 | {
|
509 | {
|
510 | // fill the "value" part of the tree storage with a random value for each tree
|
510 | // fill the "value" part of the tree storage with a random value for each tree
|
511 | for (int i=0;i<mTrees.count(); ++i) { |
511 | for (int i=0;i<mTrees.count(); ++i) { |
512 | mTrees[i].second = drandom(); |
512 | mTrees[i].second = drandom(); |
513 | }
|
513 | }
|
514 | // now sort the list....
|
514 | // now sort the list....
|
515 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
515 | qSort(mTrees.begin(), mTrees.end(), treePairValue); |
516 | 516 | ||
517 | }
|
517 | }
|
518 | 518 | ||
519 | 519 | ||
520 | 520 | ||
521 | 521 | ||
522 | 522 | ||
523 | 523 |