Subversion Repositories public iLand

Rev

Rev 294 | Rev 370 | 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
 
116
    if (mPaused)
117
        return;
225 werner 118
    bool doStop = false;
119
    bool hasError = false;
120
 
121
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
267 werner 122
        MainWindow::bufferedLog(true); // start buffering
123
        hasError = runYear(); // do the work
225 werner 124
        mRunning = true;
125
        emit year(GlobalSettings::instance()->currentYear());
126
        if (!hasError)
223 werner 127
            QTimer::singleShot(0,this, SLOT(runloop()));
225 werner 128
        else
129
           doStop = true; // an error occured
130
 
131
    } else {
132
        doStop = true; // all years simulated
223 werner 133
    }
225 werner 134
 
135
    if (doStop || mCanceled) {
136
                // finished
137
        mRunning = false;
138
        GlobalSettings::instance()->outputManager()->save();
139
        DebugTimer::printAllTimers();
140
        mFinished = true;
267 werner 141
        MainWindow::bufferedLog(false); // stop buffering
225 werner 142
        emit finished(QString());
143
    }
267 werner 144
 
225 werner 145
    QApplication::processEvents();
223 werner 146
}
147
 
222 werner 148
void ModelController::run(int years)
128 Werner 149
{
222 werner 150
    if (!canRun())
151
        return;
267 werner 152
    MainWindow::bufferedLog(true);
222 werner 153
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
154
    many_runs.setAsWarning();
223 werner 155
    mPaused = false;
225 werner 156
    mFinished = false;
157
    mCanceled = false;
223 werner 158
    mYearsToRun = years;
277 werner 159
    GlobalSettings::instance()->setCurrentYear(1); // reset clock
222 werner 160
 
161
    DebugTimer::clearAllTimers();
223 werner 162
 
163
    runloop(); // start the running loop
164
 
222 werner 165
 
225 werner 166
 
128 Werner 167
}
168
 
223 werner 169
bool ModelController::runYear()
128 Werner 170
{
223 werner 171
    if (!canRun()) return false;
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
}