Subversion Repositories public iLand

Rev

Rev 514 | Rev 575 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 514 Rev 515
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
/** ModelController is a helper class used to
2
/** ModelController is a helper class used to
3
  control the flow of operations during a model run.
3
  control the flow of operations during a model run.
4
  Really useful???? or a dispatcher???
4
  Really useful???? or a dispatcher???
5
  */
5
  */
6
6
7
#include "global.h"
7
#include "global.h"
8
#include "modelcontroller.h"
8
#include "modelcontroller.h"
9
#include <QObject>
9
#include <QObject>
10
10
11
#include "model.h"
11
#include "model.h"
12
#include "helper.h"
12
#include "helper.h"
13
#include "expression.h"
13
#include "expression.h"
14
#include "expressionwrapper.h"
14
#include "expressionwrapper.h"
15
#include "../output/outputmanager.h"
15
#include "../output/outputmanager.h"
16
16
17
#include "species.h"
17
#include "species.h"
18
#include "speciesset.h"
18
#include "speciesset.h"
19
19
20
#include "mainwindow.h" // for the debug message buffering
20
#include "mainwindow.h" // for the debug message buffering
21
21
22
ModelController::ModelController()
22
ModelController::ModelController()
23
{
23
{
24
    mModel = NULL;
24
    mModel = NULL;
25
    mPaused = false;
25
    mPaused = false;
26
    mRunning = false;
26
    mRunning = false;
27
    mYearsToRun = 0;
27
    mYearsToRun = 0;
28
}
28
}
29
29
30
ModelController::~ModelController()
30
ModelController::~ModelController()
31
{
31
{
32
    destroy();
32
    destroy();
33
}
33
}
34
34
35
/// prepare a list of all (active) species
35
/// prepare a list of all (active) species
36
QHash<QString, QString> ModelController::availableSpecies()
36
QHash<QString, QString> ModelController::availableSpecies()
37
{
37
{
38
    QHash<QString, QString> list;
38
    QHash<QString, QString> list;
39
    if (mModel) {
39
    if (mModel) {
40
        SpeciesSet *set = mModel->speciesSet();
40
        SpeciesSet *set = mModel->speciesSet();
41
        if (!set)
41
        if (!set)
42
            throw IException("there are 0 or more than one species sets.");
42
            throw IException("there are 0 or more than one species sets.");
43
        foreach (const Species *s, set->activeSpecies()) {
43
        foreach (const Species *s, set->activeSpecies()) {
44
            list[s->id()] = s->name();
44
            list[s->id()] = s->name();
45
        }
45
        }
46
    }
46
    }
47
    return list;
47
    return list;
48
}
48
}
49
49
50
bool ModelController::canCreate()
50
bool ModelController::canCreate()
51
{
51
{
52
    if (mModel)
52
    if (mModel)
53
        return false;
53
        return false;
54
    return true;
54
    return true;
55
}
55
}
56
56
57
bool ModelController::canDestroy()
57
bool ModelController::canDestroy()
58
{
58
{
59
    return mModel != NULL;
59
    return mModel != NULL;
60
}
60
}
61
61
62
bool ModelController::canRun()
62
bool ModelController::canRun()
63
{
63
{
64
    if (mModel && mModel->isSetup())
64
    if (mModel && mModel->isSetup())
65
        return true;
65
        return true;
66
    return false;
66
    return false;
67
}
67
}
68
68
69
bool ModelController::isRunning()
69
bool ModelController::isRunning()
70
{
70
{
71
    return mRunning;
71
    return mRunning;
72
}
72
}
73
73
74
bool ModelController::isFinished()
74
bool ModelController::isFinished()
75
{
75
{
76
    if (!mModel)
76
    if (!mModel)
77
        return false;
77
        return false;
78
    return canRun() && !isRunning()  && mFinished;
78
    return canRun() && !isRunning()  && mFinished;
79
}
79
}
80
80
81
int ModelController::currentYear() const
81
int ModelController::currentYear() const
82
{
82
{
83
    return GlobalSettings::instance()->currentYear();
83
    return GlobalSettings::instance()->currentYear();
84
}
84
}
85
85
86
void ModelController::setFileName(QString initFileName)
86
void ModelController::setFileName(QString initFileName)
87
{
87
{
88
    mInitFile = initFileName;
88
    mInitFile = initFileName;
89
    try {
89
    try {
90
        GlobalSettings::instance()->loadProjectFile(mInitFile);
90
        GlobalSettings::instance()->loadProjectFile(mInitFile);
91
    } catch(const IException &e) {
91
    } catch(const IException &e) {
92
        QString error_msg = e.toString();
92
        QString error_msg = e.toString();
93
        Helper::msg(error_msg);
93
        Helper::msg(error_msg);
94
        qDebug() << error_msg;
94
        qDebug() << error_msg;
95
    }
95
    }
96
}
96
}
97
97
98
void ModelController::create()
98
void ModelController::create()
99
{
99
{
100
    if (!canCreate())
100
    if (!canCreate())
101
        return;
101
        return;
102
    MainWindow::bufferedLog(true);
102
    MainWindow::bufferedLog(true);
103
    try {
103
    try {
104
        DebugTimer::clearAllTimers();
104
        DebugTimer::clearAllTimers();
105
        mModel = new Model();
105
        mModel = new Model();
106
        mModel->loadProject();
106
        mModel->loadProject();
107
        if (!mModel->isSetup())
107
        if (!mModel->isSetup())
108
            return;
108
            return;
109
109
110
        // reset clock...
110
        // reset clock...
111
        GlobalSettings::instance()->setCurrentYear(1); // reset clock
111
        GlobalSettings::instance()->setCurrentYear(1); // reset clock
112
        // initialization of trees, output on startup
112
        // initialization of trees, output on startup
113
        mModel->beforeRun();
113
        mModel->beforeRun();
114
    } catch(const IException &e) {
114
    } catch(const IException &e) {
115
        QString error_msg = e.toString();
115
        QString error_msg = e.toString();
116
        Helper::msg(error_msg);
116
        Helper::msg(error_msg);
117
        qDebug() << error_msg;
117
        qDebug() << error_msg;
118
    }
118
    }
119
    MainWindow::bufferedLog(false);
119
    MainWindow::bufferedLog(false);
120
    qDebug() << "Model created.";
120
    qDebug() << "Model created.";
121
}
121
}
122
122
123
void ModelController::destroy()
123
void ModelController::destroy()
124
{
124
{
125
    if (canDestroy()) {
125
    if (canDestroy()) {
126
        delete mModel;
126
        delete mModel;
127
        mModel = 0;
127
        mModel = 0;
128
        GlobalSettings::instance()->setCurrentYear(0);
128
        GlobalSettings::instance()->setCurrentYear(0);
129
        qDebug() << "ModelController: Model destroyed.";
129
        qDebug() << "ModelController: Model destroyed.";
130
    }
130
    }
131
}
131
}
132
132
133
void ModelController::runloop()
133
void ModelController::runloop()
134
{
134
{
135
-
 
-
 
135
    static QTime sLastTime = QTime::currentTime();
136
    QApplication::processEvents();
136
    QApplication::processEvents();
137
    if (mPaused)
137
    if (mPaused)
138
        return;
138
        return;
139
    bool doStop = false;
139
    bool doStop = false;
140
    bool hasError = false;
140
    bool hasError = false;
-
 
141
    if (GlobalSettings::instance()->currentYear()<=1) {
-
 
142
        sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation
-
 
143
    }
141
144
142
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
145
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
143
        MainWindow::bufferedLog(true); // start buffering
146
        MainWindow::bufferedLog(true); // start buffering
144
        hasError = runYear(); // do the work
147
        hasError = runYear(); // do the work
145
        mRunning = true;
148
        mRunning = true;
146
        emit year(GlobalSettings::instance()->currentYear());
149
        emit year(GlobalSettings::instance()->currentYear());
147
        if (!hasError) {
150
        if (!hasError) {
-
 
151
            int elapsed = sLastTime.msecsTo(QTime::currentTime());
148
            int time=0;
152
            int time=0;
149
            if (currentYear()%50==0)
-
 
-
 
153
            if (currentYear()%50==0 && elapsed>10000)
150
                time = 100; // a 100ms pause...
154
                time = 100; // a 100ms pause...
151
            if (currentYear()%100==0) {
-
 
-
 
155
            if (currentYear()%100==0 && elapsed>10000) {
152
                time = 500; // a 500ms pause...
156
                time = 500; // a 500ms pause...
-
 
157
            }
-
 
158
            if (time>0) {
-
 
159
                sLastTime = QTime::currentTime(); // reset clock
-
 
160
                qDebug() << "--- little break ---- (after " << elapsed << "ms).";
153
            }
161
            }
154
            QTimer::singleShot(time,this, SLOT(runloop()));
162
            QTimer::singleShot(time,this, SLOT(runloop()));
155
        }
163
        }
156
        else
164
        else
157
           doStop = true; // an error occured
165
           doStop = true; // an error occured
158
166
159
    } else {
167
    } else {
160
        doStop = true; // all years simulated
168
        doStop = true; // all years simulated
161
    }
169
    }
