Subversion Repositories public iLand

Rev

Rev 1085 | Rev 1089 | 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
 
92 Werner 21
/** @class Model
247 werner 22
  Main object of the iLand model composited of various sub models / sub components.
697 werner 23
  @ingroup core
24
  The class Model is the top level container of iLand. The Model holds a collection of ResourceUnits, links to SpeciesSet and Climate.
25
  ResourceUnit are grid cells with (currently) a size of 1 ha (100x100m). Many stand level processes (NPP produciton, WaterCycle) operate on this
26
  level.
27
  The Model also contain the landscape-wide 2m LIF-grid (http://iland.boku.ac.at/competition+for+light).
28
 
92 Werner 29
  */
30
#include "global.h"
31
#include "model.h"
286 werner 32
#include "sqlhelper.h"
92 Werner 33
 
105 Werner 34
#include "xmlhelper.h"
808 werner 35
#include "debugtimer.h"
281 werner 36
#include "environment.h"
340 werner 37
#include "timeevents.h"
106 Werner 38
#include "helper.h"
189 iland 39
#include "resourceunit.h"
208 werner 40
#include "climate.h"
92 Werner 41
#include "speciesset.h"
106 Werner 42
#include "standloader.h"
43
#include "tree.h"
185 werner 44
#include "management.h"
200 werner 45
#include "modelsettings.h"
615 werner 46
#include "standstatistics.h"
543 werner 47
#include "mapgrid.h"
632 werner 48
#include "modelcontroller.h"
641 werner 49
#include "modules.h"
654 werner 50
#include "dem.h"
1062 werner 51
#include "grasscover.h"
92 Werner 52
 
202 werner 53
#include "outputmanager.h"
176 werner 54
 
890 werner 55
#include "forestmanagementengine.h"
56
 
105 Werner 57
#include <QtCore>
58
#include <QtXml>
59
 
107 Werner 60
/** iterate over all trees of the model. return NULL if all trees processed.
61
  Usage:
62
  @code
63
  AllTreeIterator trees(model);
64
  while (Tree *tree = trees.next()) { // returns NULL when finished.
65
     tree->something(); // do something
66
  }
281 werner 67
  @endcode  */
107 Werner 68
Tree *AllTreeIterator::next()
69
{
143 Werner 70
 
107 Werner 71
    if (!mTreeEnd) {
72
        // initialize to first ressource unit
73
        mRUIterator = mModel->ruList().constBegin();
314 werner 74
        // fast forward to the first RU with trees
75
        while (mRUIterator!=mModel->ruList().constEnd()) {
76
            if ((*mRUIterator)->trees().count()>0)
77
                break;
753 werner 78
            ++mRUIterator;
314 werner 79
        }
80
            // finished if all RU processed
81
        if (mRUIterator == mModel->ruList().constEnd())
82
            return NULL;
143 Werner 83
        mTreeEnd = &((*mRUIterator)->trees().back()) + 1; // let end point to "1 after end" (STL-style)
107 Werner 84
        mCurrent = &((*mRUIterator)->trees().front());
85
    }
86
    if (mCurrent==mTreeEnd) {
753 werner 87
        ++mRUIterator; // switch to next RU (loop until RU with trees is found)
314 werner 88
        while (mRUIterator!=mModel->ruList().constEnd()) {
89
            if ((*mRUIterator)->trees().count()>0) {
90
                break;
91
            }
753 werner 92
            ++mRUIterator;
314 werner 93
        }
107 Werner 94
        if (mRUIterator == mModel->ruList().constEnd()) {
143 Werner 95
            mCurrent = NULL;
96
            return NULL; // finished!!
107 Werner 97
        }else {
143 Werner 98
            mTreeEnd = &((*mRUIterator)->trees().back()) + 1;
107 Werner 99
            mCurrent = &((*mRUIterator)->trees().front());
100
        }
101
    }
143 Werner 102
 
103
    return mCurrent++;
107 Werner 104
}
157 werner 105
Tree *AllTreeIterator::nextLiving()
106
{
107
    while (Tree *t = next())
158 werner 108
        if (!t->isDead()) return t;
157 werner 109
    return NULL;
110
}
111
Tree *AllTreeIterator::current() const
112
{
113
    return mCurrent?mCurrent-1:NULL;
114
}
107 Werner 115
 
116
 
200 werner 117
ModelSettings Model::mSettings;
92 Werner 118
Model::Model()
119
{
120
    initialize();
137 Werner 121
    GlobalSettings::instance()->setModel(this);
767 werner 122
    GlobalSettings::instance()->resetScriptEngine(); // clear the script
130 Werner 123
    QString dbg="running in release mode.";
442 werner 124
    DBGMODE( dbg="running in debug mode."; );
130 Werner 125
    qDebug() << dbg;
92 Werner 126
}
127
 
128
Model::~Model()
129
{
130
    clear();
137 Werner 131
    GlobalSettings::instance()->setModel(NULL);
92 Werner 132
}
133
 
134
/** Initial setup of the Model.
135
  */
136
void Model::initialize()
137
{
151 iland 138
   mSetup = false;
162 werner 139
   GlobalSettings::instance()->setCurrentYear(0);
151 iland 140
   mGrid = 0;
141
   mHeightGrid = 0;
185 werner 142
   mManagement = 0;
909 werner 143
   mABEManagement = 0;
281 werner 144
   mEnvironment = 0;
340 werner 145
   mTimeEvents = 0;
549 werner 146
   mStandGrid = 0;
641 werner 147
   mModules = 0;
654 werner 148
   mDEM = 0;
1062 werner 149
   mGrassCover = 0;
92 Werner 150
}
151
 
