Subversion Repositories public iLand

Rev

Rev 918 | Rev 924 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1
 
671 werner 2
/********************************************************************************************
3
**    iLand - an individual based forest landscape and disturbance model
4
**    http://iland.boku.ac.at
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
6
**
7
**    This program is free software: you can redistribute it and/or modify
8
**    it under the terms of the GNU General Public License as published by
9
**    the Free Software Foundation, either version 3 of the License, or
10
**    (at your option) any later version.
11
**
12
**    This program is distributed in the hope that it will be useful,
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
**    GNU General Public License for more details.
16
**
17
**    You should have received a copy of the GNU General Public License
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************************************/
20
 
697 werner 21
/** ModelController is a helper class used to control the flow of operations during a model run.
22
  The ModelController encapsulates the Model class and is the main control unit. It is used by the
23
  iLand GUI as well as the command line version (ilandc).
24
 
105 Werner 25
  */
128 Werner 26
 
105 Werner 27
#include "global.h"
28
#include "modelcontroller.h"
128 Werner 29
#include <QObject>
105 Werner 30
 
31
#include "model.h"
808 werner 32
#include "debugtimer.h"
128 Werner 33
#include "helper.h"
165 werner 34
#include "expression.h"
161 werner 35
#include "expressionwrapper.h"
176 werner 36
#include "../output/outputmanager.h"
105 Werner 37
 
514 werner 38
#include "species.h"
39
#include "speciesset.h"
596 werner 40
#include "mapgrid.h"
808 werner 41
#include "statdata.h"
514 werner 42
 
678 werner 43
#ifdef ILAND_GUI
267 werner 44
#include "mainwindow.h" // for the debug message buffering
678 werner 45
#endif
267 werner 46
 
105 Werner 47
ModelController::ModelController()
48
{
128 Werner 49
    mModel = NULL;
223 werner 50
    mPaused = false;
225 werner 51
    mRunning = false;
837 werner 52
    mHasError = false;
223 werner 53
    mYearsToRun = 0;
590 werner 54
    mViewerWindow = 0;
802 werner 55
    mDynamicOutputEnabled = false;
105 Werner 56
}
128 Werner 57
 
58
ModelController::~ModelController()
59
{
60
    destroy();
61
}
62
 
590 werner 63
void ModelController::connectSignals()
64
{
65
    if (!mViewerWindow)
66
        return;
678 werner 67
#ifdef ILAND_GUI
590 werner 68
    connect(this,SIGNAL(bufferLogs(bool)), mViewerWindow, SLOT(bufferedLog(bool)));
678 werner 69
#endif
590 werner 70
}
71
 
514 werner 72
/// prepare a list of all (active) species
73
QHash<QString, QString> ModelController::availableSpecies()
74
{
75
    QHash<QString, QString> list;
76
    if (mModel) {
77
        SpeciesSet *set = mModel->speciesSet();
78
        if (!set)
79
            throw IException("there are 0 or more than one species sets.");
80
        foreach (const Species *s, set->activeSpecies()) {
81
            list[s->id()] = s->name();
82
        }
83
    }
84
    return list;
85
}
128 Werner 86
 
145 Werner 87
bool ModelController::canCreate()
128 Werner 88
{
129 Werner 89
    if (mModel)
128 Werner 90
        return false;
91
    return true;
92
}
93
 
145 Werner 94
bool ModelController::canDestroy()
128 Werner 95
{
96
    return mModel != NULL;
97
}
98
 
145 Werner 99
bool ModelController::canRun()
128 Werner 100
{
101
    if (mModel && mModel->isSetup())
102
        return true;
103
    return false;
104
}
105
 
145 Werner 106
bool ModelController::isRunning()
128 Werner 107
{
225 werner 108
    return mRunning;
128 Werner 109
}
110
 
225 werner 111
bool ModelController::isFinished()
112
{
113
    if (!mModel)
114
        return false;
115
    return canRun() && !isRunning()  && mFinished;
497 werner 116
}
128 Werner 117
 
