Subversion Repositories public iLand

Rev

Rev 837 | Rev 893 | 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
248
 
249
    while (mRunning && !mPaused &&  !mFinished) {
250
        runloop(); // start the running loop
251
    }
252
    return isFinished();
253
}
254
 
255
void ModelController::internalStop()
256
{
257
    if (mRunning) {
258
        GlobalSettings::instance()->outputManager()->save();
259
        DebugTimer::printAllTimers();
260
        mFinished = true;
261
    }
262
    mRunning = false;
263
    emit bufferLogs(false); // stop buffering
264
    emit finished(QString());
265
    emit stateChanged();
266
 
267
}
268
 
222 werner 269
void ModelController::run(int years)
128 Werner 270
{
222 werner 271
    if (!canRun())
272
        return;
590 werner 273
    emit bufferLogs(true); // start buffering
274
 
222 werner 275
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
223 werner 276
    mPaused = false;
225 werner 277
    mFinished = false;
278
    mCanceled = false;
223 werner 279
    mYearsToRun = years;
497 werner 280
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
222 werner 281
 
282
    DebugTimer::clearAllTimers();
223 werner 283
 
759 werner 284
    mRunning = true;
776 werner 285
    emit stateChanged();
223 werner 286
 
776 werner 287
    qDebug() << "ModelControler: runloop started.";
288
    internalRun();
289
    emit stateChanged();
128 Werner 290
}
291
 
223 werner 292
bool ModelController::runYear()
128 Werner 293
{
223 werner 294
    if (!canRun()) return false;
421 werner 295
    DebugTimer t("ModelController:runYear");
497 werner 296
    qDebug() << "ModelController: run year" << currentYear();
421 werner 297
 
171 werner 298
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
164 werner 299
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
223 werner 300
    bool err=false;
128 Werner 301
    try {
590 werner 302
        emit bufferLogs(true);
128 Werner 303
        mModel->runYear();
162 werner 304
        fetchDynamicOutput();
128 Werner 305
    } catch(const IException &e) {
575 werner 306
        QString error_msg = e.message();
128 Werner 307
        Helper::msg(error_msg);
308
        qDebug() << error_msg;
223 werner 309
        err=true;
128 Werner 310
    }
590 werner 311
    emit bufferLogs(false);
223 werner 312
    return err;
128 Werner 313
}
314
 
222 werner 315
bool ModelController::pause()
316
{
223 werner 317
    if(!isRunning())
318
        return mPaused;
319
 
320
    if (mPaused) {
321
        // currently in pause - mode -> continue
322
        mPaused = false;
776 werner 323
 
223 werner 324
    } else {
325
        // currently running -> set to pause mode
326
        GlobalSettings::instance()->outputManager()->save();
327
        mPaused = true;
590 werner 328
        emit bufferLogs(false);
223 werner 329
    }
776 werner 330
    emit stateChanged();
223 werner 331
    return mPaused;
222 werner 332
}
128 Werner 333
 
776 werner 334
bool ModelController::continueRun()
335
{
336
    mRunning = true;
337
    emit stateChanged();
338
    return internalRun();
339
}
340
 
222 werner 341
void ModelController::cancel()
342
{
225 werner 343
    mCanceled = true;
776 werner 344
    internalStop();
345
    emit stateChanged();
222 werner 346
}
225 werner 347
 
632 werner 348
QMutex error_mutex;
349
void ModelController::throwError(const QString msg)
350
{
351
    QMutexLocker lock(&error_mutex); // serialize access
352
    qDebug() << "ModelController: throwError reached:";
353
    qDebug() << msg;
837 werner 354
    mLastError = msg;
355
    mHasError = true;
632 werner 356
    emit bufferLogs(false);
357
    emit bufferLogs(true); // start buffering again
358
 
359
    throw IException(msg); // raise error again
360
 
361
}
161 werner 362
//////////////////////////////////////
363
// dynamic outut
364
//////////////////////////////////////
365
//////////////////////////////////////
366
void ModelController::setupDynamicOutput(QString fieldList)
367
{
171 werner 368
    mDynFieldList.clear();
369
    if (!fieldList.isEmpty()) {
370
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
371
        int pos=0;
372
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
373
            mDynFieldList.append(rx.cap(1));
374
            pos += rx.matchedLength();
375
        }
376
 
377
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
170 werner 378
        mDynFieldList.prepend("count");
379
        mDynFieldList.prepend("year"); // fixed fields.
380
    }
161 werner 381
    mDynData.clear();
382
    mDynData.append(mDynFieldList.join(";"));
802 werner 383
    mDynamicOutputEnabled = true;
161 werner 384
}
162 werner 385
 
161 werner 386
QString ModelController::dynamicOutput()
387
{
388
    return mDynData.join("\n");
389
}
390
 