261 werner 152
/** sets up the simulation space.
153
*/
103 Werner 154
void Model::setupSpace()
155
{
194 werner 156
    XmlHelper xml(GlobalSettings::instance()->settings().node("model.world"));
192 werner 157
    double cellSize = xml.value("cellSize", "2").toDouble();
158
    double width = xml.value("width", "100").toDouble();
159
    double height = xml.value("height", "100").toDouble();
549 werner 160
    double buffer = xml.value("buffer", "60").toDouble();
161
    mModelRect = QRectF(0., 0., width, height);
162
 
103 Werner 163
    qDebug() << QString("setup of the world: %1x%2m with cell-size=%3m and %4m buffer").arg(width).arg(height).arg(cellSize).arg(buffer);
164
 
165
    QRectF total_grid(QPointF(-buffer, -buffer), QPointF(width+buffer, height+buffer));
166
    qDebug() << "setup grid rectangle:" << total_grid;
167
 
151 iland 168
    if (mGrid)
169
        delete mGrid;
103 Werner 170
    mGrid = new FloatGrid(total_grid, cellSize);
156 werner 171
    mGrid->initialize(1.f);
151 iland 172
    if (mHeightGrid)
173
        delete mHeightGrid;
174
    mHeightGrid = new HeightGrid(total_grid, cellSize*5);
285 werner 175
    mHeightGrid->wipe(); // set all to zero
156 werner 176
    Tree::setGrid(mGrid, mHeightGrid);
105 Werner 177
 
569 werner 178
    // setup the spatial location of the project area
179
    if (xml.hasNode("location")) {
180
        // setup of spatial location
181
        double loc_x = xml.valueDouble("location.x");
182
        double loc_y = xml.valueDouble("location.y");
183
        double loc_z = xml.valueDouble("location.z");
184
        double loc_rot = xml.valueDouble("location.rotation");
185
        setupGISTransformation(loc_x, loc_y, loc_z, loc_rot);
186
        qDebug() << "setup of spatial location: x/y/z" << loc_x << loc_y << loc_z << "rotation:" << loc_rot;
187
    } else {
188
        setupGISTransformation(0., 0., 0., 0.);
189
    }
190
 
567 werner 191
    // load environment (multiple climates, speciesSets, ...
192
    if (mEnvironment)
193
        delete mEnvironment;
194
    mEnvironment = new Environment();
281 werner 195
 
567 werner 196
    if (xml.valueBool("environmentEnabled", false)) {
197
        QString env_file = GlobalSettings::instance()->path(xml.value("environmentFile"));
198
        bool grid_mode = (xml.value("environmentMode")=="grid");
199
        QString grid_file = GlobalSettings::instance()->path(xml.value("environmentGrid"));
893 werner 200
        if (grid_mode) {
201
            if (QFile::exists(grid_file))
202
                mEnvironment->setGridMode(grid_file);
203
            else
204
                throw IException(QString("File '%1' specified in key 'environmentGrid' does not exit ('environmentMode' is 'grid').").arg(grid_file) );
205
        }
567 werner 206
 
207
        if (!mEnvironment->loadFromFile(env_file))
208
            return;
209
    } else {
210
        // load and prepare default values
211
        // (2) SpeciesSets: currently only one a global species set.
212
        SpeciesSet *speciesSet = new SpeciesSet();
213
        mSpeciesSets.push_back(speciesSet);
214
        speciesSet->setup();
215
        // Climate...
216
        Climate *c = new Climate();
217
        mClimates.push_back(c);
218
        mEnvironment->setDefaultValues(c, speciesSet);
219
    } // environment?
220
 
221
    // time series data
222
    if (xml.valueBool(".timeEventsEnabled", false)) {
223
        mTimeEvents = new TimeEvents();
584 werner 224
        mTimeEvents->loadFromFile(GlobalSettings::instance()->path(xml.value("timeEventsFile"), "script"));
567 werner 225
    }
226
 
646 werner 227
 
105 Werner 228
    // simple case: create ressource units in a regular grid.
194 werner 229
    if (xml.valueBool("resourceUnitsAsGrid")) {
881 werner 230
 
281 werner 231
        mRUmap.setup(QRectF(0., 0., width, height),100.); // Grid, that holds positions of resource units
881 werner 232
        mRUmap.wipe();
646 werner 233
 
539 werner 234
        bool mask_is_setup = false;
235
        if (xml.valueBool("standGrid.enabled")) {
236
            QString fileName = GlobalSettings::instance()->path(xml.value("standGrid.fileName"));
882 werner 237
            mStandGrid = new MapGrid(fileName,false); // create stand grid index later
543 werner 238
 
549 werner 239
            if (mStandGrid->isValid()) {
714 werner 240
                for (int i=0;i<mStandGrid->grid().count();i++) {
241
                    const int &grid_value = mStandGrid->grid().constValueAtIndex(i);
242
                    mHeightGrid->valueAtIndex(i).setValid( grid_value > -1 );
881 werner 243
                    if (grid_value>-1)
244
                        mRUmap.valueAt(mStandGrid->grid().cellCenterPoint(i)) = (ResourceUnit*)1;
714 werner 245
                    if (grid_value < -1)
718 werner 246
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
714 werner 247
                }
539 werner 248
            }
249
            mask_is_setup = true;
802 werner 250
        } else {
251
            if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
252
                // in the case we have no stand grid but only a large rectangle (without the torus option)
253
                // we assume a forest outside
254
                for (int i=0;i<mHeightGrid->count();++i) {
255
                    const QPointF &p = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
256
                    if (p.x() < 0. || p.x()>width || p.y()<0. || p.y()>height) {
257
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
258
                        mHeightGrid->valueAtIndex(i).setValid(false);
259
                    }
260
                }
261
 
262
            }
539 werner 263
        }
264
 
881 werner 265
        ResourceUnit **p; // ptr to ptr!
266
        ResourceUnit *new_ru;
267
 
268
        int ru_index = 0;
269
        for (p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
270
            QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
1032 werner 271
            if (!mStandGrid || !mStandGrid->isValid() || *p>NULL) {
917 werner 272
                mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
881 werner 273
                // create resource units for valid positions only
274
                new_ru = new ResourceUnit(ru_index++); // create resource unit
275
                new_ru->setClimate( mEnvironment->climate() );
276
                new_ru->setSpeciesSet( mEnvironment->speciesSet() );
277
                new_ru->setup();
278
                new_ru->setID( mEnvironment->currentID() ); // set id of resource unit in grid mode
279
                new_ru->setBoundingBox(r);
280
                mRU.append(new_ru);
889 werner 281
                *p = new_ru; // save in the RUmap grid
881 werner 282
            }
283
        }
1013 werner 284
        if (mEnvironment) {
285
            // retrieve species sets and climates (that were really used)
286
            mSpeciesSets << mEnvironment->speciesSetList();
287
            mClimates << mEnvironment->climateList();
1064 werner 288
            QString climate_file_list;
289
            for (int i=0, c=0;i<mClimates.count();++i) {
290
                climate_file_list += mClimates[i]->name() + ", ";
291
                if (++c>5) {
292
                    climate_file_list += "...";
293
                    break;
294
                }
881 werner 295
 
1064 werner 296
            }
297
            qDebug() << "Setup of climates: #loaded:" << mClimates.count() << "tables:" << climate_file_list;
298
 
299
 
1013 werner 300
        }
301
 
1011 werner 302
        qDebug() << "setup of" << mEnvironment->climateList().size() << "climates performed.";
303
 
889 werner 304
        if (mStandGrid && mStandGrid->isValid())
882 werner 305
            mStandGrid->createIndex();
881 werner 306
        // now store the pointers in the grid.
307
        // Important: This has to be done after the mRU-QList is complete - otherwise pointers would
308
        // point to invalid memory when QList's memory is reorganized (expanding)
309
//        ru_index = 0;
310
//        for (p=mRUmap.begin();p!=mRUmap.end(); ++p) {
311
//            *p = mRU.value(ru_index++);
312
//        }
313
        qDebug() << "created a grid of ResourceUnits: count=" << mRU.count() << "number of RU-map-cells:" << mRUmap.count();
314
 
315
 
574 werner 316
        calculateStockableArea();
317
 
285 werner 318
        // setup of the project area mask
539 werner 319
        if (!mask_is_setup && xml.valueBool("areaMask.enabled", false) && xml.hasNode("areaMask.imageFile")) {
285 werner 320
            // to be extended!!! e.g. to load ESRI-style text files....
321
            // setup a grid with the same size as the height grid...
322
            FloatGrid tempgrid((int)mHeightGrid->cellsize(), mHeightGrid->sizeX(), mHeightGrid->sizeY());
323
            QString fileName = GlobalSettings::instance()->path(xml.value("areaMask.imageFile"));
324
            loadGridFromImage(fileName, tempgrid); // fetch from image
325
            for (int i=0;i<tempgrid.count(); i++)
326
                mHeightGrid->valueAtIndex(i).setValid( tempgrid.valueAtIndex(i)>0.99 );
327
            qDebug() << "loaded project area mask from" << fileName;
328
        }
329
 
590 werner 330
        // list of "valid" resource units
331
        QList<ResourceUnit*> valid_rus;
332
        foreach(ResourceUnit* ru, mRU)
333
            if (ru->id()!=-1)
334
                valid_rus.append(ru);
335
 
654 werner 336
        // setup of the digital elevation map (if present)
337
        QString dem_file = xml.value("DEM");
338
        if (!dem_file.isEmpty()) {
656 werner 339
            mDEM = new DEM(GlobalSettings::instance()->path(dem_file));
340
            // add them to the visuals...
341
            GlobalSettings::instance()->controller()->addGrid(mDEM, "DEM height", GridViewRainbow, 0, 1000);
342
            GlobalSettings::instance()->controller()->addGrid(mDEM->slopeGrid(), "DEM slope", GridViewRainbow, 0, 3);
343
            GlobalSettings::instance()->controller()->addGrid(mDEM->aspectGrid(), "DEM aspect", GridViewRainbow, 0, 360);
344
            GlobalSettings::instance()->controller()->addGrid(mDEM->viewGrid(), "DEM view", GridViewGray, 0, 1);
345
 
654 werner 346
        }
347
 
1062 werner 348
        // setup of the grass cover
349
        if (!mGrassCover)
350
            mGrassCover = new GrassCover();
351
        mGrassCover->setup();
352
 
646 werner 353
        // setup of external modules
354
        mModules->setup();
355
        if (mModules->hasSetupResourceUnits()) {
356
            for (ResourceUnit **p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
1087 werner 357
                if (*p) {
358
                    QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
359
                    mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
360
                    mModules->setupResourceUnit( *p );
361
                }
646 werner 362
            }
363
        }
364
 
767 werner 365
        // setup of scripting environment
366
        ScriptGlobal::setupGlobalScripting();
367
 
123 Werner 368
        // setup the helper that does the multithreading
590 werner 369
        threadRunner.setup(valid_rus);
194 werner 370
        threadRunner.setMultithreading(GlobalSettings::instance()->settings().valueBool("system.settings.multithreading"));
123 Werner 371
        threadRunner.print();
105 Werner 372
 
1071 werner 373
 
194 werner 374
    } else  {
375
        throw IException("resourceUnitsAsGrid MUST be set to true - at least currently :)");
105 Werner 376
    }