776 werner 118
bool ModelController::isPaused()
119
{
120
    return mPaused;
121
}
122
 
497 werner 123
int ModelController::currentYear() const
124
{
125
    return GlobalSettings::instance()->currentYear();
225 werner 126
}
127
 
128 Werner 128
void ModelController::setFileName(QString initFileName)
129
{
130
    mInitFile = initFileName;
131
    try {
132
        GlobalSettings::instance()->loadProjectFile(mInitFile);
133
    } catch(const IException &e) {
575 werner 134
        QString error_msg = e.message();
128 Werner 135
        Helper::msg(error_msg);
837 werner 136
        mHasError = true;
137
        mLastError = error_msg;
128 Werner 138
        qDebug() << error_msg;
139
    }
140
}
141
 
142
void ModelController::create()
143
{
144
    if (!canCreate())
145
        return;
590 werner 146
    emit bufferLogs(true);
147
 
128 Werner 148
    try {
837 werner 149
        mHasError = false;
285 werner 150
        DebugTimer::clearAllTimers();
151
        mModel = new Model();
152
        mModel->loadProject();
837 werner 153
        if (!mModel->isSetup()) {
154
            mHasError = true;
155
            mLastError = "An error occured during the loading of the project. Please check the logs.";
286 werner 156
            return;
837 werner 157
        }
286 werner 158
 
497 werner 159
        // reset clock...
160
        GlobalSettings::instance()->setCurrentYear(1); // reset clock
395 werner 161
        // initialization of trees, output on startup
286 werner 162
        mModel->beforeRun();
128 Werner 163
    } catch(const IException &e) {
575 werner 164
        QString error_msg = e.message();
128 Werner 165
        Helper::msg(error_msg);
837 werner 166
        mLastError = error_msg;
167
        mHasError = true;
128 Werner 168
        qDebug() << error_msg;
169
    }
590 werner 170
    emit bufferLogs(false);
171
 
362 werner 172
    qDebug() << "Model created.";
128 Werner 173
}
174
 
175
void ModelController::destroy()
176
{
177
    if (canDestroy()) {
891 werner 178
        Model *m = mModel;
128 Werner 179
        mModel = 0;
891 werner 180
        delete m;
162 werner 181
        GlobalSettings::instance()->setCurrentYear(0);
128 Werner 182
        qDebug() << "ModelController: Model destroyed.";
183
    }
184
}
222 werner 185
 
223 werner 186
void ModelController::runloop()
187
{
515 werner 188
    static QTime sLastTime = QTime::currentTime();
678 werner 189
#ifdef ILAND_GUI
776 werner 190
 //   QApplication::processEvents();
678 werner 191
#else
776 werner 192
 //   QCoreApplication::processEvents();
678 werner 193
#endif
223 werner 194
    if (mPaused)
195
        return;
225 werner 196
    bool doStop = false;
837 werner 197
    mHasError = false;
515 werner 198
    if (GlobalSettings::instance()->currentYear()<=1) {
199
        sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation
200
    }
225 werner 201
 
202
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
590 werner 203
        emit bufferLogs(true);
776 werner 204
 
837 werner 205
        mHasError = runYear(); // do the work!
776 werner 206
 
225 werner 207
        mRunning = true;
208
        emit year(GlobalSettings::instance()->currentYear());
837 werner 209
        if (!mHasError) {
515 werner 210
            int elapsed = sLastTime.msecsTo(QTime::currentTime());
497 werner 211
            int time=0;
515 werner 212
            if (currentYear()%50==0 && elapsed>10000)
497 werner 213
                time = 100; // a 100ms pause...
515 werner 214
            if (currentYear()%100==0 && elapsed>10000) {
497 werner 215
                time = 500; // a 500ms pause...
216
            }
515 werner 217
            if (time>0) {
218
                sLastTime = QTime::currentTime(); // reset clock
219
                qDebug() << "--- little break ---- (after " << elapsed << "ms).";
776 werner 220
                //QTimer::singleShot(time,this, SLOT(runloop()));
515 werner 221
            }
776 werner 222
 
837 werner 223
        } else {
224
           doStop = true; // an error occured
225
           mLastError = "An error occured while running the model. Please check the logs.";
226
           mHasError = true;
497 werner 227
        }
225 werner 228
 
229
    } else {
230
        doStop = true; // all years simulated
223 werner 231
    }
