Subversion Repositories public iLand

Rev

Rev 1182 | Rev 1204 | 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"
1182 werner 34
#include "version.h"
165 werner 35
#include "expression.h"
161 werner 36
#include "expressionwrapper.h"
176 werner 37
#include "../output/outputmanager.h"
105 Werner 38
 
514 werner 39
#include "species.h"
40
#include "speciesset.h"
596 werner 41
#include "mapgrid.h"
808 werner 42
#include "statdata.h"
514 werner 43
 
678 werner 44
#ifdef ILAND_GUI
267 werner 45
#include "mainwindow.h" // for the debug message buffering
678 werner 46
#endif
267 werner 47
 
105 Werner 48
ModelController::ModelController()
49
{
128 Werner 50
    mModel = NULL;
223 werner 51
    mPaused = false;
225 werner 52
    mRunning = false;
837 werner 53
    mHasError = false;
223 werner 54
    mYearsToRun = 0;
590 werner 55
    mViewerWindow = 0;
802 werner 56
    mDynamicOutputEnabled = false;
105 Werner 57
}
128 Werner 58
 
59
ModelController::~ModelController()
60
{
61
    destroy();
62
}
63
 
590 werner 64
void ModelController::connectSignals()
65
{
66
    if (!mViewerWindow)
67
        return;
678 werner 68
#ifdef ILAND_GUI
590 werner 69
    connect(this,SIGNAL(bufferLogs(bool)), mViewerWindow, SLOT(bufferedLog(bool)));
678 werner 70
#endif
590 werner 71
}
72
 
514 werner 73
/// prepare a list of all (active) species
1066 werner 74
QList<const Species*> ModelController::availableSpecies()
514 werner 75
{
1066 werner 76
    QList<const Species*> list;
514 werner 77
    if (mModel) {
78
        SpeciesSet *set = mModel->speciesSet();
79
        if (!set)
80
            throw IException("there are 0 or more than one species sets.");
81
        foreach (const Species *s, set->activeSpecies()) {
1066 werner 82
            list.append(s);
514 werner 83
        }
84
    }
85
    return list;
86
}
128 Werner 87
 
145 Werner 88
bool ModelController::canCreate()
128 Werner 89
{
129 Werner 90
    if (mModel)
128 Werner 91
        return false;
92
    return true;
93
}
94
 
145 Werner 95
bool ModelController::canDestroy()
128 Werner 96
{
97
    return mModel != NULL;
98
}
99
 
145 Werner 100
bool ModelController::canRun()
128 Werner 101
{
102
    if (mModel && mModel->isSetup())
103
        return true;
104
    return false;
105
}
106
 
145 Werner 107
bool ModelController::isRunning()
128 Werner 108
{
225 werner 109
    return mRunning;
128 Werner 110
}
111
 
225 werner 112
bool ModelController::isFinished()
113
{
114
    if (!mModel)
115
        return false;
116
    return canRun() && !isRunning()  && mFinished;
497 werner 117
}
128 Werner 118
 
776 werner 119
bool ModelController::isPaused()
120
{
121
    return mPaused;
122
}
123
 
497 werner 124
int ModelController::currentYear() const
125
{
126
    return GlobalSettings::instance()->currentYear();
225 werner 127
}
128
 
128 Werner 129
void ModelController::setFileName(QString initFileName)
130
{
131
    mInitFile = initFileName;
132
    try {
133
        GlobalSettings::instance()->loadProjectFile(mInitFile);
134
    } catch(const IException &e) {
575 werner 135
        QString error_msg = e.message();
128 Werner 136
        Helper::msg(error_msg);
837 werner 137
        mHasError = true;
138
        mLastError = error_msg;
128 Werner 139
        qDebug() << error_msg;
140
    }
141
}
142
 