120 Werner 377
    mSetup = true;
103 Werner 378
}
379
 
380
 
92 Werner 381
/** clear() frees all ressources allocated with the run of a simulation.
382
 
383
  */
384
void Model::clear()
385
{
143 Werner 386
    mSetup = false;
151 iland 387
    qDebug() << "Model clear: attempting to clear" << mRU.count() << "RU, " << mSpeciesSets.count() << "SpeciesSets.";
92 Werner 388
    // clear ressource units
103 Werner 389
    qDeleteAll(mRU); // delete ressource units (and trees)
92 Werner 390
    mRU.clear();
103 Werner 391
 
392
    qDeleteAll(mSpeciesSets); // delete species sets
92 Werner 393
    mSpeciesSets.clear();
103 Werner 394
 
208 werner 395
    // delete climate data
396
    qDeleteAll(mClimates);
397
 
151 iland 398
    // delete the grids
399
    if (mGrid)
400
        delete mGrid;
401
    if (mHeightGrid)
402
        delete mHeightGrid;
185 werner 403
    if (mManagement)
404
        delete mManagement;
281 werner 405
    if (mEnvironment)
406
        delete mEnvironment;
340 werner 407
    if (mTimeEvents)
408
        delete mTimeEvents;
549 werner 409
    if (mStandGrid)
410
        delete mStandGrid;
641 werner 411
    if (mModules)
412
        delete mModules;
654 werner 413
    if (mDEM)
414
        delete mDEM;
1062 werner 415
    if (mGrassCover)
416
        delete mGrassCover;
909 werner 417
    if (mABEManagement)
418
        delete mABEManagement;
103 Werner 419
 
185 werner 420
    mGrid = 0;
421
    mHeightGrid = 0;
422
    mManagement = 0;
281 werner 423
    mEnvironment = 0;
340 werner 424
    mTimeEvents = 0;
549 werner 425
    mStandGrid  = 0;
641 werner 426
    mModules = 0;
654 werner 427
    mDEM = 0;
1062 werner 428
    mGrassCover = 0;
909 werner 429
    mABEManagement = 0;
185 werner 430
 
583 werner 431
    GlobalSettings::instance()->outputManager()->close();
432
 
92 Werner 433
    qDebug() << "Model ressources freed.";
434
}
435
 
