Subversion Repositories public iLand

Rev

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