162
170
163
    if (doStop || mCanceled) {
171
    if (doStop || mCanceled) {
164
                // finished
172
                // finished
165
        mRunning = false;
173
        mRunning = false;
166
        GlobalSettings::instance()->outputManager()->save();
174
        GlobalSettings::instance()->outputManager()->save();
167
        DebugTimer::printAllTimers();
175
        DebugTimer::printAllTimers();
168
        mFinished = true;
176
        mFinished = true;
169
        MainWindow::bufferedLog(false); // stop buffering
177
        MainWindow::bufferedLog(false); // stop buffering
170
        emit finished(QString());
178
        emit finished(QString());
171
    }
179
    }
172
180
173
    QApplication::processEvents();
181
    QApplication::processEvents();
174
}
182
}
175
183
176
void ModelController::run(int years)
184
void ModelController::run(int years)
177
{
185
{
178
    if (!canRun())
186
    if (!canRun())
179
        return;
187
        return;
180
    MainWindow::bufferedLog(true);
188
    MainWindow::bufferedLog(true);
181
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
189
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
182
    mPaused = false;
190
    mPaused = false;
183
    mFinished = false;
191
    mFinished = false;
184
    mCanceled = false;
192
    mCanceled = false;
185
    mYearsToRun = years;
193
    mYearsToRun = years;
186
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
194
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
187
195
188
    DebugTimer::clearAllTimers();
196
    DebugTimer::clearAllTimers();
189
197
190
    runloop(); // start the running loop
198
    runloop(); // start the running loop
191
199
192
200
193
201
194
}
202
}
195
203
196
bool ModelController::runYear()
204
bool ModelController::runYear()
197
{
205
{
198
    if (!canRun()) return false;
206
    if (!canRun()) return false;
199
    DebugTimer t("ModelController:runYear");
207
    DebugTimer t("ModelController:runYear");
200
    qDebug() << "ModelController: run year" << currentYear();
208
    qDebug() << "ModelController: run year" << currentYear();
201
209
202
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
210
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
203
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
211
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
204
    bool err=false;
212
    bool err=false;
205
    try {
213
    try {
206
        MainWindow::bufferedLog(true);
214
        MainWindow::bufferedLog(true);
207
        mModel->runYear();
215
        mModel->runYear();
208
        fetchDynamicOutput();
216
        fetchDynamicOutput();
209
    } catch(const IException &e) {
217
    } catch(const IException &e) {
210
        QString error_msg = e.toString();
218
        QString error_msg = e.toString();
211
        Helper::msg(error_msg);
219
        Helper::msg(error_msg);
212
        qDebug() << error_msg;
220
        qDebug() << error_msg;
213
        err=true;
221
        err=true;
214
    }
222
    }
215
    MainWindow::bufferedLog(false);
223
    MainWindow::bufferedLog(false);
216
    return err;
224
    return err;
217
}
225
}
218
226
219
bool ModelController::pause()
227
bool ModelController::pause()
220
{
228
{
221
    if(!isRunning())
229
    if(!isRunning())
222
        return mPaused;
230
        return mPaused;
223
231
224
    if (mPaused) {
232
    if (mPaused) {
225
        // currently in pause - mode -> continue
233
        // currently in pause - mode -> continue
226
        mPaused = false;
234
        mPaused = false;
227
        QTimer::singleShot(0,this, SLOT(runloop())); // continue loop
235
        QTimer::singleShot(0,this, SLOT(runloop())); // continue loop
228
    } else {
236
    } else {
229
        // currently running -> set to pause mode
237
        // currently running -> set to pause mode
230
        GlobalSettings::instance()->outputManager()->save();
238
        GlobalSettings::instance()->outputManager()->save();
231
        mPaused = true;
239
        mPaused = true;
232
        MainWindow::bufferedLog(false);
240
        MainWindow::bufferedLog(false);
233
    }
241
    }
234
    return mPaused;
242
    return mPaused;
235
}
243
}
236
244
237
void ModelController::cancel()
245
void ModelController::cancel()
238
{
246
{
239
    mCanceled = true;
247
    mCanceled = true;
240
}
248
}
241
249
242
//////////////////////////////////////
250
//////////////////////////////////////
243
// dynamic outut
251
// dynamic outut
244
//////////////////////////////////////
252
//////////////////////////////////////
245
//////////////////////////////////////
253
//////////////////////////////////////
246
void ModelController::setupDynamicOutput(QString fieldList)
254
void ModelController::setupDynamicOutput(QString fieldList)
247
{
255
{
248
    mDynFieldList.clear();
256
    mDynFieldList.clear();
249
    if (!fieldList.isEmpty()) {
257
    if (!fieldList.isEmpty()) {
250
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
258
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
251
        int pos=0;
259
        int pos=0;
252
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
260
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
253
            mDynFieldList.append(rx.cap(1));
261
            mDynFieldList.append(rx.cap(1));
254
            pos += rx.matchedLength();
262
            pos += rx.matchedLength();
255
        }
263
        }
256
264
257
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
265
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
258
        mDynFieldList.prepend("count");
266
        mDynFieldList.prepend("count");
259
        mDynFieldList.prepend("year"); // fixed fields.
267
        mDynFieldList.prepend("year"); // fixed fields.
260
    }
268
    }
