Subversion Repositories public iLand

Rev

Rev 802 | Rev 835 | 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;
223 werner 52
    mYearsToRun = 0;
590 werner 53
    mViewerWindow = 0;
802 werner 54
    mDynamicOutputEnabled = false;
105 Werner 55
}
128 Werner 56
 
57
ModelController::~ModelController()
58
{
59
    destroy();
60
}
61
 
590 werner 62
void ModelController::connectSignals()
63
{
64
    if (!mViewerWindow)
65
        return;
678 werner 66
#ifdef ILAND_GUI
590 werner 67
    connect(this,SIGNAL(bufferLogs(bool)), mViewerWindow, SLOT(bufferedLog(bool)));
678 werner 68
#endif
590 werner 69
}
70
 
514 werner 71
/// prepare a list of all (active) species
72
QHash<QString, QString> ModelController::availableSpecies()
73
{
74
    QHash<QString, QString> list;
75
    if (mModel) {
76
        SpeciesSet *set = mModel->speciesSet();
77
        if (!set)
78
            throw IException("there are 0 or more than one species sets.");
79
        foreach (const Species *s, set->activeSpecies()) {
80
            list[s->id()] = s->name();
81
        }
82
    }
83
    return list;
84
}
128 Werner 85
 
145 Werner 86
bool ModelController::canCreate()
128 Werner 87
{
129 Werner 88
    if (mModel)
128 Werner 89
        return false;
90
    return true;
91
}
92
 
145 Werner 93
bool ModelController::canDestroy()
128 Werner 94
{
95
    return mModel != NULL;
96
}
97
 
145 Werner 98
bool ModelController::canRun()
128 Werner 99
{
100
    if (mModel && mModel->isSetup())
101
        return true;
102
    return false;
103
}
104
 
145 Werner 105
bool ModelController::isRunning()
128 Werner 106
{
225 werner 107
    return mRunning;
128 Werner 108
}
109
 
225 werner 110
bool ModelController::isFinished()
111
{
112
    if (!mModel)
113
        return false;
114
    return canRun() && !isRunning()  && mFinished;
497 werner 115
}
128 Werner 116
 
776 werner 117
bool ModelController::isPaused()
118
{
119
    return mPaused;
120
}
121
 
497 werner 122
int ModelController::currentYear() const
123
{
124
    return GlobalSettings::instance()->currentYear();
225 werner 125
}
126
 
128 Werner 127
void ModelController::setFileName(QString initFileName)
128
{
129
    mInitFile = initFileName;
130
    try {
131
        GlobalSettings::instance()->loadProjectFile(mInitFile);
132
    } catch(const IException &e) {
575 werner 133
        QString error_msg = e.message();
128 Werner 134
        Helper::msg(error_msg);
135
        qDebug() << error_msg;
136
    }
137
}
138
 
139
void ModelController::create()
140
{
141
    if (!canCreate())
142
        return;
590 werner 143
    emit bufferLogs(true);
144
 
128 Werner 145
    try {
285 werner 146
        DebugTimer::clearAllTimers();
147
        mModel = new Model();
148
        mModel->loadProject();
286 werner 149
        if (!mModel->isSetup())
150
            return;
151
 
497 werner 152
        // reset clock...
153
        GlobalSettings::instance()->setCurrentYear(1); // reset clock
395 werner 154
        // initialization of trees, output on startup
286 werner 155
        mModel->beforeRun();
128 Werner 156
    } catch(const IException &e) {
575 werner 157
        QString error_msg = e.message();
128 Werner 158
        Helper::msg(error_msg);
159
        qDebug() << error_msg;
160
    }
590 werner 161
    emit bufferLogs(false);
162
 
362 werner 163
    qDebug() << "Model created.";
128 Werner 164
}
165
 
166
void ModelController::destroy()
167
{
168
    if (canDestroy()) {
169
        delete mModel;
170
        mModel = 0;
162 werner 171
        GlobalSettings::instance()->setCurrentYear(0);
128 Werner 172
        qDebug() << "ModelController: Model destroyed.";
173
    }
174
}
222 werner 175
 