143
void ModelController::create()
144
{
145
    if (!canCreate())
146
        return;
590 werner 147
    emit bufferLogs(true);
148
 
128 Werner 149
    try {
837 werner 150
        mHasError = false;
285 werner 151
        DebugTimer::clearAllTimers();
152
        mModel = new Model();
153
        mModel->loadProject();
837 werner 154
        if (!mModel->isSetup()) {
155
            mHasError = true;
156
            mLastError = "An error occured during the loading of the project. Please check the logs.";
286 werner 157
            return;
837 werner 158
        }
286 werner 159
 
497 werner 160
        // reset clock...
161
        GlobalSettings::instance()->setCurrentYear(1); // reset clock
395 werner 162
        // initialization of trees, output on startup
286 werner 163
        mModel->beforeRun();
1157 werner 164
        GlobalSettings::instance()->executeJSFunction("onAfterCreate");
128 Werner 165
    } catch(const IException &e) {
575 werner 166
        QString error_msg = e.message();
128 Werner 167
        Helper::msg(error_msg);
837 werner 168
        mLastError = error_msg;
169
        mHasError = true;
128 Werner 170
        qDebug() << error_msg;
171
    }
590 werner 172
    emit bufferLogs(false);
173
 
362 werner 174
    qDebug() << "Model created.";
128 Werner 175
}
176
 
177
void ModelController::destroy()
178
{
179
    if (canDestroy()) {
1157 werner 180
        GlobalSettings::instance()->executeJSFunction("onBeforeDestroy");
891 werner 181
        Model *m = mModel;
128 Werner 182
        mModel = 0;
891 werner 183
        delete m;
162 werner 184
        GlobalSettings::instance()->setCurrentYear(0);
128 Werner 185
        qDebug() << "ModelController: Model destroyed.";
186
    }
187
}
222 werner 188
 
223 werner 189
void ModelController::runloop()
190
{
515 werner 191
    static QTime sLastTime = QTime::currentTime();
678 werner 192
#ifdef ILAND_GUI
776 werner 193
 //   QApplication::processEvents();
678 werner 194
#else
776 werner 195
 //   QCoreApplication::processEvents();
678 werner 196
#endif
223 werner 197
    if (mPaused)
198
        return;
225 werner 199
    bool doStop = false;
837 werner 200
    mHasError = false;
515 werner 201
    if (GlobalSettings::instance()->currentYear()<=1) {
202
        sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation
203
    }
225 werner 204
 
205
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
590 werner 206
        emit bufferLogs(true);
776 werner 207
 
837 werner 208
        mHasError = runYear(); // do the work!
776 werner 209
 
225 werner 210
        mRunning = true;
211
        emit year(GlobalSettings::instance()->currentYear());
837 werner 212
        if (!mHasError) {
515 werner 213
            int elapsed = sLastTime.msecsTo(QTime::currentTime());
497 werner 214
            int time=0;
515 werner 215
            if (currentYear()%50==0 && elapsed>10000)
497 werner 216
                time = 100; // a 100ms pause...
515 werner 217
            if (currentYear()%100==0 && elapsed>10000) {
497 werner 218
                time = 500; // a 500ms pause...
219
            }
515 werner 220
            if (time>0) {
221
                sLastTime = QTime::currentTime(); // reset clock
222
                qDebug() << "--- little break ---- (after " << elapsed << "ms).";
776 werner 223
                //QTimer::singleShot(time,this, SLOT(runloop()));
515 werner 224
            }
776 werner 225
 
837 werner 226
        } else {
227
           doStop = true; // an error occured
228
           mLastError = "An error occured while running the model. Please check the logs.";
229
           mHasError = true;
497 werner 230
        }
225 werner 231
 
232
    } else {
233
        doStop = true; // all years simulated
223 werner 234
    }
225 werner 235
 
236
    if (doStop || mCanceled) {
237
                // finished
776 werner 238
        internalStop();
225 werner 239
    }
267 werner 240
 
678 werner 241
#ifdef ILAND_GUI
225 werner 242
    QApplication::processEvents();
678 werner 243
#else
244
    QCoreApplication::processEvents();
245
#endif
223 werner 246
}
247
 
776 werner 248
bool ModelController::internalRun()
249
{
250
    // main loop
918 werner 251
    try {
252
        while (mRunning && !mPaused &&  !mFinished) {
253
            runloop(); // start the running loop
254
        }
255
    } catch (IException &e) {
256
#ifdef ILAND_GUI
257
        Helper::msg(e.message());
1034 werner 258
#else
259
        qDebug() << e.message();
918 werner 260
#endif
776 werner 261
 
262
    }
263
    return isFinished();
264
}
265
 