261
    mDynData.clear();
269
    mDynData.clear();
262
    mDynData.append(mDynFieldList.join(";"));
270
    mDynData.append(mDynFieldList.join(";"));
263
}
271
}
264
272
265
QString ModelController::dynamicOutput()
273
QString ModelController::dynamicOutput()
266
{
274
{
267
    return mDynData.join("\n");
275
    return mDynData.join("\n");
268
}
276
}
269
277
270
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
278
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
271
void ModelController::fetchDynamicOutput()
279
void ModelController::fetchDynamicOutput()
272
{
280
{
273
    if (mDynFieldList.isEmpty())
281
    if (mDynFieldList.isEmpty())
274
        return;
282
        return;
275
    DebugTimer t("dynamic output");
283
    DebugTimer t("dynamic output");
276
    QStringList var;
284
    QStringList var;
277
    QString lastVar = "";
285
    QString lastVar = "";
278
    QVector<double> data;
286
    QVector<double> data;
279
    AllTreeIterator at(mModel);
287
    AllTreeIterator at(mModel);
280
    TreeWrapper tw;
288
    TreeWrapper tw;
281
    int var_index;
289
    int var_index;
282
    StatData stat;
290
    StatData stat;
283
    double value;
291
    double value;
284
    QStringList line;
292
    QStringList line;
285
    Expression custom_expr;
293
    Expression custom_expr;
286
    bool simple_expression;
294
    bool simple_expression;
287
    foreach (QString field, mDynFieldList) {
295
    foreach (QString field, mDynFieldList) {
288
        if (field=="count" || field=="year")
296
        if (field=="count" || field=="year")
289
            continue;
297
            continue;
290
        if (field.count()>0 && field.at(0)=='[') {
298
        if (field.count()>0 && field.at(0)=='[') {
291
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
299
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
292
            rex.indexIn(field);
300
            rex.indexIn(field);
293
            var = rex.capturedTexts();
301
            var = rex.capturedTexts();
294
            var.pop_front(); // drop first element (contains the full string)
302
            var.pop_front(); // drop first element (contains the full string)
295
            simple_expression = false;
303
            simple_expression = false;
296
        } else {
304
        } else {
297
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
305
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
298
            simple_expression = true;
306
            simple_expression = true;
299
        }
307
        }
300
        if (var.count()!=2)
308
        if (var.count()!=2)
301
                throw IException(QString("Invalid variable name for dynamic output:") + field);
309
                throw IException(QString("Invalid variable name for dynamic output:") + field);
302
        if (var.first()!=lastVar) {
310
        if (var.first()!=lastVar) {
303
            // load new field
311
            // load new field
304
            data.clear();
312
            data.clear();
305
            at.reset(); var_index = 0;
313
            at.reset(); var_index = 0;
306
            if (simple_expression) {
314
            if (simple_expression) {
307
                var_index = tw.variableIndex(var.first());
315
                var_index = tw.variableIndex(var.first());
308
                if (var_index<0)
316
                if (var_index<0)
309
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
317
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
310
318
311
            } else {
319
            } else {
312
                custom_expr.setExpression(var.first());
320
                custom_expr.setExpression(var.first());
313
                custom_expr.setModelObject(&tw);
321
                custom_expr.setModelObject(&tw);
314
            }
322
            }
315
            while (Tree *t = at.next()) {
323
            while (Tree *t = at.next()) {
316
                tw.setTree(t);
324
                tw.setTree(t);
317
                if (simple_expression)
325
                if (simple_expression)
318
                    value = tw.value(var_index);
326
                    value = tw.value(var_index);
319
                else
327
                else
320
                    value = custom_expr.execute();
328
                    value = custom_expr.execute();
321
                data.push_back(value);
329
                data.push_back(value);
322
            }
330
            }
323
            stat.setData(data);
331
            stat.setData(data);
324
        }
332
        }
325
        // fetch data
333
        // fetch data
326
        var_index = aggList.indexOf(var[1]);
334
        var_index = aggList.indexOf(var[1]);
327
        switch (var_index) {
335
        switch (var_index) {
328
            case 0: value = stat.mean(); break;
336
            case 0: value = stat.mean(); break;
329
            case 1: value = stat.sum(); break;
337
            case 1: value = stat.sum(); break;
330
            case 2: value = stat.min(); break;
338
            case 2: value = stat.min(); break;
331
            case 3: value = stat.max(); break;
339
            case 3: value = stat.max(); break;
332
            case 4: value = stat.percentile25(); break;
340
            case 4: value = stat.percentile25(); break;
333
            case 5: value = stat.median(); break;
341
            case 5: value = stat.median(); break;
334
            case 6: value = stat.percentile75(); break;
342
            case 6: value = stat.percentile75(); break;
335
            case 7: value = stat.percentile(5); break;
343
            case 7: value = stat.percentile(5); break;
336
            case 8: value = stat.percentile(10); break;
344
            case 8: value = stat.percentile(10); break;
337
            case 9: value = stat.percentile(90); break;
345
            case 9: value = stat.percentile(90); break;
338
            case 10: value = stat.percentile(95); break;
346
            case 10: value = stat.percentile(95); break;
339
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
347
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
340
                                  .arg(var[1]).arg(aggList.join(" ")));
348
                                  .arg(var[1]).arg(aggList.join(" ")));
341
        }
349
        }
342
        line+=QString::number(value);
350
        line+=QString::number(value);
343
    }
351
    }
344
    line.prepend( QString::number(data.size()) );
352
    line.prepend( QString::number(data.size()) );
345
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
353
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
346
    mDynData.append(line.join(";"));
354
    mDynData.append(line.join(";"));
347
}
355
}
348
 
356