436
/** Setup of the Simulation.
437
  This really creates the simulation environment and does the setup of various aspects.
438
  */
102 Werner 439
void Model::loadProject()
92 Werner 440
{
109 Werner 441
    DebugTimer dt("load project");
93 Werner 442
    GlobalSettings *g = GlobalSettings::instance();
679 werner 443
    g->printDirecories();
102 Werner 444
    const XmlHelper &xml = g->settings();
189 iland 445
 
93 Werner 446
    g->clearDatabaseConnections();
92 Werner 447
    // database connections: reset
94 Werner 448
    GlobalSettings::instance()->clearDatabaseConnections();
286 werner 449
    // input and climate connection
450
    // see initOutputDatabase() for output database
191 werner 451
    QString dbPath = g->path( xml.value("system.database.in"), "database");
194 werner 452
    GlobalSettings::instance()->setupDatabaseConnection("in", dbPath, true);
193 werner 453
    dbPath = g->path( xml.value("system.database.climate"), "database");
194 werner 454
    GlobalSettings::instance()->setupDatabaseConnection("climate", dbPath, true);
92 Werner 455
 
200 werner 456
    mSettings.loadModelSettings();
457
    mSettings.print();
416 werner 458
    // random seed: if stored value is <> 0, use this as the random seed (and produce hence always an equal sequence of random numbers)
459
    uint seed = xml.value("system.settings.randomSeed","0").toUInt();
708 werner 460
    RandomGenerator::setup(RandomGenerator::ergMersenneTwister, seed); // use the MersenneTwister as default
428 werner 461
    // linearization of expressions: if true *and* linearize() is explicitely called, then
462
    // function results will be cached over a defined range of values.
463
    bool do_linearization = xml.valueBool("system.settings.expressionLinearizationEnabled", false);
464
    Expression::setLinearizationEnabled(do_linearization);
431 werner 465
    if (do_linearization)
466
        qDebug() << "The linearization of certains expressions is enabled (performance optimization).";
467
 
468
    // log level
469
    QString log_level = xml.value("system.settings.logLevel", "debug").toLower();
470
    if (log_level=="debug") setLogLevel(0);
471
    if (log_level=="info") setLogLevel(1);
472
    if (log_level=="warning") setLogLevel(2);
473
    if (log_level=="error") setLogLevel(3);
474
 
475 werner 475
    // snag dynamics / soil model enabled? (info used during setup of world)
476
    changeSettings().carbonCycleEnabled = xml.valueBool("model.settings.carbonCycleEnabled", false);
528 werner 477
    // class size of snag classes
478
    Snag::setupThresholds(xml.valueDouble("model.settings.soil.swdDBHClass12"),
479
                          xml.valueDouble("model.settings.soil.swdDBHClass23"));
475 werner 480
 
646 werner 481
    // setup of modules
482
    if (mModules)
483
        delete mModules;
484
    mModules = new Modules();
485
 
103 Werner 486
    setupSpace();
281 werner 487
    if (mRU.isEmpty())
488
        throw IException("Setup of Model: no resource units present!");
185 werner 489
 
490
    // (3) additional issues
837 werner 491
    // (3.1) load javascript code into the engine
1065 werner 492
    QString script_file = xml.value("system.javascript.fileName");
1064 werner 493
    if (!script_file.isEmpty()) {
1065 werner 494
        script_file = g->path(script_file, "script");
1064 werner 495
        ScriptGlobal::loadScript(script_file);
496
        g->controller()->setLoadedJavascriptFile(script_file);
497
    }
837 werner 498
 
499
    // (3.2) setup of regeneration
391 werner 500
    changeSettings().regenerationEnabled = xml.valueBool("model.settings.regenerationEnabled", false);
501
    if (settings().regenerationEnabled) {
502
        foreach(SpeciesSet *ss, mSpeciesSets)
503
            ss->setupRegeneration();
387 werner 504
    }
493 werner 505
    Sapling::setRecruitmentVariation(xml.valueDouble("model.settings.seedDispersal.recruitmentDimensionVariation",0.1));
468 werner 506
 
837 werner 507
    // (3.3) management
890 werner 508
    bool use_abe = xml.valueBool("model.management.abeEnabled");
509
    if (use_abe) {
510
        // use the agent based forest management engine
909 werner 511
        mABEManagement = new ABE::ForestManagementEngine();
890 werner 512
        // setup of ABE after loading of trees.
513
 
185 werner 514
    }
910 werner 515
    // use the standard management
516
    QString mgmtFile = xml.value("model.management.file");
517
    if (!mgmtFile.isEmpty() && xml.valueBool("model.management.enabled")) {
518
        mManagement = new Management();
519
        QString path = GlobalSettings::instance()->path(mgmtFile, "script");
520
        mManagement->loadScript(path);
521
        qDebug() << "setup management using script" << path;
522
    }
468 werner 523
 
524
 
910 werner 525
 
92 Werner 526
}
105 Werner 527
 
1058 werner 528
void Model::reloadABE()
529
{
530
    // delete firest
531
    if (mABEManagement)
532
        delete mABEManagement;
533
    mABEManagement = new ABE::ForestManagementEngine();
534
    // and setup
535
    mABEManagement->setup();
536
    mABEManagement->runOnInit();
105 Werner 537
 
1058 werner 538
    mABEManagement->initialize();
539
 
540
}
541
 
542
 
543 werner 543
ResourceUnit *Model::ru(QPointF coord)
105 Werner 544
{
106 Werner 545
    if (!mRUmap.isEmpty() && mRUmap.coordValid(coord))
546
        return mRUmap.valueAt(coord);
281 werner 547
    return ru(); // default RU if there is only one
105 Werner 548
}
549
 
286 werner 550
void Model::initOutputDatabase()
551
{
552
    GlobalSettings *g = GlobalSettings::instance();
553
    QString dbPath = g->path(g->settings().value("system.database.out"), "output");
554
    // create run-metadata
555
    int maxid = SqlHelper::queryValue("select max(id) from runs", g->dbin()).toInt();
556
 
557
    maxid++;
558
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
287 werner 559
    SqlHelper::executeSql(QString("insert into runs (id, timestamp) values (%1, '%2')").arg(maxid).arg(timestamp), g->dbin());
286 werner 560
    // replace path information
561
    dbPath.replace("$id$", QString::number(maxid));
562
    dbPath.replace("$date$", timestamp);
563
    // setup final path
564
   g->setupDatabaseConnection("out", dbPath, false);
565
 
566
}
567
 
