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