Subversion Repositories public iLand

Rev

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