903 werner 568
 
824 werner 569
/// multithreaded running function for the resource unit level establishment
570
ResourceUnit *nc_sapling_growth_establishment(ResourceUnit *unit)
440 werner 571
{
632 werner 572
    try {
1001 werner 573
        { // DebugTimer t("nc_saplingGrowth"); t.setSilent();
824 werner 574
        // define a height map for the current resource unit on the stack
632 werner 575
        float sapling_map[cPxPerRU*cPxPerRU];
824 werner 576
        // set the map and initialize it:
632 werner 577
        unit->setSaplingHeightMap(sapling_map);
444 werner 578
 
450 werner 579
 
451 werner 580
        // (1) calculate the growth of (already established) saplings (populate sapling map)
824 werner 581
        QList<ResourceUnitSpecies*>::const_iterator rus;
582
        for (rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
583
            (*rus)->calclulateSaplingGrowth();
615 werner 584
 
1001 werner 585
        } { // DebugTimer t("nc_Establishment"); t.setSilent();
998 werner 586
 
824 werner 587
        // (2) calculate the establishment probabilities of new saplings
998 werner 588
        for (QList<ResourceUnitSpecies*>::const_iterator rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
864 werner 589
            (*rus)->calculateEstablishment();
615 werner 590
 
998 werner 591
        }
615 werner 592
 
440 werner 593
    } catch (const IException& e) {
632 werner 594
        GlobalSettings::instance()->controller()->throwError(e.message());
440 werner 595
    }
632 werner 596
 
824 werner 597
    unit->setSaplingHeightMap(0); // invalidate again
440 werner 598
    return unit;
824 werner 599
 
440 werner 600
}
601
 
824 werner 602
 
475 werner 603
/// multithreaded execution of the carbon cycle routine
604
ResourceUnit *nc_carbonCycle(ResourceUnit *unit)
605
{
611 werner 606
    try {
632 werner 607
        // (1) do calculations on snag dynamics for the resource unit
608
        unit->calculateCarbonCycle();
609
        // (2) do the soil carbon and nitrogen dynamics calculations (ICBM/2N)
610
    } catch (const IException& e) {
611
        GlobalSettings::instance()->controller()->throwError(e.message());
611 werner 612
    }
613
 
475 werner 614
    return unit;
615
}
616
 
440 werner 617
/// beforeRun performs several steps before the models starts running.
618
/// inter alia: * setup of the stands
619
///             * setup of the climates
105 Werner 620
void Model::beforeRun()
621
{
395 werner 622
    // setup outputs
623
    // setup output database
539 werner 624
    if (GlobalSettings::instance()->dbout().isOpen())
625
        GlobalSettings::instance()->dbout().close();
395 werner 626
    initOutputDatabase();
627
    GlobalSettings::instance()->outputManager()->setup();
628
    GlobalSettings::instance()->clearDebugLists();
629
 
105 Werner 630
    // initialize stands
967 werner 631
    StandLoader loader(this);
251 werner 632
    {
106 Werner 633
    DebugTimer loadtrees("load trees");
634
    loader.processInit();
251 werner 635
    }
934 werner 636
    // initalization of ABE
637
    if (mABEManagement) {
638
        mABEManagement->setup();
639
        mABEManagement->runOnInit();
640
    }
106 Werner 641
 
214 werner 642
    // load climate
251 werner 643
    {
1024 werner 644
        if (logLevelDebug()) qDebug() << "attempting to load climate..." ;
645
        DebugTimer loadclim("load climate");
646
        foreach(Climate *c, mClimates) {
647
            if (!c->isSetup())
648
                c->setup();
649
        }
650
        // load the first year of the climate database
651
        foreach(Climate *c, mClimates)
652
            c->nextYear();
214 werner 653
 
251 werner 654
    }
655
 
934 werner 656
 
251 werner 657
    { DebugTimer loadinit("load standstatistics");
734 werner 658
    if (logLevelDebug()) qDebug() << "attempting to calculate initial stand statistics (incl. apply and read pattern)..." ;
135 Werner 659
    Tree::setGrid(mGrid, mHeightGrid);
737 werner 660
    // debugCheckAllTrees(); // introduced for debugging session (2012-04-06)
135 Werner 661
    applyPattern();
662
    readPattern();
967 werner 663
    loader.processAfterInit(); // e.g. initialization of saplings
106 Werner 664
 
376 werner 665
    // force the compilation of initial stand statistics
241 werner 666
    createStandStatistics();
251 werner 667
    }
286 werner 668
 
934 werner 669
    // initalization of ABE (now all stands are properly set up)
909 werner 670
    if (mABEManagement) {
934 werner 671
        mABEManagement->initialize();
890 werner 672
    }
673
 
674
 
264 werner 675
    // outputs to create with inital state (without any growth) are called here:
936 werner 676
    GlobalSettings::instance()->setCurrentYear(0); // set clock to "0" (for outputs with initial state)
677
 
257 werner 678
    GlobalSettings::instance()->outputManager()->execute("stand"); // year=0
837 werner 679
    GlobalSettings::instance()->outputManager()->execute("landscape"); // year=0
504 werner 680
    GlobalSettings::instance()->outputManager()->execute("sapling"); // year=0
264 werner 681
    GlobalSettings::instance()->outputManager()->execute("tree"); // year=0
395 werner 682
    GlobalSettings::instance()->outputManager()->execute("dynamicstand"); // year=0
264 werner 683
 
257 werner 684
    GlobalSettings::instance()->setCurrentYear(1); // set to first year
1024 werner 685
 
105 Werner 686
}
687
 
331 werner 688
/** Main model runner.
689
  The sequence of actions is as follows:
690
  (1) Load the climate of the new year
691
  (2) Reset statistics for resource unit as well as for dead/managed trees
714 werner 692
  (3) Invoke Management.
331 werner 693
  (4) *after* that, calculate Light patterns
694
  (5) 3PG on stand level, tree growth. Clear stand-statistcs before they are filled by single-tree-growth. calculate water cycle (with LAIs before management)
440 werner 695
  (6) execute Regeneration
714 werner 696
  (7) invoke disturbance modules
697
  (8) calculate statistics for the year
698
  (9) write database outputs
331 werner 699
  */
105 Werner 700
void Model::runYear()
701
{
223 werner 702
    DebugTimer t("Model::runYear()");
615 werner 703
    GlobalSettings::instance()->systemStatistics()->reset();
707 werner 704
    RandomGenerator::checkGenerator(); // see if we need to generate new numbers...
649 werner 705
    // initalization at start of year for external modules
706
    mModules->yearBegin();
903 werner 707
 
341 werner 708
    // execute scheduled events for the current year
709
    if (mTimeEvents)
710
        mTimeEvents->run();
711
 
1024 werner 712
    // load the next year of the climate database (except for the first year - the first climate year is loaded immediately
713
    if (GlobalSettings::instance()->currentYear()>1) {
714
        foreach(Climate *c, mClimates)
715
            c->nextYear();
716
    }
214 werner 717
 
278 werner 718
    // reset statistics
719
    foreach(ResourceUnit *ru, mRU)
720
        ru->newYear();
721
 
391 werner 722
    foreach(SpeciesSet *set, mSpeciesSets)
723
        set->newYear();
890 werner 724
    // management classic
615 werner 725
    if (mManagement) {
726
        DebugTimer t("management");
278 werner 727
        mManagement->run();
615 werner 728
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
729
    }
909 werner 730
    // ... or ABE (the agent based variant)
731
    if (mABEManagement) {
732
        DebugTimer t("ABE:run");
733
        mABEManagement->run();
890 werner 734
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
735
    }
278 werner 736
 
937 werner 737
    // if trees are dead/removed because of management, the tree lists
738
    // need to be cleaned (and the statistics need to be recreated)
739
    cleanTreeLists();
740
 
214 werner 741
    // process a cycle of individual growth
277 werner 742
    applyPattern(); // create Light Influence Patterns
743
    readPattern(); // readout light state of individual trees
744
    grow(); // let the trees grow (growth on stand-level, tree-level, mortality)
1062 werner 745
    mGrassCover->execute(); // evaluate the grass / herb cover (and its effect on regeneration)
106 Werner 746
 
391 werner 747
    // regeneration
748
    if (settings().regenerationEnabled) {
440 werner 749
        // seed dispersal
483 werner 750
        DebugTimer tseed("Regeneration and Establishment");
391 werner 751
        foreach(SpeciesSet *set, mSpeciesSets)
475 werner 752
            set->regeneration(); // parallel execution for each species set
440 werner 753
 
615 werner 754
        GlobalSettings::instance()->systemStatistics()->tSeedDistribution+=tseed.elapsed();
440 werner 755
        // establishment
1063 werner 756
        Sapling::updateBrowsingPressure();
757
 
824 werner 758
        { DebugTimer t("saplingGrowthEstablishment");
759
        executePerResourceUnit( nc_sapling_growth_establishment, false /* true: force single thraeded operation */);
864 werner 760
        GlobalSettings::instance()->systemStatistics()->tSaplingAndEstablishment+=t.elapsed();
615 werner 761
        }
824 werner 762
 
1068 werner 763
        Establishment::debugInfo(); // debug test
764
 
615 werner 765
    }
440 werner 766
 
468 werner 767
    // calculate soil / snag dynamics
475 werner 768
    if (settings().carbonCycleEnabled) {
769
        DebugTimer ccycle("carbon cylce");
1063 werner 770
        executePerResourceUnit( nc_carbonCycle, false /* true: force single threaded operation */);
615 werner 771
        GlobalSettings::instance()->systemStatistics()->tCarbonCycle+=ccycle.elapsed();
772
 
475 werner 773
    }
649 werner 774
 
775
    // external modules/disturbances
776
    mModules->run();
777
 
937 werner 778
    // cleanup of tree lists if external modules removed trees.
779
    cleanTreeLists();
664 werner 780
 
937 werner 781
 
615 werner 782
    DebugTimer toutput("outputs");
278 werner 783
    // calculate statistics
784
    foreach(ResourceUnit *ru, mRU)
785
        ru->yearEnd();
124 Werner 786
 
277 werner 787
    // create outputs
184 werner 788
    OutputManager *om = GlobalSettings::instance()->outputManager();
285 werner 789
    om->execute("tree"); // single tree output
278 werner 790
    om->execute("stand"); //resource unit level x species
837 werner 791
    om->execute("landscape"); //landscape x species
504 werner 792
    om->execute("sapling"); // sapling layer per RU x species
278 werner 793
    om->execute("production_month"); // 3pg responses growth per species x RU x month
285 werner 794
    om->execute("dynamicstand"); // output with user-defined columns (based on species x RU)
278 werner 795
    om->execute("standdead"); // resource unit level x species
796
    om->execute("management"); // resource unit level x species
587 werner 797
    om->execute("carbon"); // resource unit level, carbon pools above and belowground
609 werner 798
    om->execute("carbonflow"); // resource unit level, GPP, NPP and total carbon flows (atmosphere, harvest, ...)
185 werner 799
 
615 werner 800
    GlobalSettings::instance()->systemStatistics()->tWriteOutput+=toutput.elapsed();
801
    GlobalSettings::instance()->systemStatistics()->tTotalYear+=t.elapsed();
802
    GlobalSettings::instance()->systemStatistics()->writeOutput();
803
 
162 werner 804
    GlobalSettings::instance()->setCurrentYear(GlobalSettings::instance()->currentYear()+1);
1085 werner 805
 
806
    // try to clean up a bit of memory (useful if many large JS objects (e.g., grids) are used)
807
    GlobalSettings::instance()->scriptEngine()->collectGarbage();
105 Werner 808
}
809
 
278 werner 810
 
811
 
105 Werner 812
void Model::afterStop()
813
{
814
    // do some cleanup
815
}
106 Werner 816
 
369 werner 817
/// multithreaded running function for LIP printing
187 iland 818
ResourceUnit* nc_applyPattern(ResourceUnit *unit)
106 Werner 819
{
820
 
821
    QVector<Tree>::iterator tit;
118 Werner 822
    QVector<Tree>::iterator tend = unit->trees().end();
107 Werner 823
 
632 werner 824
    try {
107 Werner 825
 
632 werner 826
        // light concurrence influence
827
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
828
            // height dominance grid
829
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
830
                (*tit).heightGrid(); // just do it ;)
155 werner 831
 
632 werner 832
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
833
                (*tit).applyLIP(); // just do it ;)
155 werner 834
 
632 werner 835
        } else {
836
            // height dominance grid
837
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
838
                (*tit).heightGrid_torus(); // just do it ;)
155 werner 839
 
632 werner 840
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
841
                (*tit).applyLIP_torus(); // do it the wraparound way
842
        }
843
        return unit;
844
    } catch (const IException &e) {
845
        GlobalSettings::instance()->controller()->throwError(e.message());
118 Werner 846
    }
847
    return unit;
848
}
106 Werner 849
 
369 werner 850
/// multithreaded running function for LIP value extraction
187 iland 851
ResourceUnit *nc_readPattern(ResourceUnit *unit)
118 Werner 852
{
853
    QVector<Tree>::iterator tit;
854
    QVector<Tree>::iterator  tend = unit->trees().end();
632 werner 855
    try {
856
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
857
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
858
                (*tit).readLIF(); // multipliactive approach
859
        } else {
860
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
861
                (*tit).readLIF_torus(); // do it the wraparound way
862
        }
863
    } catch (const IException &e) {
864
        GlobalSettings::instance()->controller()->throwError(e.message());
118 Werner 865
    }
866
    return unit;
106 Werner 867
}
868
 
