Subversion Repositories public iLand

Rev

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