Subversion Repositories public iLand

Rev

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