266
void ModelController::internalStop()
267
{
268
    if (mRunning) {
269
        GlobalSettings::instance()->outputManager()->save();
270
        DebugTimer::printAllTimers();
1182 werner 271
        saveDebugOutputs();
1081 werner 272
        //if (GlobalSettings::instance()->dbout().isOpen())
273
        //    GlobalSettings::instance()->dbout().close();
1072 werner 274
 
776 werner 275
        mFinished = true;
276
    }
277
    mRunning = false;
964 werner 278
    mPaused = false; // in any case
776 werner 279
    emit bufferLogs(false); // stop buffering
280
    emit finished(QString());
281
    emit stateChanged();
282
 
283
}
284
 
222 werner 285
void ModelController::run(int years)
128 Werner 286
{
222 werner 287
    if (!canRun())
288
        return;
590 werner 289
    emit bufferLogs(true); // start buffering
290
 
222 werner 291
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
223 werner 292
    mPaused = false;
225 werner 293
    mFinished = false;
294
    mCanceled = false;
223 werner 295
    mYearsToRun = years;
497 werner 296
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
222 werner 297
 
298
    DebugTimer::clearAllTimers();
223 werner 299
 
759 werner 300
    mRunning = true;
776 werner 301
    emit stateChanged();
223 werner 302
 
776 werner 303
    qDebug() << "ModelControler: runloop started.";
304
    internalRun();
305
    emit stateChanged();
128 Werner 306
}
307
 
223 werner 308
bool ModelController::runYear()
128 Werner 309
{
223 werner 310
    if (!canRun()) return false;
421 werner 311
    DebugTimer t("ModelController:runYear");
1157 werner 312
    qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss:") << "ModelController: run year" << currentYear();
421 werner 313
 
171 werner 314
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
164 werner 315
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
223 werner 316
    bool err=false;
128 Werner 317
    try {
590 werner 318
        emit bufferLogs(true);
1157 werner 319
        GlobalSettings::instance()->executeJSFunction("onYearBegin");
128 Werner 320
        mModel->runYear();
1157 werner 321
 
162 werner 322
        fetchDynamicOutput();
128 Werner 323
    } catch(const IException &e) {
575 werner 324
        QString error_msg = e.message();
128 Werner 325
        Helper::msg(error_msg);
326
        qDebug() << error_msg;
223 werner 327
        err=true;
128 Werner 328
    }
590 werner 329
    emit bufferLogs(false);
1157 werner 330
#ifdef ILAND_GUI
331
    QApplication::processEvents();
332
#else
333
    QCoreApplication::processEvents();
334
#endif
335
 
223 werner 336
    return err;
128 Werner 337
}
338
 
222 werner 339
bool ModelController::pause()
340
{
223 werner 341
    if(!isRunning())
342
        return mPaused;
343
 
344
    if (mPaused) {
345
        // currently in pause - mode -> continue
346
        mPaused = false;
776 werner 347
 
223 werner 348
    } else {
349
        // currently running -> set to pause mode
350
        GlobalSettings::instance()->outputManager()->save();
351
        mPaused = true;
590 werner 352
        emit bufferLogs(false);
223 werner 353
    }
776 werner 354
    emit stateChanged();
223 werner 355
    return mPaused;
222 werner 356
}
128 Werner 357
 
776 werner 358
bool ModelController::continueRun()
359
{
360
    mRunning = true;
361
    emit stateChanged();
362
    return internalRun();
363
}
364
 
222 werner 365
void ModelController::cancel()
366
{
225 werner 367
    mCanceled = true;
776 werner 368
    internalStop();
369
    emit stateChanged();
222 werner 370
}
225 werner 371
 
921 werner 372
 
