Subversion Repositories public iLand

Rev

Rev 1221 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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