369 werner 869
/// multithreaded running function for the growth of individual trees
187 iland 870
ResourceUnit *nc_grow(ResourceUnit *unit)
118 Werner 871
{
872
    QVector<Tree>::iterator tit;
873
    QVector<Tree>::iterator  tend = unit->trees().end();
632 werner 874
    try {
875
        unit->beforeGrow(); // reset statistics
876
        // calculate light responses
877
        // responses are based on *modified* values for LightResourceIndex
878
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
879
            (*tit).calcLightResponse();
880
        }
118 Werner 881
 
632 werner 882
        unit->calculateInterceptedArea();
251 werner 883
 
632 werner 884
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
885
            (*tit).grow(); // actual growth of individual trees
886
        }
887
    } catch (const IException &e) {
888
        GlobalSettings::instance()->controller()->throwError(e.message());
118 Werner 889
    }
615 werner 890
 
891
    GlobalSettings::instance()->systemStatistics()->treeCount+=unit->trees().count();
118 Werner 892
    return unit;
893
}
894
 
369 werner 895
/// multithreaded running function for the resource level production
896
ResourceUnit *nc_production(ResourceUnit *unit)
897
{
632 werner 898
    try {
899
        unit->production();
900
    } catch (const IException &e) {
901
        GlobalSettings::instance()->controller()->throwError(e.message());
902
    }
369 werner 903
    return unit;
904
}
905
 