225 werner 232
 
233
    if (doStop || mCanceled) {
234
                // finished
776 werner 235
        internalStop();
225 werner 236
    }
267 werner 237
 
678 werner 238
#ifdef ILAND_GUI
225 werner 239
    QApplication::processEvents();
678 werner 240
#else
241
    QCoreApplication::processEvents();
242
#endif
223 werner 243
}
244
 
776 werner 245
bool ModelController::internalRun()
246
{
247
    // main loop
918 werner 248
    try {
249
        while (mRunning && !mPaused &&  !mFinished) {
250
            runloop(); // start the running loop
251
        }
252
    } catch (IException &e) {
253
#ifdef ILAND_GUI
254
        Helper::msg(e.message());
255
#endif
776 werner 256
 
257
    }
918 werner 258
 
776 werner 259
    return isFinished();
260
}
261
 
262
void ModelController::internalStop()
263
{
264
    if (mRunning) {
265
        GlobalSettings::instance()->outputManager()->save();
266
        DebugTimer::printAllTimers();
267
        mFinished = true;
268
    }
269
    mRunning = false;
270
    emit bufferLogs(false); // stop buffering
271
    emit finished(QString());
272
    emit stateChanged();
273
 
274
}
275
 
222 werner 276
void ModelController::run(int years)
128 Werner 277
{
222 werner 278
    if (!canRun())
279
        return;
590 werner 280
    emit bufferLogs(true); // start buffering
281
 
222 werner 282
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
223 werner 283
    mPaused = false;
225 werner 284
    mFinished = false;
285
    mCanceled = false;
223 werner 286
    mYearsToRun = years;
497 werner 287
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
222 werner 288
 
289
    DebugTimer::clearAllTimers();
223 werner 290
 
759 werner 291
    mRunning = true;
776 werner 292
    emit stateChanged();
223 werner 293
 
776 werner 294
    qDebug() << "ModelControler: runloop started.";
295
    internalRun();
296
    emit stateChanged();
128 Werner 297
}
298
 
223 werner 299
bool ModelController::runYear()
128 Werner 300
{
223 werner 301
    if (!canRun()) return false;
421 werner 302
    DebugTimer t("ModelController:runYear");
497 werner 303
    qDebug() << "ModelController: run year" << currentYear();
421 werner 304
 
171 werner 305
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
164 werner 306
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
223 werner 307
    bool err=false;
128 Werner 308
    try {
590 werner 309
        emit bufferLogs(true);
128 Werner 310
        mModel->runYear();
162 werner 311
        fetchDynamicOutput();
128 Werner 312
    } catch(const IException &e) {
575 werner 313
        QString error_msg = e.message();
128 Werner 314
        Helper::msg(error_msg);
315
        qDebug() << error_msg;
223 werner 316
        err=true;
128 Werner 317
    }
590 werner 318
    emit bufferLogs(false);
223 werner 319
    return err;
128 Werner 320
}
321
 
222 werner 322
bool ModelController::pause()
323
{
223 werner 324
    if(!isRunning())
325
        return mPaused;
326
 
327
    if (mPaused) {
328
        // currently in pause - mode -> continue
329
        mPaused = false;
776 werner 330
 
223 werner 331
    } else {
332
        // currently running -> set to pause mode
333
        GlobalSettings::instance()->outputManager()->save();
334
        mPaused = true;
590 werner 335
        emit bufferLogs(false);
223 werner 336
    }
776 werner 337
    emit stateChanged();
223 werner 338
    return mPaused;
222 werner 339
}
128 Werner 340
 
