Subversion Repositories public iLand

Rev

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