Subversion Repositories public iLand

Rev

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