373
// this function is called when exceptions occur in multithreaded code.
632 werner 374
QMutex error_mutex;
375
void ModelController::throwError(const QString msg)
376
{
377
    QMutexLocker lock(&error_mutex); // serialize access
378
    qDebug() << "ModelController: throwError reached:";
379
    qDebug() << msg;
837 werner 380
    mLastError = msg;
381
    mHasError = true;
632 werner 382
    emit bufferLogs(false);
383
    emit bufferLogs(true); // start buffering again
384
 
921 werner 385
    emit finished(msg);
632 werner 386
    throw IException(msg); // raise error again
387
 
388
}
161 werner 389
//////////////////////////////////////
390
// dynamic outut
391
//////////////////////////////////////
392
//////////////////////////////////////
393
void ModelController::setupDynamicOutput(QString fieldList)
394
{
171 werner 395
    mDynFieldList.clear();
396
    if (!fieldList.isEmpty()) {
397
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
398
        int pos=0;
399
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
400
            mDynFieldList.append(rx.cap(1));
401
            pos += rx.matchedLength();
402
        }
403
 
404
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
170 werner 405
        mDynFieldList.prepend("count");
406
        mDynFieldList.prepend("year"); // fixed fields.
407
    }
161 werner 408
    mDynData.clear();
409
    mDynData.append(mDynFieldList.join(";"));
802 werner 410
    mDynamicOutputEnabled = true;
161 werner 411
}
162 werner 412
 
161 werner 413
QString ModelController::dynamicOutput()
414
{
415
    return mDynData.join("\n");
416
}
417
 
218 werner 418
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
161 werner 419
void ModelController::fetchDynamicOutput()
420
{
802 werner 421
    if (!mDynamicOutputEnabled || mDynFieldList.isEmpty())
161 werner 422
        return;
165 werner 423
    DebugTimer t("dynamic output");
161 werner 424
    QStringList var;
425
    QString lastVar = "";
426
    QVector<double> data;
427
    AllTreeIterator at(mModel);
428
    TreeWrapper tw;
429
    int var_index;
430
    StatData stat;
431
    double value;
432
    QStringList line;
165 werner 433
    Expression custom_expr;
434
    bool simple_expression;
161 werner 435
    foreach (QString field, mDynFieldList) {
163 werner 436
        if (field=="count" || field=="year")
437
            continue;
166 werner 438
        if (field.count()>0 && field.at(0)=='[') {
439
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
440
            rex.indexIn(field);
441
            var = rex.capturedTexts();
442
            var.pop_front(); // drop first element (contains the full string)
165 werner 443
            simple_expression = false;
444
        } else {
445
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
446
            simple_expression = true;
447
        }
161 werner 448
        if (var.count()!=2)
449
                throw IException(QString("Invalid variable name for dynamic output:") + field);
450
        if (var.first()!=lastVar) {
451
            // load new field
452
            data.clear();
168 werner 453
            at.reset(); var_index = 0;
165 werner 454
            if (simple_expression) {
455
                var_index = tw.variableIndex(var.first());
166 werner 456
                if (var_index<0)
165 werner 457
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
166 werner 458
 
165 werner 459
            } else {
460
                custom_expr.setExpression(var.first());
461
                custom_expr.setModelObject(&tw);
161 werner 462
            }
463
            while (Tree *t = at.next()) {
464
                tw.setTree(t);
165 werner 465
                if (simple_expression)
466
                    value = tw.value(var_index);
467
                else
468
                    value = custom_expr.execute();
166 werner 469
                data.push_back(value);
161 werner 470
            }
471
            stat.setData(data);
472
        }
473
        // fetch data
474
        var_index = aggList.indexOf(var[1]);
475
        switch (var_index) {
476
            case 0: value = stat.mean(); break;
477
            case 1: value = stat.sum(); break;
478
            case 2: value = stat.min(); break;
479
            case 3: value = stat.max(); break;
480
            case 4: value = stat.percentile25(); break;
481
            case 5: value = stat.median(); break;
482
            case 6: value = stat.percentile75(); break;
218 werner 483
            case 7: value = stat.percentile(5); break;
484
            case 8: value = stat.percentile(10); break;
485
            case 9: value = stat.percentile(90); break;
486
            case 10: value = stat.percentile(95); break;
161 werner 487
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
488
                                  .arg(var[1]).arg(aggList.join(" ")));
489
        }
490
        line+=QString::number(value);
491
    }
162 werner 492
    line.prepend( QString::number(data.size()) );
493
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
494
    mDynData.append(line.join(";"));
161 werner 495
}
590 werner 496
 
