Subversion Repositories public iLand

Rev

Rev 421 | Rev 497 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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