223 werner 176
void ModelController::runloop()
177
{
515 werner 178
    static QTime sLastTime = QTime::currentTime();
678 werner 179
#ifdef ILAND_GUI
776 werner 180
 //   QApplication::processEvents();
678 werner 181
#else
776 werner 182
 //   QCoreApplication::processEvents();
678 werner 183
#endif
223 werner 184
    if (mPaused)
185
        return;
225 werner 186
    bool doStop = false;
187
    bool hasError = false;
515 werner 188
    if (GlobalSettings::instance()->currentYear()<=1) {
189
        sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation
190
    }
225 werner 191
 
192
    if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) {
590 werner 193
        emit bufferLogs(true);
776 werner 194
 
195
        hasError = runYear(); // do the work!
196
 
225 werner 197
        mRunning = true;
198
        emit year(GlobalSettings::instance()->currentYear());
497 werner 199
        if (!hasError) {
515 werner 200
            int elapsed = sLastTime.msecsTo(QTime::currentTime());
497 werner 201
            int time=0;
515 werner 202
            if (currentYear()%50==0 && elapsed>10000)
497 werner 203
                time = 100; // a 100ms pause...
515 werner 204
            if (currentYear()%100==0 && elapsed>10000) {
497 werner 205
                time = 500; // a 500ms pause...
206
            }
515 werner 207
            if (time>0) {
208
                sLastTime = QTime::currentTime(); // reset clock
209
                qDebug() << "--- little break ---- (after " << elapsed << "ms).";
776 werner 210
                //QTimer::singleShot(time,this, SLOT(runloop()));
515 werner 211
            }
776 werner 212
 
497 werner 213
        }
225 werner 214
        else
215
           doStop = true; // an error occured
216
 
217
    } else {
218
        doStop = true; // all years simulated
223 werner 219
    }
225 werner 220
 
221
    if (doStop || mCanceled) {
222
                // finished
776 werner 223
        internalStop();
225 werner 224
    }
267 werner 225
 
678 werner 226
#ifdef ILAND_GUI
225 werner 227
    QApplication::processEvents();
678 werner 228
#else
229
    QCoreApplication::processEvents();
230
#endif
223 werner 231
}
232
 
776 werner 233
bool ModelController::internalRun()
234
{
235
    // main loop
236
 
237
    while (mRunning && !mPaused &&  !mFinished) {
238
        runloop(); // start the running loop
239
    }
240
    return isFinished();
241
}
242
 
243
void ModelController::internalStop()
244
{
245
    if (mRunning) {
246
        GlobalSettings::instance()->outputManager()->save();
247
        DebugTimer::printAllTimers();
248
        mFinished = true;
249
    }
250
    mRunning = false;
251
    emit bufferLogs(false); // stop buffering
252
    emit finished(QString());
253
    emit stateChanged();
254
 
255
}
256
 
222 werner 257
void ModelController::run(int years)
128 Werner 258
{
222 werner 259
    if (!canRun())
260
        return;
590 werner 261
    emit bufferLogs(true); // start buffering
262
 
222 werner 263
    DebugTimer many_runs(QString("Timer for %1 runs").arg(years));
223 werner 264
    mPaused = false;
225 werner 265
    mFinished = false;
266
    mCanceled = false;
223 werner 267
    mYearsToRun = years;
497 werner 268
    //GlobalSettings::instance()->setCurrentYear(1); // reset clock
222 werner 269
 
270
    DebugTimer::clearAllTimers();
223 werner 271
 
759 werner 272
    mRunning = true;
776 werner 273
    emit stateChanged();
223 werner 274
 
776 werner 275
    qDebug() << "ModelControler: runloop started.";
276
    internalRun();
277
    emit stateChanged();
128 Werner 278
}
279
 
223 werner 280
bool ModelController::runYear()
128 Werner 281
{
223 werner 282
    if (!canRun()) return false;
421 werner 283
    DebugTimer t("ModelController:runYear");
497 werner 284
    qDebug() << "ModelController: run year" << currentYear();
421 werner 285
 
171 werner 286
    if (GlobalSettings::instance()->settings().paramValueBool("debug_clear"))
164 werner 287
        GlobalSettings::instance()->clearDebugLists();  // clear debug data
223 werner 288
    bool err=false;
128 Werner 289
    try {
590 werner 290
        emit bufferLogs(true);
128 Werner 291
        mModel->runYear();
162 werner 292
        fetchDynamicOutput();
128 Werner 293
    } catch(const IException &e) {
575 werner 294
        QString error_msg = e.message();
760 werner 295
#ifdef ILAND_GUI
128 Werner 296
        Helper::msg(error_msg);
760 werner 297
#endif
128 Werner 298
        qDebug() << error_msg;
223 werner 299
        err=true;
128 Werner 300
    }
590 werner 301
    emit bufferLogs(false);
223 werner 302
    return err;
128 Werner 303
}
304
 
