Subversion Repositories public iLand

Rev

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