776 werner 341
bool ModelController::continueRun()
342
{
343
    mRunning = true;
344
    emit stateChanged();
345
    return internalRun();
346
}
347
 
222 werner 348
void ModelController::cancel()
349
{
225 werner 350
    mCanceled = true;
776 werner 351
    internalStop();
352
    emit stateChanged();
222 werner 353
}
225 werner 354
 
921 werner 355
 
356
// this function is called when exceptions occur in multithreaded code.
632 werner 357
QMutex error_mutex;
358
void ModelController::throwError(const QString msg)
359
{
360
    QMutexLocker lock(&error_mutex); // serialize access
361
    qDebug() << "ModelController: throwError reached:";
362
    qDebug() << msg;
837 werner 363
    mLastError = msg;
364
    mHasError = true;
632 werner 365
    emit bufferLogs(false);
366
    emit bufferLogs(true); // start buffering again
367
 
921 werner 368
    emit finished(msg);
632 werner 369
    throw IException(msg); // raise error again
370
 
371
}
161 werner 372
//////////////////////////////////////
373
// dynamic outut
374
//////////////////////////////////////
375
//////////////////////////////////////
376
void ModelController::setupDynamicOutput(QString fieldList)
377
{
171 werner 378
    mDynFieldList.clear();
379
    if (!fieldList.isEmpty()) {
380
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
381
        int pos=0;
382
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
383
            mDynFieldList.append(rx.cap(1));
384
            pos += rx.matchedLength();
385
        }
386
 
387
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
170 werner 388
        mDynFieldList.prepend("count");
389
        mDynFieldList.prepend("year"); // fixed fields.
390
    }
161 werner 391
    mDynData.clear();
392
    mDynData.append(mDynFieldList.join(";"));
802 werner 393
    mDynamicOutputEnabled = true;
161 werner 394
}
162 werner 395
 
161 werner 396
QString ModelController::dynamicOutput()
397
{
398
    return mDynData.join("\n");
399
}
400
 
218 werner 401
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
161 werner 402
void ModelController::fetchDynamicOutput()
403
{
802 werner 404
    if (!mDynamicOutputEnabled || mDynFieldList.isEmpty())
161 werner 405
        return;
165 werner 406
    DebugTimer t("dynamic output");
161 werner 407
    QStringList var;
408
    QString lastVar = "";
409
    QVector<double> data;
410
    AllTreeIterator at(mModel);
411
    TreeWrapper tw;
412
    int var_index;
413
    StatData stat;
414
    double value;
415
    QStringList line;
165 werner 416
    Expression custom_expr;
417
    bool simple_expression;
161 werner 418
    foreach (QString field, mDynFieldList) {
163 werner 419
        if (field=="count" || field=="year")
420
            continue;
166 werner 421
        if (field.count()>0 && field.at(0)=='[') {
422
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
423
            rex.indexIn(field);
424
            var = rex.capturedTexts();
425
            var.pop_front(); // drop first element (contains the full string)
165 werner 426
            simple_expression = false;
427
        } else {
428
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
429
            simple_expression = true;
430
        }
161 werner 431
        if (var.count()!=2)
432
                throw IException(QString("Invalid variable name for dynamic output:") + field);
433
        if (var.first()!=lastVar) {
434
            // load new field
435
            data.clear();
168 werner 436
            at.reset(); var_index = 0;
165 werner 437
            if (simple_expression) {
438
                var_index = tw.variableIndex(var.first());
166 werner 439
                if (var_index<0)
165 werner 440
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
166 werner 441
 
165 werner 442
            } else {
443
                custom_expr.setExpression(var.first());
444
                custom_expr.setModelObject(&tw);
161 werner 445
            }
446
            while (Tree *t = at.next()) {
447
                tw.setTree(t);
165 werner 448
                if (simple_expression)
449
                    value = tw.value(var_index);
450
                else
451
                    value = custom_expr.execute();
166 werner 452
                data.push_back(value);
161 werner 453
            }
454
            stat.setData(data);
455
        }
456
        // fetch data
457
        var_index = aggList.indexOf(var[1]);
458
        switch (var_index) {
459
            case 0: value = stat.mean(); break;
460
            case 1: value = stat.sum(); break;
461
            case 2: value = stat.min(); break;
462
            case 3: value = stat.max(); break;
463
            case 4: value = stat.percentile25(); break;
464
            case 5: value = stat.median(); break;
465
            case 6: value = stat.percentile75(); break;
218 werner 466
            case 7: value = stat.percentile(5); break;
467
            case 8: value = stat.percentile(10); break;
468
            case 9: value = stat.percentile(90); break;
469
            case 10: value = stat.percentile(95); break;
161 werner 470
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
471
                                  .arg(var[1]).arg(aggList.join(" ")));
472
        }
473
        line+=QString::number(value);
474
    }