222 werner 305
bool ModelController::pause()
306
{
223 werner 307
    if(!isRunning())
308
        return mPaused;
309
 
310
    if (mPaused) {
311
        // currently in pause - mode -> continue
312
        mPaused = false;
776 werner 313
 
223 werner 314
    } else {
315
        // currently running -> set to pause mode
316
        GlobalSettings::instance()->outputManager()->save();
317
        mPaused = true;
590 werner 318
        emit bufferLogs(false);
223 werner 319
    }
776 werner 320
    emit stateChanged();
223 werner 321
    return mPaused;
222 werner 322
}
128 Werner 323
 
776 werner 324
bool ModelController::continueRun()
325
{
326
    mRunning = true;
327
    emit stateChanged();
328
    return internalRun();
329
}
330
 
222 werner 331
void ModelController::cancel()
332
{
225 werner 333
    mCanceled = true;
776 werner 334
    internalStop();
335
    emit stateChanged();
222 werner 336
}
225 werner 337
 
632 werner 338
QMutex error_mutex;
339
void ModelController::throwError(const QString msg)
340
{
341
    QMutexLocker lock(&error_mutex); // serialize access
342
    qDebug() << "ModelController: throwError reached:";
343
    qDebug() << msg;
344
    emit bufferLogs(false);
345
    emit bufferLogs(true); // start buffering again
346
 
347
    throw IException(msg); // raise error again
348
 
349
}
161 werner 350
//////////////////////////////////////
351
// dynamic outut
352
//////////////////////////////////////
353
//////////////////////////////////////
354
void ModelController::setupDynamicOutput(QString fieldList)
355
{
171 werner 356
    mDynFieldList.clear();
357
    if (!fieldList.isEmpty()) {
358
        QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)");
359
        int pos=0;
360
        while ((pos = rx.indexIn(fieldList, pos)) != -1) {
361
            mDynFieldList.append(rx.cap(1));
362
            pos += rx.matchedLength();
363
        }
364
 
365
        //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
170 werner 366
        mDynFieldList.prepend("count");
367
        mDynFieldList.prepend("year"); // fixed fields.
368
    }
161 werner 369
    mDynData.clear();
370
    mDynData.append(mDynFieldList.join(";"));
802 werner 371
    mDynamicOutputEnabled = true;
161 werner 372
}
162 werner 373
 
161 werner 374
QString ModelController::dynamicOutput()
375
{
376
    return mDynData.join("\n");
377
}
378
 
218 werner 379
const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95";
161 werner 380
void ModelController::fetchDynamicOutput()
381
{
802 werner 382
    if (!mDynamicOutputEnabled || mDynFieldList.isEmpty())
161 werner 383
        return;
165 werner 384
    DebugTimer t("dynamic output");
161 werner 385
    QStringList var;
386
    QString lastVar = "";
387
    QVector<double> data;
388
    AllTreeIterator at(mModel);
389
    TreeWrapper tw;
390
    int var_index;
391
    StatData stat;
392
    double value;
393
    QStringList line;
165 werner 394
    Expression custom_expr;
395
    bool simple_expression;
161 werner 396
    foreach (QString field, mDynFieldList) {
163 werner 397
        if (field=="count" || field=="year")
398
            continue;
166 werner 399
        if (field.count()>0 && field.at(0)=='[') {
400
            QRegExp rex("\\[(.+)\\]\\.(\\w+)");
401
            rex.indexIn(field);
402
            var = rex.capturedTexts();
403
            var.pop_front(); // drop first element (contains the full string)
165 werner 404
            simple_expression = false;
405
        } else {
406
            var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts);
407
            simple_expression = true;
408
        }
161 werner 409
        if (var.count()!=2)
410
                throw IException(QString("Invalid variable name for dynamic output:") + field);
411
        if (var.first()!=lastVar) {
412
            // load new field
413
            data.clear();
168 werner 414
            at.reset(); var_index = 0;
165 werner 415
            if (simple_expression) {
416
                var_index = tw.variableIndex(var.first());
166 werner 417
                if (var_index<0)
165 werner 418
                    throw IException(QString("Invalid variable name for dynamic output:") + var.first());
166 werner 419
 
165 werner 420
            } else {
421
                custom_expr.setExpression(var.first());
422
                custom_expr.setModelObject(&tw);
161 werner 423
            }
424
            while (Tree *t = at.next()) {
425
                tw.setTree(t);
165 werner 426
                if (simple_expression)
427
                    value = tw.value(var_index);
428
                else
429
                    value = custom_expr.execute();
166 werner 430
                data.push_back(value);
161 werner 431
            }
432
            stat.setData(data);
433
        }
434
        // fetch data
435
        var_index = aggList.indexOf(var[1]);
436
        switch (var_index) {
437
            case 0: value = stat.mean(); break;
438
            case 1: value = stat.sum(); break;
439
            case 2: value = stat.min(); break;
440
            case 3: value = stat.max(); break;
441
            case 4: value = stat.percentile25(); break;
442
            case 5: value = stat.median(); break;
443
            case 6: value = stat.percentile75(); break;
218 werner 444
            case 7: value = stat.percentile(5); break;
445
            case 8: value = stat.percentile(10); break;
446
            case 9: value = stat.percentile(90); break;
447
            case 10: value = stat.percentile(95); break;
161 werner 448
            default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2")
449
                                  .arg(var[1]).arg(aggList.join(" ")));
450
        }
