Subversion Repositories public iLand

Rev

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