Rev 1034 | Rev 1066 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1034 | Rev 1061 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/modelcontroller.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/modelcontroller.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 | /** ModelController is a helper class used to control the flow of operations during a model run.
|
21 | /** ModelController is a helper class used to control the flow of operations during a model run.
|
22 | The ModelController encapsulates the Model class and is the main control unit. It is used by the
|
22 | The ModelController encapsulates the Model class and is the main control unit. It is used by the
|
23 | iLand GUI as well as the command line version (ilandc).
|
23 | iLand GUI as well as the command line version (ilandc).
|
24 | 24 | ||
25 | */
|
25 | */
|
26 | 26 | ||
27 | #include "global.h"
|
27 | #include "global.h"
|
28 | #include "modelcontroller.h"
|
28 | #include "modelcontroller.h"
|
29 | #include <QObject>
|
29 | #include <QObject>
|
30 | 30 | ||
31 | #include "model.h"
|
31 | #include "model.h"
|
32 | #include "debugtimer.h"
|
32 | #include "debugtimer.h"
|
33 | #include "helper.h"
|
33 | #include "helper.h"
|
34 | #include "expression.h"
|
34 | #include "expression.h"
|
35 | #include "expressionwrapper.h"
|
35 | #include "expressionwrapper.h"
|
36 | #include "../output/outputmanager.h"
|
36 | #include "../output/outputmanager.h"
|
37 | 37 | ||
38 | #include "species.h"
|
38 | #include "species.h"
|
39 | #include "speciesset.h"
|
39 | #include "speciesset.h"
|
40 | #include "mapgrid.h"
|
40 | #include "mapgrid.h"
|
41 | #include "statdata.h"
|
41 | #include "statdata.h"
|
42 | 42 | ||
43 | #ifdef ILAND_GUI
|
43 | #ifdef ILAND_GUI
|
44 | #include "mainwindow.h" // for the debug message buffering
|
44 | #include "mainwindow.h" // for the debug message buffering
|
45 | #endif
|
45 | #endif
|
46 | 46 | ||
47 | ModelController::ModelController() |
47 | ModelController::ModelController() |
48 | {
|
48 | {
|
49 | mModel = NULL; |
49 | mModel = NULL; |
50 | mPaused = false; |
50 | mPaused = false; |
51 | mRunning = false; |
51 | mRunning = false; |
52 | mHasError = false; |
52 | mHasError = false; |
53 | mYearsToRun = 0; |
53 | mYearsToRun = 0; |
54 | mViewerWindow = 0; |
54 | mViewerWindow = 0; |
55 | mDynamicOutputEnabled = false; |
55 | mDynamicOutputEnabled = false; |
56 | }
|
56 | }
|
57 | 57 | ||
58 | ModelController::~ModelController() |
58 | ModelController::~ModelController() |
59 | {
|
59 | {
|
60 | destroy(); |
60 | destroy(); |
61 | }
|
61 | }
|
62 | 62 | ||
63 | void ModelController::connectSignals() |
63 | void ModelController::connectSignals() |
64 | {
|
64 | {
|
65 | if (!mViewerWindow) |
65 | if (!mViewerWindow) |
66 | return; |
66 | return; |
67 | #ifdef ILAND_GUI
|
67 | #ifdef ILAND_GUI
|
68 | connect(this,SIGNAL(bufferLogs(bool)), mViewerWindow, SLOT(bufferedLog(bool))); |
68 | connect(this,SIGNAL(bufferLogs(bool)), mViewerWindow, SLOT(bufferedLog(bool))); |
69 | #endif
|
69 | #endif
|
70 | }
|
70 | }
|
71 | 71 | ||
72 | /// prepare a list of all (active) species
|
72 | /// prepare a list of all (active) species
|
73 | QHash<QString, QString> ModelController::availableSpecies() |
73 | QHash<QString, QString> ModelController::availableSpecies() |
74 | {
|
74 | {
|
75 | QHash<QString, QString> list; |
75 | QHash<QString, QString> list; |
76 | if (mModel) { |
76 | if (mModel) { |
77 | SpeciesSet *set = mModel->speciesSet(); |
77 | SpeciesSet *set = mModel->speciesSet(); |
78 | if (!set) |
78 | if (!set) |
79 | throw IException("there are 0 or more than one species sets."); |
79 | throw IException("there are 0 or more than one species sets."); |
80 | foreach (const Species *s, set->activeSpecies()) { |
80 | foreach (const Species *s, set->activeSpecies()) { |
81 | list[s->id()] = s->name(); |
81 | list[s->id()] = s->name(); |
82 | }
|
82 | }
|
83 | }
|
83 | }
|
84 | return list; |
84 | return list; |
85 | }
|
85 | }
|
86 | 86 | ||
87 | bool ModelController::canCreate() |
87 | bool ModelController::canCreate() |
88 | {
|
88 | {
|
89 | if (mModel) |
89 | if (mModel) |
90 | return false; |
90 | return false; |
91 | return true; |
91 | return true; |
92 | }
|
92 | }
|
93 | 93 | ||
94 | bool ModelController::canDestroy() |
94 | bool ModelController::canDestroy() |
95 | {
|
95 | {
|
96 | return mModel != NULL; |
96 | return mModel != NULL; |
97 | }
|
97 | }
|
98 | 98 | ||
99 | bool ModelController::canRun() |
99 | bool ModelController::canRun() |
100 | {
|
100 | {
|
101 | if (mModel && mModel->isSetup()) |
101 | if (mModel && mModel->isSetup()) |
102 | return true; |
102 | return true; |
103 | return false; |
103 | return false; |
104 | }
|
104 | }
|
105 | 105 | ||
106 | bool ModelController::isRunning() |
106 | bool ModelController::isRunning() |
107 | {
|
107 | {
|
108 | return mRunning; |
108 | return mRunning; |
109 | }
|
109 | }
|
110 | 110 | ||
111 | bool ModelController::isFinished() |
111 | bool ModelController::isFinished() |
112 | {
|
112 | {
|
113 | if (!mModel) |
113 | if (!mModel) |
114 | return false; |
114 | return false; |
115 | return canRun() && !isRunning() && mFinished; |
115 | return canRun() && !isRunning() && mFinished; |
116 | }
|
116 | }
|
117 | 117 | ||
118 | bool ModelController::isPaused() |
118 | bool ModelController::isPaused() |
119 | {
|
119 | {
|
120 | return mPaused; |
120 | return mPaused; |
121 | }
|
121 | }
|
122 | 122 | ||
123 | int ModelController::currentYear() const |
123 | int ModelController::currentYear() const |
124 | {
|
124 | {
|
125 | return GlobalSettings::instance()->currentYear(); |
125 | return GlobalSettings::instance()->currentYear(); |
126 | }
|
126 | }
|
127 | 127 | ||
128 | void ModelController::setFileName(QString initFileName) |
128 | void ModelController::setFileName(QString initFileName) |
129 | {
|
129 | {
|
130 | mInitFile = initFileName; |
130 | mInitFile = initFileName; |
131 | try { |
131 | try { |
132 | GlobalSettings::instance()->loadProjectFile(mInitFile); |
132 | GlobalSettings::instance()->loadProjectFile(mInitFile); |
133 | } catch(const IException &e) { |
133 | } catch(const IException &e) { |
134 | QString error_msg = e.message(); |
134 | QString error_msg = e.message(); |
135 | Helper::msg(error_msg); |
135 | Helper::msg(error_msg); |
136 | mHasError = true; |
136 | mHasError = true; |
137 | mLastError = error_msg; |
137 | mLastError = error_msg; |
138 | qDebug() << error_msg; |
138 | qDebug() << error_msg; |
139 | }
|
139 | }
|
140 | }
|
140 | }
|
141 | 141 | ||
142 | void ModelController::create() |
142 | void ModelController::create() |
143 | {
|
143 | {
|
144 | if (!canCreate()) |
144 | if (!canCreate()) |
145 | return; |
145 | return; |
146 | emit bufferLogs(true); |
146 | emit bufferLogs(true); |
147 | 147 | ||
148 | try { |
148 | try { |
149 | mHasError = false; |
149 | mHasError = false; |
150 | DebugTimer::clearAllTimers(); |
150 | DebugTimer::clearAllTimers(); |
151 | mModel = new Model(); |
151 | mModel = new Model(); |
152 | mModel->loadProject(); |
152 | mModel->loadProject(); |
153 | if (!mModel->isSetup()) { |
153 | if (!mModel->isSetup()) { |
154 | mHasError = true; |
154 | mHasError = true; |
155 | mLastError = "An error occured during the loading of the project. Please check the logs."; |
155 | mLastError = "An error occured during the loading of the project. Please check the logs."; |
156 | return; |
156 | return; |
157 | }
|
157 | }
|
158 | 158 | ||
159 | // reset clock...
|
159 | // reset clock...
|
160 | GlobalSettings::instance()->setCurrentYear(1); // reset clock |
160 | GlobalSettings::instance()->setCurrentYear(1); // reset clock |
161 | // initialization of trees, output on startup
|
161 | // initialization of trees, output on startup
|
162 | mModel->beforeRun(); |
162 | mModel->beforeRun(); |
163 | } catch(const IException &e) { |
163 | } catch(const IException &e) { |
164 | QString error_msg = e.message(); |
164 | QString error_msg = e.message(); |
165 | Helper::msg(error_msg); |
165 | Helper::msg(error_msg); |
166 | mLastError = error_msg; |
166 | mLastError = error_msg; |
167 | mHasError = true; |
167 | mHasError = true; |
168 | qDebug() << error_msg; |
168 | qDebug() << error_msg; |
169 | }
|
169 | }
|
170 | emit bufferLogs(false); |
170 | emit bufferLogs(false); |
171 | 171 | ||
172 | qDebug() << "Model created."; |
172 | qDebug() << "Model created."; |
173 | }
|
173 | }
|
174 | 174 | ||
175 | void ModelController::destroy() |
175 | void ModelController::destroy() |
176 | {
|
176 | {
|
177 | if (canDestroy()) { |
177 | if (canDestroy()) { |
178 | Model *m = mModel; |
178 | Model *m = mModel; |
179 | mModel = 0; |
179 | mModel = 0; |
180 | delete m; |
180 | delete m; |
181 | GlobalSettings::instance()->setCurrentYear(0); |
181 | GlobalSettings::instance()->setCurrentYear(0); |
182 | qDebug() << "ModelController: Model destroyed."; |
182 | qDebug() << "ModelController: Model destroyed."; |
183 | }
|
183 | }
|
184 | }
|
184 | }
|
185 | 185 | ||
186 | void ModelController::runloop() |
186 | void ModelController::runloop() |
187 | {
|
187 | {
|
188 | static QTime sLastTime = QTime::currentTime(); |
188 | static QTime sLastTime = QTime::currentTime(); |
189 | #ifdef ILAND_GUI
|
189 | #ifdef ILAND_GUI
|
190 | // QApplication::processEvents();
|
190 | // QApplication::processEvents();
|
191 | #else
|
191 | #else
|
192 | // QCoreApplication::processEvents();
|
192 | // QCoreApplication::processEvents();
|
193 | #endif
|
193 | #endif
|
194 | if (mPaused) |
194 | if (mPaused) |
195 | return; |
195 | return; |
196 | bool doStop = false; |
196 | bool doStop = false; |
197 | mHasError = false; |
197 | mHasError = false; |
198 | if (GlobalSettings::instance()->currentYear()<=1) { |
198 | if (GlobalSettings::instance()->currentYear()<=1) { |
199 | sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation |
199 | sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation |
200 | }
|
200 | }
|
201 | 201 | ||
202 | if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) { |
202 | if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) { |
203 | emit bufferLogs(true); |
203 | emit bufferLogs(true); |
204 | 204 | ||
205 | mHasError = runYear(); // do the work! |
205 | mHasError = runYear(); // do the work! |
206 | 206 | ||
207 | mRunning = true; |
207 | mRunning = true; |
208 | emit year(GlobalSettings::instance()->currentYear()); |
208 | emit year(GlobalSettings::instance()->currentYear()); |
209 | if (!mHasError) { |
209 | if (!mHasError) { |
210 | int elapsed = sLastTime.msecsTo(QTime::currentTime()); |
210 | int elapsed = sLastTime.msecsTo(QTime::currentTime()); |
211 | int time=0; |
211 | int time=0; |
212 | if (currentYear()%50==0 && elapsed>10000) |
212 | if (currentYear()%50==0 && elapsed>10000) |
213 | time = 100; // a 100ms pause... |
213 | time = 100; // a 100ms pause... |
214 | if (currentYear()%100==0 && elapsed>10000) { |
214 | if (currentYear()%100==0 && elapsed>10000) { |
215 | time = 500; // a 500ms pause... |
215 | time = 500; // a 500ms pause... |
216 | }
|
216 | }
|
217 | if (time>0) { |
217 | if (time>0) { |
218 | sLastTime = QTime::currentTime(); // reset clock |
218 | sLastTime = QTime::currentTime(); // reset clock |
219 | qDebug() << "--- little break ---- (after " << elapsed << "ms)."; |
219 | qDebug() << "--- little break ---- (after " << elapsed << "ms)."; |
220 | //QTimer::singleShot(time,this, SLOT(runloop()));
|
220 | //QTimer::singleShot(time,this, SLOT(runloop()));
|
221 | }
|
221 | }
|
222 | 222 | ||
223 | } else { |
223 | } else { |
224 | doStop = true; // an error occured |
224 | doStop = true; // an error occured |
225 | mLastError = "An error occured while running the model. Please check the logs."; |
225 | mLastError = "An error occured while running the model. Please check the logs."; |
226 | mHasError = true; |
226 | mHasError = true; |
227 | }
|
227 | }
|
228 | 228 | ||
229 | } else { |
229 | } else { |
230 | doStop = true; // all years simulated |
230 | doStop = true; // all years simulated |
231 | }
|
231 | }
|
232 | 232 | ||
233 | if (doStop || mCanceled) { |
233 | if (doStop || mCanceled) { |
234 | // finished
|
234 | // finished
|
235 | internalStop(); |
235 | internalStop(); |
236 | }
|
236 | }
|
237 | 237 | ||
238 | #ifdef ILAND_GUI
|
238 | #ifdef ILAND_GUI
|
239 | QApplication::processEvents(); |
239 | QApplication::processEvents(); |
240 | #else
|
240 | #else
|
241 | QCoreApplication::processEvents(); |
241 | QCoreApplication::processEvents(); |
242 | #endif
|
242 | #endif
|
243 | }
|
243 | }
|
244 | 244 | ||
245 | bool ModelController::internalRun() |
245 | bool ModelController::internalRun() |
246 | {
|
246 | {
|
247 | // main loop
|
247 | // main loop
|
248 | try { |
248 | try { |
249 | while (mRunning && !mPaused && !mFinished) { |
249 | while (mRunning && !mPaused && !mFinished) { |
250 | runloop(); // start the running loop |
250 | runloop(); // start the running loop |
251 | }
|
251 | }
|
252 | } catch (IException &e) { |
252 | } catch (IException &e) { |
253 | #ifdef ILAND_GUI
|
253 | #ifdef ILAND_GUI
|
254 | Helper::msg(e.message()); |
254 | Helper::msg(e.message()); |
255 | #else
|
255 | #else
|
256 | qDebug() << e.message(); |
256 | qDebug() << e.message(); |
257 | #endif
|
257 | #endif
|
258 | 258 | ||
259 | }
|
259 | }
|
260 | 260 | ||
261 | return isFinished(); |
261 | return isFinished(); |
262 | }
|
262 | }
|
263 | 263 | ||
264 | void ModelController::internalStop() |
264 | void ModelController::internalStop() |
265 | {
|
265 | {
|
266 | if (mRunning) { |
266 | if (mRunning) { |
267 | GlobalSettings::instance()->outputManager()->save(); |
267 | GlobalSettings::instance()->outputManager()->save(); |
268 | DebugTimer::printAllTimers(); |
268 | DebugTimer::printAllTimers(); |
269 | mFinished = true; |
269 | mFinished = true; |
270 | }
|
270 | }
|
271 | mRunning = false; |
271 | mRunning = false; |
272 | mPaused = false; // in any case |
272 | mPaused = false; // in any case |
273 | emit bufferLogs(false); // stop buffering |
273 | emit bufferLogs(false); // stop buffering |
274 | emit finished(QString()); |
274 | emit finished(QString()); |
275 | emit stateChanged(); |
275 | emit stateChanged(); |
276 | 276 | ||
277 | }
|
277 | }
|
278 | 278 | ||
279 | void ModelController::run(int years) |
279 | void ModelController::run(int years) |
280 | {
|
280 | {
|
281 | if (!canRun()) |
281 | if (!canRun()) |
282 | return; |
282 | return; |
283 | emit bufferLogs(true); // start buffering |
283 | emit bufferLogs(true); // start buffering |
284 | 284 | ||
285 | DebugTimer many_runs(QString("Timer for %1 runs").arg(years)); |
285 | DebugTimer many_runs(QString("Timer for %1 runs").arg(years)); |
286 | mPaused = false; |
286 | mPaused = false; |
287 | mFinished = false; |
287 | mFinished = false; |
288 | mCanceled = false; |
288 | mCanceled = false; |
289 | mYearsToRun = years; |
289 | mYearsToRun = years; |
290 | //GlobalSettings::instance()->setCurrentYear(1); // reset clock
|
290 | //GlobalSettings::instance()->setCurrentYear(1); // reset clock
|
291 | 291 | ||
292 | DebugTimer::clearAllTimers(); |
292 | DebugTimer::clearAllTimers(); |
293 | 293 | ||
294 | mRunning = true; |
294 | mRunning = true; |
295 | emit stateChanged(); |
295 | emit stateChanged(); |
296 | 296 | ||
297 | qDebug() << "ModelControler: runloop started."; |
297 | qDebug() << "ModelControler: runloop started."; |
298 | internalRun(); |
298 | internalRun(); |
299 | emit stateChanged(); |
299 | emit stateChanged(); |
300 | }
|
300 | }
|
301 | 301 | ||
302 | bool ModelController::runYear() |
302 | bool ModelController::runYear() |
303 | {
|
303 | {
|
304 | if (!canRun()) return false; |
304 | if (!canRun()) return false; |
305 | DebugTimer t("ModelController:runYear"); |
305 | DebugTimer t("ModelController:runYear"); |
306 | qDebug() << "ModelController: run year" << currentYear(); |
306 | qDebug() << "ModelController: run year" << currentYear(); |
307 | 307 | ||
308 | if (GlobalSettings::instance()->settings().paramValueBool("debug_clear")) |
308 | if (GlobalSettings::instance()->settings().paramValueBool("debug_clear")) |
309 | GlobalSettings::instance()->clearDebugLists(); // clear debug data |
309 | GlobalSettings::instance()->clearDebugLists(); // clear debug data |
310 | bool err=false; |
310 | bool err=false; |
311 | try { |
311 | try { |
312 | emit bufferLogs(true); |
312 | emit bufferLogs(true); |
313 | mModel->runYear(); |
313 | mModel->runYear(); |
314 | fetchDynamicOutput(); |
314 | fetchDynamicOutput(); |
315 | } catch(const IException &e) { |
315 | } catch(const IException &e) { |
316 | QString error_msg = e.message(); |
316 | QString error_msg = e.message(); |
317 | Helper::msg(error_msg); |
317 | Helper::msg(error_msg); |
318 | qDebug() << error_msg; |
318 | qDebug() << error_msg; |
319 | err=true; |
319 | err=true; |
320 | }
|
320 | }
|
321 | emit bufferLogs(false); |
321 | emit bufferLogs(false); |
322 | return err; |
322 | return err; |
323 | }
|
323 | }
|
324 | 324 | ||
325 | bool ModelController::pause() |
325 | bool ModelController::pause() |
326 | {
|
326 | {
|
327 | if(!isRunning()) |
327 | if(!isRunning()) |
328 | return mPaused; |
328 | return mPaused; |
329 | 329 | ||
330 | if (mPaused) { |
330 | if (mPaused) { |
331 | // currently in pause - mode -> continue
|
331 | // currently in pause - mode -> continue
|
332 | mPaused = false; |
332 | mPaused = false; |
333 | 333 | ||
334 | } else { |
334 | } else { |
335 | // currently running -> set to pause mode
|
335 | // currently running -> set to pause mode
|
336 | GlobalSettings::instance()->outputManager()->save(); |
336 | GlobalSettings::instance()->outputManager()->save(); |
337 | mPaused = true; |
337 | mPaused = true; |
338 | emit bufferLogs(false); |
338 | emit bufferLogs(false); |
339 | }
|
339 | }
|
340 | emit stateChanged(); |
340 | emit stateChanged(); |
341 | return mPaused; |
341 | return mPaused; |
342 | }
|
342 | }
|
343 | 343 | ||
344 | bool ModelController::continueRun() |
344 | bool ModelController::continueRun() |
345 | {
|
345 | {
|
346 | mRunning = true; |
346 | mRunning = true; |
347 | emit stateChanged(); |
347 | emit stateChanged(); |
348 | return internalRun(); |
348 | return internalRun(); |
349 | }
|
349 | }
|
350 | 350 | ||
351 | void ModelController::cancel() |
351 | void ModelController::cancel() |
352 | {
|
352 | {
|
353 | mCanceled = true; |
353 | mCanceled = true; |
354 | internalStop(); |
354 | internalStop(); |
355 | emit stateChanged(); |
355 | emit stateChanged(); |
356 | }
|
356 | }
|
357 | 357 | ||
358 | 358 | ||
359 | // this function is called when exceptions occur in multithreaded code.
|
359 | // this function is called when exceptions occur in multithreaded code.
|
360 | QMutex error_mutex;
|
360 | QMutex error_mutex;
|
361 | void ModelController::throwError(const QString msg) |
361 | void ModelController::throwError(const QString msg) |
362 | {
|
362 | {
|
363 | QMutexLocker lock(&error_mutex); // serialize access |
363 | QMutexLocker lock(&error_mutex); // serialize access |
364 | qDebug() << "ModelController: throwError reached:"; |
364 | qDebug() << "ModelController: throwError reached:"; |
365 | qDebug() << msg; |
365 | qDebug() << msg; |
366 | mLastError = msg; |
366 | mLastError = msg; |
367 | mHasError = true; |
367 | mHasError = true; |
368 | emit bufferLogs(false); |
368 | emit bufferLogs(false); |
369 | emit bufferLogs(true); // start buffering again |
369 | emit bufferLogs(true); // start buffering again |
370 | 370 | ||
371 | emit finished(msg); |
371 | emit finished(msg); |
372 | throw IException(msg); // raise error again |
372 | throw IException(msg); // raise error again |
373 | 373 | ||
374 | }
|
374 | }
|
375 | //////////////////////////////////////
|
375 | //////////////////////////////////////
|
376 | // dynamic outut
|
376 | // dynamic outut
|
377 | //////////////////////////////////////
|
377 | //////////////////////////////////////
|
378 | //////////////////////////////////////
|
378 | //////////////////////////////////////
|
379 | void ModelController::setupDynamicOutput(QString fieldList) |
379 | void ModelController::setupDynamicOutput(QString fieldList) |
380 | {
|
380 | {
|
381 | mDynFieldList.clear(); |
381 | mDynFieldList.clear(); |
382 | if (!fieldList.isEmpty()) { |
382 | if (!fieldList.isEmpty()) { |
383 | QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)"); |
383 | QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)"); |
384 | int pos=0; |
384 | int pos=0; |
385 | while ((pos = rx.indexIn(fieldList, pos)) != -1) { |
385 | while ((pos = rx.indexIn(fieldList, pos)) != -1) { |
386 | mDynFieldList.append(rx.cap(1)); |
386 | mDynFieldList.append(rx.cap(1)); |
387 | pos += rx.matchedLength(); |
387 | pos += rx.matchedLength(); |
388 | }
|
388 | }
|
389 | 389 | ||
390 | //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
|
390 | //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
|
391 | mDynFieldList.prepend("count"); |
391 | mDynFieldList.prepend("count"); |
392 | mDynFieldList.prepend("year"); // fixed fields. |
392 | mDynFieldList.prepend("year"); // fixed fields. |
393 | }
|
393 | }
|
394 | mDynData.clear(); |
394 | mDynData.clear(); |
395 | mDynData.append(mDynFieldList.join(";")); |
395 | mDynData.append(mDynFieldList.join(";")); |
396 | mDynamicOutputEnabled = true; |
396 | mDynamicOutputEnabled = true; |
397 | }
|
397 | }
|
398 | 398 | ||
399 | QString ModelController::dynamicOutput() |
399 | QString ModelController::dynamicOutput() |
400 | {
|
400 | {
|
401 | return mDynData.join("\n"); |
401 | return mDynData.join("\n"); |
402 | }
|
402 | }
|
403 | 403 | ||
404 | const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95"; |
404 | const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95"; |
405 | void ModelController::fetchDynamicOutput() |
405 | void ModelController::fetchDynamicOutput() |
406 | {
|
406 | {
|
407 | if (!mDynamicOutputEnabled || mDynFieldList.isEmpty()) |
407 | if (!mDynamicOutputEnabled || mDynFieldList.isEmpty()) |
408 | return; |
408 | return; |
409 | DebugTimer t("dynamic output"); |
409 | DebugTimer t("dynamic output"); |
410 | QStringList var;
|
410 | QStringList var;
|
411 | QString lastVar = ""; |
411 | QString lastVar = ""; |
412 | QVector<double> data; |
412 | QVector<double> data; |
413 | AllTreeIterator at(mModel); |
413 | AllTreeIterator at(mModel); |
414 | TreeWrapper tw;
|
414 | TreeWrapper tw;
|
415 | int var_index; |
415 | int var_index; |
416 | StatData stat;
|
416 | StatData stat;
|
417 | double value; |
417 | double value; |
418 | QStringList line;
|
418 | QStringList line;
|
419 | Expression custom_expr;
|
419 | Expression custom_expr;
|
420 | bool simple_expression; |
420 | bool simple_expression; |
421 | foreach (QString field, mDynFieldList) { |
421 | foreach (QString field, mDynFieldList) { |
422 | if (field=="count" || field=="year") |
422 | if (field=="count" || field=="year") |
423 | continue; |
423 | continue; |
424 | if (field.count()>0 && field.at(0)=='[') { |
424 | if (field.count()>0 && field.at(0)=='[') { |
425 | QRegExp rex("\\[(.+)\\]\\.(\\w+)"); |
425 | QRegExp rex("\\[(.+)\\]\\.(\\w+)"); |
426 | rex.indexIn(field); |
426 | rex.indexIn(field); |
427 | var = rex.capturedTexts(); |
427 | var = rex.capturedTexts(); |
428 | var.pop_front(); // drop first element (contains the full string) |
428 | var.pop_front(); // drop first element (contains the full string) |
429 | simple_expression = false; |
429 | simple_expression = false; |
430 | } else { |
430 | } else { |
431 | var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts); |
431 | var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts); |
432 | simple_expression = true; |
432 | simple_expression = true; |
433 | }
|
433 | }
|
434 | if (var.count()!=2) |
434 | if (var.count()!=2) |
435 | throw IException(QString("Invalid variable name for dynamic output:") + field); |
435 | throw IException(QString("Invalid variable name for dynamic output:") + field); |
436 | if (var.first()!=lastVar) { |
436 | if (var.first()!=lastVar) { |
437 | // load new field
|
437 | // load new field
|
438 | data.clear(); |
438 | data.clear(); |
439 | at.reset(); var_index = 0; |
439 | at.reset(); var_index = 0; |
440 | if (simple_expression) { |
440 | if (simple_expression) { |
441 | var_index = tw.variableIndex(var.first()); |
441 | var_index = tw.variableIndex(var.first()); |
442 | if (var_index<0) |
442 | if (var_index<0) |
443 | throw IException(QString("Invalid variable name for dynamic output:") + var.first()); |
443 | throw IException(QString("Invalid variable name for dynamic output:") + var.first()); |
444 | 444 | ||
445 | } else { |
445 | } else { |
446 | custom_expr.setExpression(var.first()); |
446 | custom_expr.setExpression(var.first()); |
447 | custom_expr.setModelObject(&tw); |
447 | custom_expr.setModelObject(&tw); |
448 | }
|
448 | }
|
449 | while (Tree *t = at.next()) { |
449 | while (Tree *t = at.next()) { |
450 | tw.setTree(t); |
450 | tw.setTree(t); |
451 | if (simple_expression) |
451 | if (simple_expression) |
452 | value = tw.value(var_index); |
452 | value = tw.value(var_index); |
453 | else
|
453 | else
|
454 | value = custom_expr.execute(); |
454 | value = custom_expr.execute(); |
455 | data.push_back(value); |
455 | data.push_back(value); |
456 | }
|
456 | }
|
457 | stat.setData(data); |
457 | stat.setData(data); |
458 | }
|
458 | }
|
459 | // fetch data
|
459 | // fetch data
|
460 | var_index = aggList.indexOf(var[1]); |
460 | var_index = aggList.indexOf(var[1]); |
461 | switch (var_index) { |
461 | switch (var_index) { |
462 | case 0: value = stat.mean(); break; |
462 | case 0: value = stat.mean(); break; |
463 | case 1: value = stat.sum(); break; |
463 | case 1: value = stat.sum(); break; |
464 | case 2: value = stat.min(); break; |
464 | case 2: value = stat.min(); break; |
465 | case 3: value = stat.max(); break; |
465 | case 3: value = stat.max(); break; |
466 | case 4: value = stat.percentile25(); break; |
466 | case 4: value = stat.percentile25(); break; |
467 | case 5: value = stat.median(); break; |
467 | case 5: value = stat.median(); break; |
468 | case 6: value = stat.percentile75(); break; |
468 | case 6: value = stat.percentile75(); break; |
469 | case 7: value = stat.percentile(5); break; |
469 | case 7: value = stat.percentile(5); break; |
470 | case 8: value = stat.percentile(10); break; |
470 | case 8: value = stat.percentile(10); break; |
471 | case 9: value = stat.percentile(90); break; |
471 | case 9: value = stat.percentile(90); break; |
472 | case 10: value = stat.percentile(95); break; |
472 | case 10: value = stat.percentile(95); break; |
473 | default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2") |
473 | default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2") |
474 | .arg(var[1]).arg(aggList.join(" "))); |
474 | .arg(var[1]).arg(aggList.join(" "))); |
475 | }
|
475 | }
|
476 | line+=QString::number(value); |
476 | line+=QString::number(value); |
477 | }
|
477 | }
|
478 | line.prepend( QString::number(data.size()) ); |
478 | line.prepend( QString::number(data.size()) ); |
479 | line.prepend( QString::number(GlobalSettings::instance()->currentYear()) ); |
479 | line.prepend( QString::number(GlobalSettings::instance()->currentYear()) ); |
480 | mDynData.append(line.join(";")); |
480 | mDynData.append(line.join(";")); |
481 | }
|
481 | }
|
482 | 482 | ||
483 | void ModelController::saveScreenshot(QString file_name) |
483 | void ModelController::saveScreenshot(QString file_name) |
484 | {
|
484 | {
|
485 | #ifdef ILAND_GUI
|
485 | #ifdef ILAND_GUI
|
486 | if (!mViewerWindow) |
486 | if (!mViewerWindow) |
487 | return; |
487 | return; |
488 | QImage img = mViewerWindow->screenshot(); |
488 | QImage img = mViewerWindow->screenshot(); |
489 | img.save(file_name); |
489 | img.save(file_name); |
490 | #else
|
490 | #else
|
491 | Q_UNUSED(file_name); |
491 | Q_UNUSED(file_name); |
492 | #endif
|
492 | #endif
|
493 | }
|
493 | }
|
494 | 494 | ||
495 | void ModelController::paintMap(MapGrid *map, double min_value, double max_value) |
495 | void ModelController::paintMap(MapGrid *map, double min_value, double max_value) |
496 | {
|
496 | {
|
497 | #ifdef ILAND_GUI
|
497 | #ifdef ILAND_GUI
|
498 | if (mViewerWindow) { |
498 | if (mViewerWindow) { |
499 | mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value); |
499 | mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value); |
500 | qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value; |
500 | qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value; |
501 | }
|
501 | }
|
502 | #else
|
502 | #else
|
503 | Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value); |
503 | Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value); |
504 | #endif
|
504 | #endif
|
505 | }
|
505 | }
|
506 | 506 | ||
507 | void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value) |
507 | void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value) |
508 | {
|
508 | {
|
509 | #ifdef ILAND_GUI
|
509 | #ifdef ILAND_GUI
|
510 | 510 | ||
511 | if (mViewerWindow) { |
511 | if (mViewerWindow) { |
512 | mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value); |
512 | mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value); |
513 | qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value; |
513 | qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value; |
514 | }
|
514 | }
|
515 | #else
|
515 | #else
|
516 | Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value); |
516 | Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value); |
517 | #endif
|
517 | #endif
|
518 | }
|
518 | }
|
519 | 519 | ||
520 | void ModelController::addLayers(const LayeredGridBase *layers, const QString &name) |
520 | void ModelController::addLayers(const LayeredGridBase *layers, const QString &name) |
521 | {
|
521 | {
|
522 | #ifdef ILAND_GUI
|
522 | #ifdef ILAND_GUI
|
523 | if (mViewerWindow) |
523 | if (mViewerWindow) |
524 | mViewerWindow->addLayers(layers, name); |
524 | mViewerWindow->addLayers(layers, name); |
525 | //qDebug() << layers->names();
|
525 | //qDebug() << layers->names();
|
526 | #else
|
526 | #else
|
527 | Q_UNUSED(layers); Q_UNUSED(name); |
527 | Q_UNUSED(layers); Q_UNUSED(name); |
528 | #endif
|
528 | #endif
|
529 | }
|
529 | }
|
530 | void ModelController::removeLayers(const LayeredGridBase *layers) |
530 | void ModelController::removeLayers(const LayeredGridBase *layers) |
531 | {
|
531 | {
|
532 | #ifdef ILAND_GUI
|
532 | #ifdef ILAND_GUI
|
533 | if (mViewerWindow) |
533 | if (mViewerWindow) |
534 | mViewerWindow->removeLayers(layers); |
534 | mViewerWindow->removeLayers(layers); |
535 | //qDebug() << layers->names();
|
535 | //qDebug() << layers->names();
|
536 | #else
|
536 | #else
|
537 | Q_UNUSED(layers); |
537 | Q_UNUSED(layers); |
538 | #endif
|
538 | #endif
|
539 | }
|
539 | }
|
540 | 540 | ||
541 | void ModelController::setViewport(QPointF center_point, double scale_px_per_m) |
541 | void ModelController::setViewport(QPointF center_point, double scale_px_per_m) |
542 | {
|
542 | {
|
543 | #ifdef ILAND_GUI
|
543 | #ifdef ILAND_GUI
|
544 | if (mViewerWindow) |
544 | if (mViewerWindow) |
545 | mViewerWindow->setViewport(center_point, scale_px_per_m); |
545 | mViewerWindow->setViewport(center_point, scale_px_per_m); |
546 | #else
|
546 | #else
|
547 | Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m); |
547 | Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m); |
- | 548 | #endif
|
|
- | 549 | }
|
|
- | 550 | ||
- | 551 | void ModelController::setUIShortcuts(QVariantMap shortcuts) |
|
- | 552 | {
|
|
- | 553 | #ifdef ILAND_GUI
|
|
- | 554 | if (mViewerWindow) |
|
- | 555 | mViewerWindow->setUIshortcuts(shortcuts); |
|
- | 556 | #else
|
|
- | 557 | Q_UNUSED(shortcuts); |
|
548 | #endif
|
558 | #endif
|
549 | }
|
559 | }
|
550 | 560 | ||
551 | void ModelController::repaint() |
561 | void ModelController::repaint() |
552 | {
|
562 | {
|
553 | #ifdef ILAND_GUI
|
563 | #ifdef ILAND_GUI
|
554 | if (mViewerWindow) |
564 | if (mViewerWindow) |
555 | mViewerWindow->repaint(); |
565 | mViewerWindow->repaint(); |
556 | #endif
|
566 | #endif
|
557 | }
|
567 | }
|
558 | 568 | ||
559 | 569 | ||
560 | 570 | ||
561 | 571 | ||
562 | 572 | ||
563 | 573 |