Subversion Repositories public iLand

Rev

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