451
        line+=QString::number(value);
452
    }
162 werner 453
    line.prepend( QString::number(data.size()) );
454
    line.prepend( QString::number(GlobalSettings::instance()->currentYear()) );
455
    mDynData.append(line.join(";"));
161 werner 456
}
590 werner 457
 
458
void ModelController::saveScreenshot(QString file_name)
459
{
678 werner 460
#ifdef ILAND_GUI
590 werner 461
    if (!mViewerWindow)
462
        return;
463
    QImage img = mViewerWindow->screenshot();
464
    img.save(file_name);
678 werner 465
#endif
590 werner 466
}
596 werner 467
 
468
void ModelController::paintMap(MapGrid *map, double min_value, double max_value)
469
{
678 werner 470
#ifdef ILAND_GUI
596 werner 471
    if (mViewerWindow) {
643 werner 472
        mViewerWindow->paintGrid(map, "", GridViewRainbow, min_value, max_value);
596 werner 473
        qDebug() << "painted map grid" << map->name() << "min-value (blue):" << min_value << "max-value(red):" << max_value;
474
    }
780 werner 475
#else
476
    Q_UNUSED(map);Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 477
#endif
596 werner 478
}
632 werner 479
 
649 werner 480
void ModelController::addGrid(const FloatGrid *grid, const QString &name, const GridViewType view_type, double min_value, double max_value)
642 werner 481
{
678 werner 482
#ifdef ILAND_GUI
483
 
642 werner 484
    if (mViewerWindow) {
643 werner 485
        mViewerWindow->paintGrid(grid, name, view_type, min_value, max_value);
642 werner 486
        qDebug() << "painted grid min-value (blue):" << min_value << "max-value(red):" << max_value;
487
    }
780 werner 488
#else
489
    Q_UNUSED(grid); Q_UNUSED(name); Q_UNUSED(view_type); Q_UNUSED(min_value);Q_UNUSED(max_value);
678 werner 490
#endif
642 werner 491
}
492
 
649 werner 493
void ModelController::addLayers(const LayeredGridBase *layers, const QString &name)
634 werner 494
{
678 werner 495
#ifdef ILAND_GUI
634 werner 496
    if (mViewerWindow)
649 werner 497
        mViewerWindow->addLayers(layers, name);
498
    //qDebug() << layers->names();
780 werner 499
#else
500
    Q_UNUSED(layers); Q_UNUSED(name);
678 werner 501
#endif
634 werner 502
}
632 werner 503
 
649 werner 504
void ModelController::setViewport(QPointF center_point, double scale_px_per_m)
646 werner 505
{
678 werner 506
#ifdef ILAND_GUI
647 werner 507
    if (mViewerWindow)
649 werner 508
        mViewerWindow->setViewport(center_point, scale_px_per_m);
780 werner 509
#else
510
    Q_UNUSED(center_point);Q_UNUSED(scale_px_per_m);
678 werner 511
#endif
646 werner 512
}
634 werner 513
 
652 werner 514
void ModelController::repaint()
515
{
678 werner 516
#ifdef ILAND_GUI
652 werner 517
    if (mViewerWindow)
518
        mViewerWindow->repaint();
678 werner 519
#endif
652 werner 520
}
646 werner 521
 
649 werner 522
 
652 werner 523