218 werner 391
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
161 werner 392
void ModelController::fetchDynamicOutput()
393
{
802 werner 394
    if (!mDynamicOutputEnabled || mDynFieldList.isEmpty())
161 werner 395
        return;
165 werner 396
    DebugTimer t("dynamic output");
161 werner 397
    QStringList var;
398
    QString lastVar = "";
399
    QVector<double> data;
400
    AllTreeIterator at(mModel);
401
    TreeWrapper tw;
402
    int var_index;
403
    StatData stat;
404
    double value;
405
    QStringList line;
165 werner 406
    Expression custom_expr;
407
    bool simple_expression;
161 werner 408
    foreach (QString field, mDynFieldList) {
163 werner 409
        if (field=="count" || field=="year")
410
            continue;
166 werner 411
        if (field.count()>0 && field.at(0)=='[') {
412
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
413
            rex.indexIn(field);
414
            var = rex.capturedTexts();
415
            var.pop_front(); // drop first element (contains the full string)
165 werner 416
            simple_expression = false;
417
        } else {
418
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
419
            simple_expression = true;
420
        }
161 werner 421
        if (var.count()!=2)
422
                throw IException(QString("Invalid variable name for dynamic output:") + field);
423
        if (var.first()!=lastVar) {
424
            // load new field
425
            data.clear();
168 werner 426
            at.reset(); var_index = 0;
165 werner 427
            if (simple_expression) {
428
                var_index = tw.variableIndex(var.first());
166 werner 429
                if (var_index<0)
165 werner 430
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
166 werner 431
 
165 werner 432
            } else {
433
                custom_expr.setExpression(var.first());
434
                custom_expr.setModelObject(&tw);
161 werner 435
            }
436
            while (Tree *t = at.next()) {
437
                tw.setTree(t);
165 werner 438
                if (simple_expression)
439
                    value = tw.value(var_index);
440
                else
441
                    value = custom_expr.execute();
166 werner 442
                data.push_back(value);
161 werner 443
            }
444
            stat.setData(data);
445
        }
446
        // fetch data
447
        var_index = aggList.indexOf(var[1]);
448
        switch (var_index) {
449
            case 0: value = stat.mean(); break;
450
            case 1: value = stat.sum(); break;
451
            case 2: value = stat.min(); break;
452
            case 3: value = stat.max(); break;
453
            case 4: value = stat.percentile25(); break;
454
            case 5: value = stat.median(); break;
455
            case 6: value = stat.percentile75(); break;
218 werner 456
            case 7: value = stat.percentile(5); break;
457
            case 8: value = stat.percentile(10); break;
458
            case 9: value = stat.percentile(90); break;
459
            case 10: value = stat.percentile(95); break;
161 werner 460
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
461
                                  .arg(var[1]).arg(aggList.join(" ")));
462
        }
463
        line+=QString::number(value);
464
    }
162 werner 465
    line.prepend( QString::number(data.size()) );
466
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
467
    mDynData.append(line.join(";"));
161 werner 468
}
590 werner 469
 
470
void ModelController::saveScreenshot(QString file_name)
471
{
678 werner 472
#ifdef ILAND_GUI
590 werner 473
    if (!mViewerWindow)
474
        return;
475
    QImage img = mViewerWindow->screenshot();
476
    img.save(file_name);
678 werner 477
#endif
590 werner 478
}
596 werner 479
 
480
void ModelController::paintMap(MapGrid *map, double min_value, double max_value)
481
{
678 werner 482
#ifdef ILAND_GUI
596 werner 483
    if (mViewerWindow) {
643 werner 484
        mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value);
596 werner 485
        qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value;
486
    }
780 werner 487
#else
488
    Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 489
#endif
596 werner 490
}
632 werner 491
 
649 werner 492
void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value)
642 werner 493
{
678 werner 494
#ifdef ILAND_GUI
495
 
642 werner 496
    if (mViewerWindow) {
643 werner 497
        mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value);
642 werner 498
        qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value;
499
    }
780 werner 500
#else
501
    Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 502
#endif
642 werner 503
}
504
 
649 werner 505
void ModelController::addLayers(const LayeredGridBase *layers, const QString &name)
634 werner 506
{
678 werner 507
#ifdef ILAND_GUI
634 werner 508
    if (mViewerWindow)
649 werner 509
        mViewerWindow->addLayers(layers, name);
510
    //qDebug() << layers->names();
780 werner 511
#else
512
    Q_UNUSED(layers); Q_UNUSED(name);
678 werner 513
#endif
634 werner 514
}
632 werner 515
 
649 werner 516
void ModelController::setViewport(QPointF center_point, double scale_px_per_m)
646 werner 517
{
678 werner 518
#ifdef ILAND_GUI
647 werner 519
    if (mViewerWindow)
649 werner 520
        mViewerWindow->setViewport(center_point, scale_px_per_m);
780 werner 521
#else
522
    Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m);
678 werner 523
#endif
646 werner 524
}
634 werner 525
 
652 werner 526
void ModelController::repaint()
527
{
678 werner 528
#ifdef ILAND_GUI
652 werner 529
    if (mViewerWindow)
530
        mViewerWindow->repaint();
678 werner 531
#endif
652 werner 532
}
646 werner 533
 
649 werner 534
 
652 werner 535