1182 werner 497
void ModelController::saveDebugOutputs()
498
{
499
    // save to files if switch is true
500
    if (!GlobalSettings::instance()->settings().valueBool("system.settings.debugOutputAutoSave"))
501
        return;
502
 
503
    QString p = GlobalSettings::instance()->path("debug_", "temp");
504
 
505
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreePartition, ";", p + "tree_partition.csv");
506
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreeGrowth, ";", p + "tree_growth.csv");
507
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dTreeNPP, ";", p + "tree_npp.csv");
1196 werner 508
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dStandGPP, ";", p + "stand_gpp.csv");
1182 werner 509
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dWaterCycle, ";", p + "water_cycle.csv");
510
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dDailyResponses, ";", p + "daily_responses.csv");
511
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dEstablishment, ";", p + "establishment.csv");
512
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dSaplingGrowth, ";", p + "saplinggrowth.csv");
513
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dCarbonCycle, ";", p + "carboncycle.csv");
514
    GlobalSettings::instance()->debugDataTable(GlobalSettings::dPerformance, ";", p + "performance.csv");
515
    Helper::saveToTextFile(p+"dynamic.csv", dynamicOutput());
516
    Helper::saveToTextFile(p+ "version.txt", verboseVersion());
517
 
518
 
519
    qDebug() << "saved debug outputs to" << p;
520
 
521
}
522
 
590 werner 523
void ModelController::saveScreenshot(QString file_name)
524
{
678 werner 525
#ifdef ILAND_GUI
590 werner 526
    if (!mViewerWindow)
527
        return;
528
    QImage img = mViewerWindow->screenshot();
1180 werner 529
    img.save(GlobalSettings::instance()->path(file_name));
1032 werner 530
#else
531
    Q_UNUSED(file_name);
678 werner 532
#endif
590 werner 533
}
596 werner 534
 
535
void ModelController::paintMap(MapGrid *map, double min_value, double max_value)
536
{
678 werner 537
#ifdef ILAND_GUI
596 werner 538
    if (mViewerWindow) {
643 werner 539
        mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value);
596 werner 540
        qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value;
541
    }
780 werner 542
#else
543
    Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 544
#endif
596 werner 545
}
632 werner 546
 
649 werner 547
void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value)
642 werner 548
{
678 werner 549
#ifdef ILAND_GUI
550
 
642 werner 551
    if (mViewerWindow) {
643 werner 552
        mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value);
642 werner 553
        qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value;
554
    }
780 werner 555
#else
556
    Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 557
#endif
642 werner 558
}
559
 
649 werner 560
void ModelController::addLayers(const LayeredGridBase *layers, const QString &name)
634 werner 561
{
678 werner 562
#ifdef ILAND_GUI
634 werner 563
    if (mViewerWindow)
649 werner 564
        mViewerWindow->addLayers(layers, name);
565
    //qDebug() << layers->names();
780 werner 566
#else
567
    Q_UNUSED(layers); Q_UNUSED(name);
678 werner 568
#endif
634 werner 569
}
893 werner 570
void ModelController::removeLayers(const LayeredGridBase *layers)
571
{
572
#ifdef ILAND_GUI
573
    if (mViewerWindow)
574
        mViewerWindow->removeLayers(layers);
575
    //qDebug() << layers->names();
576
#else
924 werner 577
    Q_UNUSED(layers);
893 werner 578
#endif
579
}
632 werner 580
 
649 werner 581
void ModelController::setViewport(QPointF center_point, double scale_px_per_m)
646 werner 582
{
678 werner 583
#ifdef ILAND_GUI
647 werner 584
    if (mViewerWindow)
649 werner 585
        mViewerWindow->setViewport(center_point, scale_px_per_m);
780 werner 586
#else
587
    Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m);
678 werner 588
#endif
646 werner 589
}
634 werner 590
 
1061 werner 591
void ModelController::setUIShortcuts(QVariantMap shortcuts)
592
{
593
#ifdef ILAND_GUI
594
    if (mViewerWindow)
595
        mViewerWindow->setUIshortcuts(shortcuts);
596
#else
597
    Q_UNUSED(shortcuts);
598
#endif
599
}
600
 
652 werner 601
void ModelController::repaint()
602
{
678 werner 603
#ifdef ILAND_GUI
652 werner 604
    if (mViewerWindow)
605
        mViewerWindow->repaint();
678 werner 606
#endif
652 werner 607
}
646 werner 608
 
649 werner 609
 
652 werner 610
 
962 werner 611
 
612