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