440 werner 906
 
124 Werner 907
void Model::test()
908
{
909
    // Test-funktion: braucht 1/3 time von readGrid()
910
    DebugTimer t("test");
911
    FloatGrid averaged = mGrid->averaged(10);
912
    int count = 0;
913
    float *end = averaged.end();
914
    for (float *p=averaged.begin(); p!=end; ++p)
915
        if (*p > 0.9)
916
            count++;
917
    qDebug() << count << "LIF>0.9 of " << averaged.count();
918
}
919
 
734 werner 920
void Model::debugCheckAllTrees()
921
{
922
    AllTreeIterator at(this);
923
    bool has_errors = false; double dummy=0.;
924
    while (Tree *t = at.next()) {
925
        // plausibility
926
        if (t->dbh()<0 || t->dbh()>10000. || t->biomassFoliage()<0. || t->height()>1000. || t->height() < 0.
927
                || t->biomassFoliage() <0.)
928
            has_errors = true;
929
        // check for objects....
930
        dummy = t->stamp()->offset() + t->ru()->ruSpecies()[1]->statistics().count();
931
    }
932
    if (has_errors)
933
        qDebug() << "model: debugCheckAllTrees found problems" << dummy;
934
}
935
 
118 Werner 936
void Model::applyPattern()
937
{
938
 
939
    DebugTimer t("applyPattern()");
940
    // intialize grids...
720 werner 941
    initializeGrid();
551 werner 942
 
406 werner 943
    // initialize height grid with a value of 4m. This is the height of the regeneration layer
551 werner 944
    for (HeightGridValue *h=mHeightGrid->begin();h!=mHeightGrid->end();++h) {
945
        h->resetCount(); // set count = 0, but do not touch the flags
946
        h->height = 4.f;
947
    }
118 Werner 948
 
123 Werner 949
    threadRunner.run(nc_applyPattern);
615 werner 950
    GlobalSettings::instance()->systemStatistics()->tApplyPattern+=t.elapsed();
118 Werner 951
}
952
 
106 Werner 953
void Model::readPattern()
954
{
955
    DebugTimer t("readPattern()");
123 Werner 956
    threadRunner.run(nc_readPattern);
615 werner 957
    GlobalSettings::instance()->systemStatistics()->tReadPattern+=t.elapsed();
958
 
106 Werner 959
}
960
 
331 werner 961
/** Main function for the growth of stands and trees.
962
   This includes several steps.
963
   (1) calculate the stocked area (i.e. count pixels in height grid)
964
   (2) 3PG production (including response calculation, water cycle)
965
   (3) single tree growth (including mortality)
966
   (4) cleanup of tree lists (remove dead trees)
967
  */
106 Werner 968
void Model::grow()
969
{
151 iland 970
 
369 werner 971
    if (!settings().growthEnabled)
972
        return;
973
    { DebugTimer t("growRU()");
974
    calculateStockedArea();
113 Werner 975
 
374 werner 976
    // multithreaded: mutex for the message handler in mainwindow solved the crashes.
977
    threadRunner.run(nc_production);
370 werner 978
    }
979
 
980
    DebugTimer t("growTrees()");
251 werner 981
    threadRunner.run(nc_grow); // actual growth of individual trees
159 werner 982
 
187 iland 983
    foreach(ResourceUnit *ru, mRU) {
159 werner 984
       ru->cleanTreeList();
376 werner 985
       ru->afterGrow();
168 werner 986
       //qDebug() << (b-n) << "trees died (of" << b << ").";
159 werner 987
   }
615 werner 988
   GlobalSettings::instance()->systemStatistics()->tTreeGrowth+=t.elapsed();
123 Werner 989
}
151 iland 990
 
240 werner 991
/** calculate for each resource unit the fraction of area which is stocked.
992
  This is done by checking the pixels of the global height grid.
151 iland 993
  */