162 werner 475
    line.prepend( QString::number(data.size()) );
476
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
477
    mDynData.append(line.join(";"));
161 werner 478
}
590 werner 479
 
480
void ModelController::saveScreenshot(QString file_name)
481
{
678 werner 482
#ifdef ILAND_GUI
590 werner 483
    if (!mViewerWindow)
484
        return;
485
    QImage img = mViewerWindow->screenshot();
486
    img.save(file_name);
678 werner 487
#endif
590 werner 488
}
596 werner 489
 
490
void ModelController::paintMap(MapGrid *map, double min_value, double max_value)
491
{
678 werner 492
#ifdef ILAND_GUI
596 werner 493
    if (mViewerWindow) {
643 werner 494
        mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value);
596 werner 495
        qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value;
496
    }
780 werner 497
#else
498
    Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 499
#endif
596 werner 500
}
632 werner 501
 
649 werner 502
void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value)
642 werner 503
{
678 werner 504
#ifdef ILAND_GUI
505
 
642 werner 506
    if (mViewerWindow) {
643 werner 507
        mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value);
642 werner 508
        qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value;
509
    }
780 werner 510
#else
511
    Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 512
#endif
642 werner 513
}
514
 
649 werner 515
void ModelController::addLayers(const LayeredGridBase *layers, const QString &name)
634 werner 516
{
678 werner 517
#ifdef ILAND_GUI
634 werner 518
    if (mViewerWindow)
649 werner 519
        mViewerWindow->addLayers(layers, name);
520
    //qDebug() << layers->names();
780 werner 521
#else
522
    Q_UNUSED(layers); Q_UNUSED(name);
678 werner 523
#endif
634 werner 524
}
893 werner 525
void ModelController::removeLayers(const LayeredGridBase *layers)
526
{
527
#ifdef ILAND_GUI
528
    if (mViewerWindow)
529
        mViewerWindow->removeLayers(layers);
530
    //qDebug() << layers->names();
531
#else
532
    Q_UNUSED(layers); Q_UNUSED(name);
533
#endif
534
}
632 werner 535
 
649 werner 536
void ModelController::setViewport(QPointF center_point, double scale_px_per_m)
646 werner 537
{
678 werner 538
#ifdef ILAND_GUI
647 werner 539
    if (mViewerWindow)
649 werner 540
        mViewerWindow->setViewport(center_point, scale_px_per_m);
780 werner 541
#else
542
    Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m);
678 werner 543
#endif
646 werner 544
}
634 werner 545
 
652 werner 546
void ModelController::repaint()
547
{
678 werner 548
#ifdef ILAND_GUI
652 werner 549
    if (mViewerWindow)
550
        mViewerWindow->repaint();
678 werner 551
#endif
652 werner 552
}
646 werner 553
 
649 werner 554
 
652 werner 555