994
void Model::calculateStockedArea()
995
{
996
    // iterate over the whole heightgrid and count pixels for each ressource unit
997
    HeightGridValue *end = mHeightGrid->end();
998
    QPointF cp;
187 iland 999
    ResourceUnit *ru;
151 iland 1000
    for (HeightGridValue *i=mHeightGrid->begin(); i!=end; ++i) {
1001
        cp = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
1002
        if (mRUmap.coordValid(cp)) {
1003
            ru = mRUmap.valueAt(cp);
1004
            if (ru) {
285 werner 1005
                ru->countStockedPixel( (*i).count()>0 );
151 iland 1006
            }
1007
        }
1008
 
1009
    }
1010
}
240 werner 1011
 
664 werner 1012
/** calculate for each resource unit the stockable area.
574 werner 1013
  "stockability" is determined by the isValid flag of resource units which in turn
1014
  is derived from stand grid values.
1015
  */
1016
void Model::calculateStockableArea()
1017
{
1018
 
1019
    foreach(ResourceUnit *ru, mRU) {
720 werner 1020
        // //
1021
        //        if (ru->id()==-1) {
1022
        //            ru->setStockableArea(0.);
1023
        //            continue;
1024
        //        }
574 werner 1025
        GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1026
        int valid=0, total=0;
1027
        while (runner.next()) {
1028
            if ( runner.current()->isValid() )
1029
                valid++;
1030
            total++;
1031
        }
575 werner 1032
        if (total) {
574 werner 1033
            ru->setStockableArea( cHeightPixelArea * valid);
734 werner 1034
            if (valid==0 && ru->id()>-1) {
1035
                // invalidate this resource unit
1036
                ru->setID(-1);
1037
            }
575 werner 1038
            if (valid>0 && ru->id()==-1) {
1039
                qDebug() << "Warning: a resource unit has id=-1 but stockable area (id was set to 0)!!! ru: " << ru->boundingBox() << "with index" << ru->index();
1040
                ru->setID(0);
664 werner 1041
                // test-code
1042
                //GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1043
                //while (runner.next()) {
1044
                //    qDebug() << mHeightGrid->cellCenterPoint(mHeightGrid->indexOf( runner.current() )) << ": " << runner.current()->isValid();
1045
                //}
585 werner 1046
 
575 werner 1047
            }
1048
        } else
574 werner 1049
            throw IException("calculateStockableArea: resource unit without pixels!");
1050
 
1051
    }
720 werner 1052
    // mark those pixels that are at the edge of a "forest-out-of-area"
1053
    GridRunner<HeightGridValue> runner(*mHeightGrid, mHeightGrid->metricRect());
1054
    HeightGridValue* neighbors[8];
1055
    while (runner.next()) {
1056
        if (runner.current()->isForestOutside()) {
1057
            // if the current pixel is a "radiating" border pixel,
1058
            // then check the neighbors and set a flag if the pixel is a neighbor of a in-project-area pixel.
1059
            runner.neighbors8(neighbors);
1060
            for (int i=0;i<8;++i)
1061
                if (neighbors[i] &&  neighbors[i]->isValid())
1062
                    runner.current()->setIsRadiating();
1063
 
1064
        }
1065
    }
1066
 
574 werner 1067
}
1068
 
720 werner 1069
void Model::initializeGrid()
1070
{
1071
    // fill the whole grid with a value of "1."
1072
    mGrid->initialize(1.f);
574 werner 1073
 
720 werner 1074
    // apply special values for grid cells border regions where out-of-area cells
1075
    // radiate into the main LIF grid.
1076
    QPoint p;
1077
    int ix_min, ix_max, iy_min, iy_max, ix_center, iy_center;
1078
    const int px_offset = cPxPerHeight / 2; // for 5 px per height grid cell, the offset is 2
1079
    const int max_radiate_distance = 7;
1080
    const float step_width = 1.f / (float)max_radiate_distance;
1081
    int c_rad = 0;
1082
    for (HeightGridValue *hgv=mHeightGrid->begin(); hgv!=mHeightGrid->end(); ++hgv) {
1083
        if (hgv->isRadiating()) {
1084
            p=mHeightGrid->indexOf(hgv);
1085
            ix_min = p.x() * cPxPerHeight - max_radiate_distance + px_offset;
1086
            ix_max = ix_min + 2*max_radiate_distance + 1;
1087
            ix_center = ix_min + max_radiate_distance;
1088
            iy_min = p.y() * cPxPerHeight - max_radiate_distance + px_offset;
1089
            iy_max = iy_min + 2*max_radiate_distance + 1;
1090
            iy_center = iy_min + max_radiate_distance;
1091
            for (int y=iy_min; y<=iy_max; ++y) {
1092
                for (int x=ix_min; x<=ix_max; ++x) {
802 werner 1093
                    if (!mGrid->isIndexValid(x,y) ||  !(*mHeightGrid)(x/cPxPerHeight, y/cPxPerHeight).isValid())
720 werner 1094
                        continue;
1095
                    float value = qMax(qAbs(x-ix_center), qAbs(y-iy_center)) * step_width;
1096
                    float &v = mGrid->valueAtIndex(x, y);
1097
                    if (value>=0.f && v>value)
1098
                        v = value;
1099
                }
1100
            }
1101
            c_rad++;
1102
        }
1103
    }
721 werner 1104
    if (logLevelDebug())
1105
        qDebug() << "initialize grid:" << c_rad << "radiating pixels...";
720 werner 1106
 
1107
}
1108
 
1109
 
241 werner 1110
/// Force the creation of stand statistics.
1111
/// - stocked area (for resourceunit-areas)
1112
/// - ru - statistics
240 werner 1113
void Model::createStandStatistics()
1114
{
241 werner 1115
    calculateStockedArea();
482 werner 1116
    foreach(ResourceUnit *ru, mRU) {
1117
        ru->addTreeAgingForAllTrees();
240 werner 1118
        ru->createStandStatistics();
482 werner 1119
    }
240 werner 1120
}
584 werner 1121
 
936 werner 1122
void Model::cleanTreeLists()
1123
{
937 werner 1124
    foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
1125
        if (ru->hasDiedTrees()) {
1126
            ru->cleanTreeList();
1127
            ru->recreateStandStatistics();
1128
        }
1129
    }
936 werner 1130
}
584 werner 1131
 
936 werner 1132