Subversion Repositories public iLand

Rev

Rev 1104 | Rev 1114 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1104 Rev 1111
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/model.cpp':
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/model.cpp':
2
/********************************************************************************************
2
/********************************************************************************************
3
**    iLand - an individual based forest landscape and disturbance model
3
**    iLand - an individual based forest landscape and disturbance model
4
**    http://iland.boku.ac.at
4
**    http://iland.boku.ac.at
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
6
**
6
**
7
**    This program is free software: you can redistribute it and/or modify
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
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
9
**    the Free Software Foundation, either version 3 of the License, or
10
**    (at your option) any later version.
10
**    (at your option) any later version.
11
**
11
**
12
**    This program is distributed in the hope that it will be useful,
12
**    This program is distributed in the hope that it will be useful,
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
**    GNU General Public License for more details.
15
**    GNU General Public License for more details.
16
**
16
**
17
**    You should have received a copy of the GNU General Public License
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/>.
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************************************/
19
********************************************************************************************/
20
20
21
/** @class Model
21
/** @class Model
22
  Main object of the iLand model composited of various sub models / sub components.
22
  Main object of the iLand model composited of various sub models / sub components.
23
  @ingroup core
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.
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
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.
26
  level.
27
  The Model also contain the landscape-wide 2m LIF-grid (http://iland.boku.ac.at/competition+for+light).
27
  The Model also contain the landscape-wide 2m LIF-grid (http://iland.boku.ac.at/competition+for+light).
28

28

29
  */
29
  */
30
#include "global.h"
30
#include "global.h"
31
#include "model.h"
31
#include "model.h"
32
#include "sqlhelper.h"
32
#include "sqlhelper.h"
33
33
34
#include "xmlhelper.h"
34
#include "xmlhelper.h"
35
#include "debugtimer.h"
35
#include "debugtimer.h"
36
#include "environment.h"
36
#include "environment.h"
37
#include "timeevents.h"
37
#include "timeevents.h"
38
#include "helper.h"
38
#include "helper.h"
39
#include "resourceunit.h"
39
#include "resourceunit.h"
40
#include "climate.h"
40
#include "climate.h"
41
#include "speciesset.h"
41
#include "speciesset.h"
42
#include "standloader.h"
42
#include "standloader.h"
43
#include "tree.h"
43
#include "tree.h"
44
#include "management.h"
44
#include "management.h"
-
 
45
#include "saplings.h"
45
#include "modelsettings.h"
46
#include "modelsettings.h"
46
#include "standstatistics.h"
47
#include "standstatistics.h"
47
#include "mapgrid.h"
48
#include "mapgrid.h"
48
#include "modelcontroller.h"
49
#include "modelcontroller.h"
49
#include "modules.h"
50
#include "modules.h"
50
#include "dem.h"
51
#include "dem.h"
51
#include "grasscover.h"
52
#include "grasscover.h"
52
53
53
#include "outputmanager.h"
54
#include "outputmanager.h"
54
55
55
#include "forestmanagementengine.h"
56
#include "forestmanagementengine.h"
56
57
57
#include <QtCore>
58
#include <QtCore>
58
#include <QtXml>
59
#include <QtXml>
59
60
60
/** iterate over all trees of the model. return NULL if all trees processed.
61
/** iterate over all trees of the model. return NULL if all trees processed.
61
  Usage:
62
  Usage:
62
  @code
63
  @code
63
  AllTreeIterator trees(model);
64
  AllTreeIterator trees(model);
64
  while (Tree *tree = trees.next()) { // returns NULL when finished.
65
  while (Tree *tree = trees.next()) { // returns NULL when finished.
65
     tree->something(); // do something
66
     tree->something(); // do something
66
  }
67
  }
67
  @endcode  */
68
  @endcode  */
68
Tree *AllTreeIterator::next()
69
Tree *AllTreeIterator::next()
69
{
70
{
70
71
71
    if (!mTreeEnd) {
72
    if (!mTreeEnd) {
72
        // initialize to first ressource unit
73
        // initialize to first ressource unit
73
        mRUIterator = mModel->ruList().constBegin();
74
        mRUIterator = mModel->ruList().constBegin();
74
        // fast forward to the first RU with trees
75
        // fast forward to the first RU with trees
75
        while (mRUIterator!=mModel->ruList().constEnd()) {
76
        while (mRUIterator!=mModel->ruList().constEnd()) {
76
            if ((*mRUIterator)->trees().count()>0)
77
            if ((*mRUIterator)->trees().count()>0)
77
                break;
78
                break;
78
            ++mRUIterator;
79
            ++mRUIterator;
79
        }
80
        }
80
            // finished if all RU processed
81
            // finished if all RU processed
81
        if (mRUIterator == mModel->ruList().constEnd())
82
        if (mRUIterator == mModel->ruList().constEnd())
82
            return NULL;
83
            return NULL;
83
        mTreeEnd = &((*mRUIterator)->trees().back()) + 1; // let end point to "1 after end" (STL-style)
84
        mTreeEnd = &((*mRUIterator)->trees().back()) + 1; // let end point to "1 after end" (STL-style)
84
        mCurrent = &((*mRUIterator)->trees().front());
85
        mCurrent = &((*mRUIterator)->trees().front());
85
    }
86
    }
86
    if (mCurrent==mTreeEnd) {
87
    if (mCurrent==mTreeEnd) {
87
        ++mRUIterator; // switch to next RU (loop until RU with trees is found)
88
        ++mRUIterator; // switch to next RU (loop until RU with trees is found)
88
        while (mRUIterator!=mModel->ruList().constEnd()) {
89
        while (mRUIterator!=mModel->ruList().constEnd()) {
89
            if ((*mRUIterator)->trees().count()>0) {
90
            if ((*mRUIterator)->trees().count()>0) {
90
                break;
91
                break;
91
            }
92
            }
92
            ++mRUIterator;
93
            ++mRUIterator;
93
        }
94
        }
94
        if (mRUIterator == mModel->ruList().constEnd()) {
95
        if (mRUIterator == mModel->ruList().constEnd()) {
95
            mCurrent = NULL;
96
            mCurrent = NULL;
96
            return NULL; // finished!!
97
            return NULL; // finished!!
97
        }else {
98
        }else {
98
            mTreeEnd = &((*mRUIterator)->trees().back()) + 1;
99
            mTreeEnd = &((*mRUIterator)->trees().back()) + 1;
99
            mCurrent = &((*mRUIterator)->trees().front());
100
            mCurrent = &((*mRUIterator)->trees().front());
100
        }
101
        }
101
    }
102
    }
102
103
103
    return mCurrent++;
104
    return mCurrent++;
104
}
105
}
105
Tree *AllTreeIterator::nextLiving()
106
Tree *AllTreeIterator::nextLiving()
106
{
107
{
107
    while (Tree *t = next())
108
    while (Tree *t = next())
108
        if (!t->isDead()) return t;
109
        if (!t->isDead()) return t;
109
    return NULL;
110
    return NULL;
110
}
111
}
111
Tree *AllTreeIterator::current() const
112
Tree *AllTreeIterator::current() const
112
{
113
{
113
    return mCurrent?mCurrent-1:NULL;
114
    return mCurrent?mCurrent-1:NULL;
114
}
115
}
115
116
116
117
117
ModelSettings Model::mSettings;
118
ModelSettings Model::mSettings;
118
Model::Model()
119
Model::Model()
119
{
120
{
120
    initialize();
121
    initialize();
121
    GlobalSettings::instance()->setModel(this);
122
    GlobalSettings::instance()->setModel(this);
122
    GlobalSettings::instance()->resetScriptEngine(); // clear the script
123
    GlobalSettings::instance()->resetScriptEngine(); // clear the script
123
    QString dbg="running in release mode.";
124
    QString dbg="running in release mode.";
124
    DBGMODE( dbg="running in debug mode."; );
125
    DBGMODE( dbg="running in debug mode."; );
125
    qDebug() << dbg;
126
    qDebug() << dbg;
126
}
127
}
127
128
128
Model::~Model()
129
Model::~Model()
129
{
130
{
130
    clear();
131
    clear();
131
    GlobalSettings::instance()->setModel(NULL);
132
    GlobalSettings::instance()->setModel(NULL);
132
}
133
}
133
134
134
/** Initial setup of the Model.
135
/** Initial setup of the Model.
135
  */
136
  */
136
void Model::initialize()
137
void Model::initialize()
137
{
138
{
138
   mSetup = false;
139
   mSetup = false;
139
   GlobalSettings::instance()->setCurrentYear(0);
140
   GlobalSettings::instance()->setCurrentYear(0);
140
   mGrid = 0;
141
   mGrid = 0;
141
   mHeightGrid = 0;
142
   mHeightGrid = 0;
142
   mManagement = 0;
143
   mManagement = 0;
143
   mABEManagement = 0;
144
   mABEManagement = 0;
144
   mEnvironment = 0;
145
   mEnvironment = 0;
145
   mTimeEvents = 0;
146
   mTimeEvents = 0;
146
   mStandGrid = 0;
147
   mStandGrid = 0;
147
   mModules = 0;
148
   mModules = 0;
148
   mDEM = 0;
149
   mDEM = 0;
149
   mGrassCover = 0;
150
   mGrassCover = 0;
-
 
151
   mSaplings=0;
150
}
152
}
151
153
152
/** sets up the simulation space.
154
/** sets up the simulation space.
153
*/
155
*/
154
void Model::setupSpace()
156
void Model::setupSpace()
155
{
157
{
156
    XmlHelper xml(GlobalSettings::instance()->settings().node("model.world"));
158
    XmlHelper xml(GlobalSettings::instance()->settings().node("model.world"));
157
    double cellSize = xml.value("cellSize", "2").toDouble();
159
    double cellSize = xml.value("cellSize", "2").toDouble();
158
    double width = xml.value("width", "100").toDouble();
160
    double width = xml.value("width", "100").toDouble();
159
    double height = xml.value("height", "100").toDouble();
161
    double height = xml.value("height", "100").toDouble();
160
    double buffer = xml.value("buffer", "60").toDouble();
162
    double buffer = xml.value("buffer", "60").toDouble();
161
    mModelRect = QRectF(0., 0., width, height);
163
    mModelRect = QRectF(0., 0., width, height);
162
164
163
    qDebug() << QString("setup of the world: %1x%2m with cell-size=%3m and %4m buffer").arg(width).arg(height).arg(cellSize).arg(buffer);
165
    qDebug() << QString("setup of the world: %1x%2m with cell-size=%3m and %4m buffer").arg(width).arg(height).arg(cellSize).arg(buffer);
164
166
165
    QRectF total_grid(QPointF(-buffer, -buffer), QPointF(width+buffer, height+buffer));
167
    QRectF total_grid(QPointF(-buffer, -buffer), QPointF(width+buffer, height+buffer));
166
    qDebug() << "setup grid rectangle:" << total_grid;
168
    qDebug() << "setup grid rectangle:" << total_grid;
167
169
168
    if (mGrid)
170
    if (mGrid)
169
        delete mGrid;
171
        delete mGrid;
170
    mGrid = new FloatGrid(total_grid, cellSize);
172
    mGrid = new FloatGrid(total_grid, cellSize);
171
    mGrid->initialize(1.f);
173
    mGrid->initialize(1.f);
172
    if (mHeightGrid)
174
    if (mHeightGrid)
173
        delete mHeightGrid;
175
        delete mHeightGrid;
174
    mHeightGrid = new HeightGrid(total_grid, cellSize*5);
176
    mHeightGrid = new HeightGrid(total_grid, cellSize*5);
175
    mHeightGrid->wipe(); // set all to zero
177
    mHeightGrid->wipe(); // set all to zero
176
    Tree::setGrid(mGrid, mHeightGrid);
178
    Tree::setGrid(mGrid, mHeightGrid);
177
179
178
    // setup the spatial location of the project area
180
    // setup the spatial location of the project area
179
    if (xml.hasNode("location")) {
181
    if (xml.hasNode("location")) {
180
        // setup of spatial location
182
        // setup of spatial location
181
        double loc_x = xml.valueDouble("location.x");
183
        double loc_x = xml.valueDouble("location.x");
182
        double loc_y = xml.valueDouble("location.y");
184
        double loc_y = xml.valueDouble("location.y");
183
        double loc_z = xml.valueDouble("location.z");
185
        double loc_z = xml.valueDouble("location.z");
184
        double loc_rot = xml.valueDouble("location.rotation");
186
        double loc_rot = xml.valueDouble("location.rotation");
185
        setupGISTransformation(loc_x, loc_y, loc_z, loc_rot);
187
        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;
188
        qDebug() << "setup of spatial location: x/y/z" << loc_x << loc_y << loc_z << "rotation:" << loc_rot;
187
    } else {
189
    } else {
188
        setupGISTransformation(0., 0., 0., 0.);
190
        setupGISTransformation(0., 0., 0., 0.);
189
    }
191
    }
190
192
191
    // load environment (multiple climates, speciesSets, ...
193
    // load environment (multiple climates, speciesSets, ...
192
    if (mEnvironment)
194
    if (mEnvironment)
193
        delete mEnvironment;
195
        delete mEnvironment;
194
    mEnvironment = new Environment();
196
    mEnvironment = new Environment();
195
197
196
    if (xml.valueBool("environmentEnabled", false)) {
198
    if (xml.valueBool("environmentEnabled", false)) {
197
        QString env_file = GlobalSettings::instance()->path(xml.value("environmentFile"));
199
        QString env_file = GlobalSettings::instance()->path(xml.value("environmentFile"));
198
        bool grid_mode = (xml.value("environmentMode")=="grid");
200
        bool grid_mode = (xml.value("environmentMode")=="grid");
199
        QString grid_file = GlobalSettings::instance()->path(xml.value("environmentGrid"));
201
        QString grid_file = GlobalSettings::instance()->path(xml.value("environmentGrid"));
200
        if (grid_mode) {
202
        if (grid_mode) {
201
            if (QFile::exists(grid_file))
203
            if (QFile::exists(grid_file))
202
                mEnvironment->setGridMode(grid_file);
204
                mEnvironment->setGridMode(grid_file);
203
            else
205
            else
204
                throw IException(QString("File '%1' specified in key 'environmentGrid' does not exit ('environmentMode' is 'grid').").arg(grid_file) );
206
                throw IException(QString("File '%1' specified in key 'environmentGrid' does not exit ('environmentMode' is 'grid').").arg(grid_file) );
205
        }
207
        }
206
208
207
        if (!mEnvironment->loadFromFile(env_file))
209
        if (!mEnvironment->loadFromFile(env_file))
208
            return;
210
            return;
209
    } else {
211
    } else {
210
        // load and prepare default values
212
        // load and prepare default values
211
        // (2) SpeciesSets: currently only one a global species set.
213
        // (2) SpeciesSets: currently only one a global species set.
212
        SpeciesSet *speciesSet = new SpeciesSet();
214
        SpeciesSet *speciesSet = new SpeciesSet();
213
        mSpeciesSets.push_back(speciesSet);
215
        mSpeciesSets.push_back(speciesSet);
214
        speciesSet->setup();
216
        speciesSet->setup();
215
        // Climate...
217
        // Climate...
216
        Climate *c = new Climate();
218
        Climate *c = new Climate();
217
        mClimates.push_back(c);
219
        mClimates.push_back(c);
218
        mEnvironment->setDefaultValues(c, speciesSet);
220
        mEnvironment->setDefaultValues(c, speciesSet);
219
    } // environment?
221
    } // environment?
220
222
221
    // time series data
223
    // time series data
222
    if (xml.valueBool(".timeEventsEnabled", false)) {
224
    if (xml.valueBool(".timeEventsEnabled", false)) {
223
        mTimeEvents = new TimeEvents();
225
        mTimeEvents = new TimeEvents();
224
        mTimeEvents->loadFromFile(GlobalSettings::instance()->path(xml.value("timeEventsFile"), "script"));
226
        mTimeEvents->loadFromFile(GlobalSettings::instance()->path(xml.value("timeEventsFile"), "script"));
225
    }
227
    }
226
228
227
229
228
    // simple case: create ressource units in a regular grid.
230
    // simple case: create ressource units in a regular grid.
229
    if (xml.valueBool("resourceUnitsAsGrid")) {
231
    if (xml.valueBool("resourceUnitsAsGrid")) {
230
232
231
        mRUmap.setup(QRectF(0., 0., width, height),100.); // Grid, that holds positions of resource units
233
        mRUmap.setup(QRectF(0., 0., width, height),100.); // Grid, that holds positions of resource units
232
        mRUmap.wipe();
234
        mRUmap.wipe();
233
235
234
        bool mask_is_setup = false;
236
        bool mask_is_setup = false;
235
        if (xml.valueBool("standGrid.enabled")) {
237
        if (xml.valueBool("standGrid.enabled")) {
236
            QString fileName = GlobalSettings::instance()->path(xml.value("standGrid.fileName"));
238
            QString fileName = GlobalSettings::instance()->path(xml.value("standGrid.fileName"));
237
            mStandGrid = new MapGrid(fileName,false); // create stand grid index later
239
            mStandGrid = new MapGrid(fileName,false); // create stand grid index later
238
240
239
            if (mStandGrid->isValid()) {
241
            if (mStandGrid->isValid()) {
240
                for (int i=0;i<mStandGrid->grid().count();i++) {
242
                for (int i=0;i<mStandGrid->grid().count();i++) {
241
                    const int &grid_value = mStandGrid->grid().constValueAtIndex(i);
243
                    const int &grid_value = mStandGrid->grid().constValueAtIndex(i);
242
                    mHeightGrid->valueAtIndex(i).setValid( grid_value > -1 );
244
                    mHeightGrid->valueAtIndex(i).setValid( grid_value > -1 );
243
                    if (grid_value>-1)
245
                    if (grid_value>-1)
244
                        mRUmap.valueAt(mStandGrid->grid().cellCenterPoint(i)) = (ResourceUnit*)1;
246
                        mRUmap.valueAt(mStandGrid->grid().cellCenterPoint(i)) = (ResourceUnit*)1;
245
                    if (grid_value < -1)
247
                    if (grid_value < -1)
246
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
248
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
247
                }
249
                }
248
            }
250
            }
249
            mask_is_setup = true;
251
            mask_is_setup = true;
250
        } else {
252
        } else {
251
            if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
253
            if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
252
                // in the case we have no stand grid but only a large rectangle (without the torus option)
254
                // in the case we have no stand grid but only a large rectangle (without the torus option)
253
                // we assume a forest outside
255
                // we assume a forest outside
254
                for (int i=0;i<mHeightGrid->count();++i) {
256
                for (int i=0;i<mHeightGrid->count();++i) {
255
                    const QPointF &p = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
257
                    const QPointF &p = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
256
                    if (p.x() < 0. || p.x()>width || p.y()<0. || p.y()>height) {
258
                    if (p.x() < 0. || p.x()>width || p.y()<0. || p.y()>height) {
257
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
259
                        mHeightGrid->valueAtIndex(i).setForestOutside(true);
258
                        mHeightGrid->valueAtIndex(i).setValid(false);
260
                        mHeightGrid->valueAtIndex(i).setValid(false);
259
                    }
261
                    }
260
                }
262
                }
261
263
262
            }
264
            }
263
        }
265
        }
264
266
265
        ResourceUnit **p; // ptr to ptr!
267
        ResourceUnit **p; // ptr to ptr!
266
        ResourceUnit *new_ru;
268
        ResourceUnit *new_ru;
267
269
268
        int ru_index = 0;
270
        int ru_index = 0;
269
        for (p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
271
        for (p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
270
            QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
272
            QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
271
            if (!mStandGrid || !mStandGrid->isValid() || *p>NULL) {
273
            if (!mStandGrid || !mStandGrid->isValid() || *p>NULL) {
272
                mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
274
                mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
273
                // create resource units for valid positions only
275
                // create resource units for valid positions only
274
                new_ru = new ResourceUnit(ru_index++); // create resource unit
276
                new_ru = new ResourceUnit(ru_index++); // create resource unit
275
                new_ru->setClimate( mEnvironment->climate() );
277
                new_ru->setClimate( mEnvironment->climate() );
276
                new_ru->setSpeciesSet( mEnvironment->speciesSet() );
278
                new_ru->setSpeciesSet( mEnvironment->speciesSet() );
277
                new_ru->setup();
279
                new_ru->setup();
278
                new_ru->setID( mEnvironment->currentID() ); // set id of resource unit in grid mode
280
                new_ru->setID( mEnvironment->currentID() ); // set id of resource unit in grid mode
279
                new_ru->setBoundingBox(r);
281
                new_ru->setBoundingBox(r);
280
                mRU.append(new_ru);
282
                mRU.append(new_ru);
281
                *p = new_ru; // save in the RUmap grid
283
                *p = new_ru; // save in the RUmap grid
282
            }
284
            }
283
        }
285
        }
284
        if (mEnvironment) {
286
        if (mEnvironment) {
285
            // retrieve species sets and climates (that were really used)
287
            // retrieve species sets and climates (that were really used)
286
            mSpeciesSets << mEnvironment->speciesSetList();
288
            mSpeciesSets << mEnvironment->speciesSetList();
287
            mClimates << mEnvironment->climateList();
289
            mClimates << mEnvironment->climateList();
288
            QString climate_file_list;
290
            QString climate_file_list;
289
            for (int i=0, c=0;i<mClimates.count();++i) {
291
            for (int i=0, c=0;i<mClimates.count();++i) {
290
                climate_file_list += mClimates[i]->name() + ", ";
292
                climate_file_list += mClimates[i]->name() + ", ";
291
                if (++c>5) {
293
                if (++c>5) {
292
                    climate_file_list += "...";
294
                    climate_file_list += "...";
293
                    break;
295
                    break;
294
                }
296
                }
295
297
296
            }
298
            }
297
            qDebug() << "Setup of climates: #loaded:" << mClimates.count() << "tables:" << climate_file_list;
299
            qDebug() << "Setup of climates: #loaded:" << mClimates.count() << "tables:" << climate_file_list;
298
300
299
301
300
        }
302
        }
301
303
302
        qDebug() << "setup of" << mEnvironment->climateList().size() << "climates performed.";
304
        qDebug() << "setup of" << mEnvironment->climateList().size() << "climates performed.";
303
305
304
        if (mStandGrid && mStandGrid->isValid())
306
        if (mStandGrid && mStandGrid->isValid())
305
            mStandGrid->createIndex();
307
            mStandGrid->createIndex();
306
        // now store the pointers in the grid.
308
        // now store the pointers in the grid.
307
        // Important: This has to be done after the mRU-QList is complete - otherwise pointers would
309
        // 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)
310
        // point to invalid memory when QList's memory is reorganized (expanding)
309
//        ru_index = 0;
311
//        ru_index = 0;
310
//        for (p=mRUmap.begin();p!=mRUmap.end(); ++p) {
312
//        for (p=mRUmap.begin();p!=mRUmap.end(); ++p) {
311
//            *p = mRU.value(ru_index++);
313
//            *p = mRU.value(ru_index++);
312
//        }
314
//        }
313
        qDebug() << "created a grid of ResourceUnits: count=" << mRU.count() << "number of RU-map-cells:" << mRUmap.count();
315
        qDebug() << "created a grid of ResourceUnits: count=" << mRU.count() << "number of RU-map-cells:" << mRUmap.count();
314
316
315
317
316
        calculateStockableArea();
318
        calculateStockableArea();
317
319
318
        // setup of the project area mask
320
        // setup of the project area mask
319
        if (!mask_is_setup && xml.valueBool("areaMask.enabled", false) && xml.hasNode("areaMask.imageFile")) {
321
        if (!mask_is_setup && xml.valueBool("areaMask.enabled", false) && xml.hasNode("areaMask.imageFile")) {
320
            // to be extended!!! e.g. to load ESRI-style text files....
322
            // to be extended!!! e.g. to load ESRI-style text files....
321
            // setup a grid with the same size as the height grid...
323
            // setup a grid with the same size as the height grid...
322
            FloatGrid tempgrid((int)mHeightGrid->cellsize(), mHeightGrid->sizeX(), mHeightGrid->sizeY());
324
            FloatGrid tempgrid((int)mHeightGrid->cellsize(), mHeightGrid->sizeX(), mHeightGrid->sizeY());
323
            QString fileName = GlobalSettings::instance()->path(xml.value("areaMask.imageFile"));
325
            QString fileName = GlobalSettings::instance()->path(xml.value("areaMask.imageFile"));
324
            loadGridFromImage(fileName, tempgrid); // fetch from image
326
            loadGridFromImage(fileName, tempgrid); // fetch from image
325
            for (int i=0;i<tempgrid.count(); i++)
327
            for (int i=0;i<tempgrid.count(); i++)
326
                mHeightGrid->valueAtIndex(i).setValid( tempgrid.valueAtIndex(i)>0.99 );
328
                mHeightGrid->valueAtIndex(i).setValid( tempgrid.valueAtIndex(i)>0.99 );
327
            qDebug() << "loaded project area mask from" << fileName;
329
            qDebug() << "loaded project area mask from" << fileName;
328
        }
330
        }
329
331
330
        // list of "valid" resource units
332
        // list of "valid" resource units
331
        QList<ResourceUnit*> valid_rus;
333
        QList<ResourceUnit*> valid_rus;
332
        foreach(ResourceUnit* ru, mRU)
334
        foreach(ResourceUnit* ru, mRU)
333
            if (ru->id()!=-1)
335
            if (ru->id()!=-1)
334
                valid_rus.append(ru);
336
                valid_rus.append(ru);
335
337
336
        // setup of the digital elevation map (if present)
338
        // setup of the digital elevation map (if present)
337
        QString dem_file = xml.value("DEM");
339
        QString dem_file = xml.value("DEM");
338
        if (!dem_file.isEmpty()) {
340
        if (!dem_file.isEmpty()) {
339
            mDEM = new DEM(GlobalSettings::instance()->path(dem_file));
341
            mDEM = new DEM(GlobalSettings::instance()->path(dem_file));
340
            // add them to the visuals...
342
            // add them to the visuals...
341
            GlobalSettings::instance()->controller()->addGrid(mDEM, "DEM height", GridViewRainbow, 0, 1000);
343
            GlobalSettings::instance()->controller()->addGrid(mDEM, "DEM height", GridViewRainbow, 0, 1000);
342
            GlobalSettings::instance()->controller()->addGrid(mDEM->slopeGrid(), "DEM slope", GridViewRainbow, 0, 3);
344
            GlobalSettings::instance()->controller()->addGrid(mDEM->slopeGrid(), "DEM slope", GridViewRainbow, 0, 3);
343
            GlobalSettings::instance()->controller()->addGrid(mDEM->aspectGrid(), "DEM aspect", GridViewRainbow, 0, 360);
345
            GlobalSettings::instance()->controller()->addGrid(mDEM->aspectGrid(), "DEM aspect", GridViewRainbow, 0, 360);
344
            GlobalSettings::instance()->controller()->addGrid(mDEM->viewGrid(), "DEM view", GridViewGray, 0, 1);
346
            GlobalSettings::instance()->controller()->addGrid(mDEM->viewGrid(), "DEM view", GridViewGray, 0, 1);
345
347
346
        }
348
        }
-
 
349
-
 
350
        // setup of saplings
-
 
351
        if (mSaplings) {
-
 
352
            delete mSaplings; mSaplings=0;
-
 
353
        }
-
 
354
        if (settings().regenerationEnabled) {
-
 
355
            mSaplings = new Saplings();
-
 
356
            mSaplings->setup();
-
 
357
        }
-
 
358
347
359
348
        // setup of the grass cover
360
        // setup of the grass cover
349
        if (!mGrassCover)
361
        if (!mGrassCover)
350
            mGrassCover = new GrassCover();
362
            mGrassCover = new GrassCover();
351
        mGrassCover->setup();
363
        mGrassCover->setup();
352
364
353
        // setup of external modules
365
        // setup of external modules
354
        mModules->setup();
366
        mModules->setup();
355
        if (mModules->hasSetupResourceUnits()) {
367
        if (mModules->hasSetupResourceUnits()) {
356
            for (ResourceUnit **p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
368
            for (ResourceUnit **p=mRUmap.begin(); p!=mRUmap.end(); ++p) {
357
                if (*p) {
369
                if (*p) {
358
                    QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
370
                    QRectF r = mRUmap.cellRect(mRUmap.indexOf(p));
359
                    mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
371
                    mEnvironment->setPosition( r.center() ); // if environment is 'disabled' default values from the project file are used.
360
                    mModules->setupResourceUnit( *p );
372
                    mModules->setupResourceUnit( *p );
361
                }
373
                }
362
            }
374
            }
363
        }
375
        }
364
376
365
        // setup of scripting environment
377
        // setup of scripting environment
366
        ScriptGlobal::setupGlobalScripting();
378
        ScriptGlobal::setupGlobalScripting();
367
379
368
        // setup the helper that does the multithreading
380
        // setup the helper that does the multithreading
369
        threadRunner.setup(valid_rus);
381
        threadRunner.setup(valid_rus);
370
        threadRunner.setMultithreading(GlobalSettings::instance()->settings().valueBool("system.settings.multithreading"));
382
        threadRunner.setMultithreading(GlobalSettings::instance()->settings().valueBool("system.settings.multithreading"));
371
        threadRunner.print();
383
        threadRunner.print();
372
384
373
385
374
    } else  {
386
    } else  {
375
        throw IException("resourceUnitsAsGrid MUST be set to true - at least currently :)");
387
        throw IException("resourceUnitsAsGrid MUST be set to true - at least currently :)");
376
    }
388
    }
377
    mSetup = true;
389
    mSetup = true;
378
}
390
}
379
391
380
392
381
/** clear() frees all ressources allocated with the run of a simulation.
393
/** clear() frees all ressources allocated with the run of a simulation.
382

394

383
  */
395
  */
384
void Model::clear()
396
void Model::clear()
385
{
397
{
386
    mSetup = false;
398
    mSetup = false;
387
    qDebug() << "Model clear: attempting to clear" << mRU.count() << "RU, " << mSpeciesSets.count() << "SpeciesSets.";
399
    qDebug() << "Model clear: attempting to clear" << mRU.count() << "RU, " << mSpeciesSets.count() << "SpeciesSets.";
388
    // clear ressource units
400
    // clear ressource units
389
    qDeleteAll(mRU); // delete ressource units (and trees)
401
    qDeleteAll(mRU); // delete ressource units (and trees)
390
    mRU.clear();
402
    mRU.clear();
391
403
392
    qDeleteAll(mSpeciesSets); // delete species sets
404
    qDeleteAll(mSpeciesSets); // delete species sets
393
    mSpeciesSets.clear();
405
    mSpeciesSets.clear();
394
406
395
    // delete climate data
407
    // delete climate data
396
    qDeleteAll(mClimates);
408
    qDeleteAll(mClimates);
397
409
398
    // delete the grids
410
    // delete the grids
399
    if (mGrid)
411
    if (mGrid)
400
        delete mGrid;
412
        delete mGrid;
401
    if (mHeightGrid)
413
    if (mHeightGrid)
402
        delete mHeightGrid;
414
        delete mHeightGrid;
-
 
415
    if (mSaplings)
-
 
416
        delete mSaplings;
403
    if (mManagement)
417
    if (mManagement)
404
        delete mManagement;
418
        delete mManagement;
405
    if (mEnvironment)
419
    if (mEnvironment)
406
        delete mEnvironment;
420
        delete mEnvironment;
407
    if (mTimeEvents)
421
    if (mTimeEvents)
408
        delete mTimeEvents;
422
        delete mTimeEvents;
409
    if (mStandGrid)
423
    if (mStandGrid)
410
        delete mStandGrid;
424
        delete mStandGrid;
411
    if (mModules)
425
    if (mModules)
412
        delete mModules;
426
        delete mModules;
413
    if (mDEM)
427
    if (mDEM)
414
        delete mDEM;
428
        delete mDEM;
415
    if (mGrassCover)
429
    if (mGrassCover)
416
        delete mGrassCover;
430
        delete mGrassCover;
417
    if (mABEManagement)
431
    if (mABEManagement)
418
        delete mABEManagement;
432
        delete mABEManagement;
419
433
420
    mGrid = 0;
434
    mGrid = 0;
421
    mHeightGrid = 0;
435
    mHeightGrid = 0;
422
    mManagement = 0;
436
    mManagement = 0;
423
    mEnvironment = 0;
437
    mEnvironment = 0;
424
    mTimeEvents = 0;
438
    mTimeEvents = 0;
425
    mStandGrid  = 0;
439
    mStandGrid  = 0;
426
    mModules = 0;
440
    mModules = 0;
427
    mDEM = 0;
441
    mDEM = 0;
428
    mGrassCover = 0;
442
    mGrassCover = 0;
429
    mABEManagement = 0;
443
    mABEManagement = 0;
430
444
431
    GlobalSettings::instance()->outputManager()->close();
445
    GlobalSettings::instance()->outputManager()->close();
432
446
433
    qDebug() << "Model ressources freed.";
447
    qDebug() << "Model ressources freed.";
434
}
448
}
435
449
436
/** Setup of the Simulation.
450
/** Setup of the Simulation.
437
  This really creates the simulation environment and does the setup of various aspects.
451
  This really creates the simulation environment and does the setup of various aspects.
438
  */
452
  */
439
void Model::loadProject()
453
void Model::loadProject()
440
{
454
{
441
    DebugTimer dt("load project");
455
    DebugTimer dt("load project");
442
    GlobalSettings *g = GlobalSettings::instance();
456
    GlobalSettings *g = GlobalSettings::instance();
443
    g->printDirecories();
457
    g->printDirecories();
444
    const XmlHelper &xml = g->settings();
458
    const XmlHelper &xml = g->settings();
445
459
446
    g->clearDatabaseConnections();
460
    g->clearDatabaseConnections();
447
    // database connections: reset
461
    // database connections: reset
448
    GlobalSettings::instance()->clearDatabaseConnections();
462
    GlobalSettings::instance()->clearDatabaseConnections();
449
    // input and climate connection
463
    // input and climate connection
450
    // see initOutputDatabase() for output database
464
    // see initOutputDatabase() for output database
451
    QString dbPath = g->path( xml.value("system.database.in"), "database");
465
    QString dbPath = g->path( xml.value("system.database.in"), "database");
452
    GlobalSettings::instance()->setupDatabaseConnection("in", dbPath, true);
466
    GlobalSettings::instance()->setupDatabaseConnection("in", dbPath, true);
453
    dbPath = g->path( xml.value("system.database.climate"), "database");
467
    dbPath = g->path( xml.value("system.database.climate"), "database");
454
    GlobalSettings::instance()->setupDatabaseConnection("climate", dbPath, true);
468
    GlobalSettings::instance()->setupDatabaseConnection("climate", dbPath, true);
455
469
456
    mSettings.loadModelSettings();
470
    mSettings.loadModelSettings();
457
    mSettings.print();
471
    mSettings.print();
458
    // random seed: if stored value is <> 0, use this as the random seed (and produce hence always an equal sequence of random numbers)
472
    // 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();
473
    uint seed = xml.value("system.settings.randomSeed","0").toUInt();
460
    RandomGenerator::setup(RandomGenerator::ergMersenneTwister, seed); // use the MersenneTwister as default
474
    RandomGenerator::setup(RandomGenerator::ergMersenneTwister, seed); // use the MersenneTwister as default
461
    // linearization of expressions: if true *and* linearize() is explicitely called, then
475
    // linearization of expressions: if true *and* linearize() is explicitely called, then
462
    // function results will be cached over a defined range of values.
476
    // function results will be cached over a defined range of values.
463
    bool do_linearization = xml.valueBool("system.settings.expressionLinearizationEnabled", false);
477
    bool do_linearization = xml.valueBool("system.settings.expressionLinearizationEnabled", false);
464
    Expression::setLinearizationEnabled(do_linearization);
478
    Expression::setLinearizationEnabled(do_linearization);
465
    if (do_linearization)
479
    if (do_linearization)
466
        qDebug() << "The linearization of certains expressions is enabled (performance optimization).";
480
        qDebug() << "The linearization of certains expressions is enabled (performance optimization).";
467
481
468
    // log level
482
    // log level
469
    QString log_level = xml.value("system.settings.logLevel", "debug").toLower();
483
    QString log_level = xml.value("system.settings.logLevel", "debug").toLower();
470
    if (log_level=="debug") setLogLevel(0);
484
    if (log_level=="debug") setLogLevel(0);
471
    if (log_level=="info") setLogLevel(1);
485
    if (log_level=="info") setLogLevel(1);
472
    if (log_level=="warning") setLogLevel(2);
486
    if (log_level=="warning") setLogLevel(2);
473
    if (log_level=="error") setLogLevel(3);
487
    if (log_level=="error") setLogLevel(3);
474
488
475
    // snag dynamics / soil model enabled? (info used during setup of world)
489
    // snag dynamics / soil model enabled? (info used during setup of world)
476
    changeSettings().carbonCycleEnabled = xml.valueBool("model.settings.carbonCycleEnabled", false);
490
    changeSettings().carbonCycleEnabled = xml.valueBool("model.settings.carbonCycleEnabled", false);
477
    // class size of snag classes
491
    // class size of snag classes
478
    Snag::setupThresholds(xml.valueDouble("model.settings.soil.swdDBHClass12"),
492
    Snag::setupThresholds(xml.valueDouble("model.settings.soil.swdDBHClass12"),
479
                          xml.valueDouble("model.settings.soil.swdDBHClass23"));
493
                          xml.valueDouble("model.settings.soil.swdDBHClass23"));
480
494
481
    // setup of modules
495
    // setup of modules
482
    if (mModules)
496
    if (mModules)
483
        delete mModules;
497
        delete mModules;
484
    mModules = new Modules();
498
    mModules = new Modules();
-
 
499
-
 
500
    changeSettings().regenerationEnabled = xml.valueBool("model.settings.regenerationEnabled", false);
-
 
501
485
502
486
    setupSpace();
503
    setupSpace();
487
    if (mRU.isEmpty())
504
    if (mRU.isEmpty())
488
        throw IException("Setup of Model: no resource units present!");
505
        throw IException("Setup of Model: no resource units present!");
489
506
490
    // (3) additional issues
507
    // (3) additional issues
491
    // (3.1) load javascript code into the engine
508
    // (3.1) load javascript code into the engine
492
    QString script_file = xml.value("system.javascript.fileName");
509
    QString script_file = xml.value("system.javascript.fileName");
493
    if (!script_file.isEmpty()) {
510
    if (!script_file.isEmpty()) {
494
        script_file = g->path(script_file, "script");
511
        script_file = g->path(script_file, "script");
495
        ScriptGlobal::loadScript(script_file);
512
        ScriptGlobal::loadScript(script_file);
496
        g->controller()->setLoadedJavascriptFile(script_file);
513
        g->controller()->setLoadedJavascriptFile(script_file);
497
    }
514
    }
498
515
499
    // (3.2) setup of regeneration
516
    // (3.2) setup of regeneration
500
    changeSettings().regenerationEnabled = xml.valueBool("model.settings.regenerationEnabled", false);
-
 
501
    if (settings().regenerationEnabled) {
517
    if (settings().regenerationEnabled) {
502
        foreach(SpeciesSet *ss, mSpeciesSets)
518
        foreach(SpeciesSet *ss, mSpeciesSets)
503
            ss->setupRegeneration();
519
            ss->setupRegeneration();
504
    }
520
    }
505
    Sapling::setRecruitmentVariation(xml.valueDouble("model.settings.seedDispersal.recruitmentDimensionVariation",0.1));
521
    Sapling::setRecruitmentVariation(xml.valueDouble("model.settings.seedDispersal.recruitmentDimensionVariation",0.1));
506
522
507
    // (3.3) management
523
    // (3.3) management
508
    bool use_abe = xml.valueBool("model.management.abeEnabled");
524
    bool use_abe = xml.valueBool("model.management.abeEnabled");
509
    if (use_abe) {
525
    if (use_abe) {
510
        // use the agent based forest management engine
526
        // use the agent based forest management engine
511
        mABEManagement = new ABE::ForestManagementEngine();
527
        mABEManagement = new ABE::ForestManagementEngine();
512
        // setup of ABE after loading of trees.
528
        // setup of ABE after loading of trees.
513
529
514
    }
530
    }
515
    // use the standard management
531
    // use the standard management
516
    QString mgmtFile = xml.value("model.management.file");
532
    QString mgmtFile = xml.value("model.management.file");
517
    if (!mgmtFile.isEmpty() && xml.valueBool("model.management.enabled")) {
533
    if (!mgmtFile.isEmpty() && xml.valueBool("model.management.enabled")) {
518
        mManagement = new Management();
534
        mManagement = new Management();
519
        QString path = GlobalSettings::instance()->path(mgmtFile, "script");
535
        QString path = GlobalSettings::instance()->path(mgmtFile, "script");
520
        mManagement->loadScript(path);
536
        mManagement->loadScript(path);
521
        qDebug() << "setup management using script" << path;
537
        qDebug() << "setup management using script" << path;
522
    }
538
    }
523
539
524
540
525
541
526
}
542
}
527
543
528
void Model::reloadABE()
544
void Model::reloadABE()
529
{
545
{
530
    // delete firest
546
    // delete firest
531
    if (mABEManagement)
547
    if (mABEManagement)
532
        delete mABEManagement;
548
        delete mABEManagement;
533
    mABEManagement = new ABE::ForestManagementEngine();
549
    mABEManagement = new ABE::ForestManagementEngine();
534
    // and setup
550
    // and setup
535
    mABEManagement->setup();
551
    mABEManagement->setup();
536
    mABEManagement->runOnInit(true);
552
    mABEManagement->runOnInit(true);
537
553
538
    mABEManagement->initialize();
554
    mABEManagement->initialize();
539
555
540
    mABEManagement->runOnInit(false);
556
    mABEManagement->runOnInit(false);
541
557
542
}
558
}
543
559
544
560
545
ResourceUnit *Model::ru(QPointF coord)
561
ResourceUnit *Model::ru(QPointF coord)
546
{
562
{
547
    if (!mRUmap.isEmpty() && mRUmap.coordValid(coord))
563
    if (!mRUmap.isEmpty() && mRUmap.coordValid(coord))
548
        return mRUmap.valueAt(coord);
564
        return mRUmap.valueAt(coord);
549
    return ru(); // default RU if there is only one
565
    return ru(); // default RU if there is only one
550
}
566
}
551
567
552
void Model::initOutputDatabase()
568
void Model::initOutputDatabase()
553
{
569
{
554
    GlobalSettings *g = GlobalSettings::instance();
570
    GlobalSettings *g = GlobalSettings::instance();
555
    QString dbPath = g->path(g->settings().value("system.database.out"), "output");
571
    QString dbPath = g->path(g->settings().value("system.database.out"), "output");
556
    // create run-metadata
572
    // create run-metadata
557
    int maxid = SqlHelper::queryValue("select max(id) from runs", g->dbin()).toInt();
573
    int maxid = SqlHelper::queryValue("select max(id) from runs", g->dbin()).toInt();
558
574
559
    maxid++;
575
    maxid++;
560
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
576
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
561
    SqlHelper::executeSql(QString("insert into runs (id, timestamp) values (%1, '%2')").arg(maxid).arg(timestamp), g->dbin());
577
    SqlHelper::executeSql(QString("insert into runs (id, timestamp) values (%1, '%2')").arg(maxid).arg(timestamp), g->dbin());
562
    // replace path information
578
    // replace path information
563
    dbPath.replace("$id$", QString::number(maxid));
579
    dbPath.replace("$id$", QString::number(maxid));
564
    dbPath.replace("$date$", timestamp);
580
    dbPath.replace("$date$", timestamp);
565
    // setup final path
581
    // setup final path
566
   g->setupDatabaseConnection("out", dbPath, false);
582
   g->setupDatabaseConnection("out", dbPath, false);
567
583
568
}
584
}
569
585
570
586
571
/// multithreaded running function for the resource unit level establishment
587
/// multithreaded running function for the resource unit level establishment
572
ResourceUnit *nc_sapling_growth_establishment(ResourceUnit *unit)
588
ResourceUnit *nc_sapling_growth_establishment(ResourceUnit *unit)
573
{
589
{
574
    try {
590
    try {
575
        { // DebugTimer t("nc_saplingGrowth"); t.setSilent();
591
        { // DebugTimer t("nc_saplingGrowth"); t.setSilent();
576
        // define a height map for the current resource unit on the stack
592
        // define a height map for the current resource unit on the stack
577
        float sapling_map[cPxPerRU*cPxPerRU];
593
        float sapling_map[cPxPerRU*cPxPerRU];
578
        // set the map and initialize it:
594
        // set the map and initialize it:
579
        unit->setSaplingHeightMap(sapling_map);
595
        unit->setSaplingHeightMap(sapling_map);
580
596
581
597
582
        // (1) calculate the growth of (already established) saplings (populate sapling map)
598
        // (1) calculate the growth of (already established) saplings (populate sapling map)
583
        QList<ResourceUnitSpecies*>::const_iterator rus;
599
        QList<ResourceUnitSpecies*>::const_iterator rus;
584
        for (rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
600
        for (rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
585
            (*rus)->calclulateSaplingGrowth();
601
            (*rus)->calclulateSaplingGrowth();
586
602
587
        } { // DebugTimer t("nc_Establishment"); t.setSilent();
603
        } { // DebugTimer t("nc_Establishment"); t.setSilent();
588
604
589
        // (2) calculate the establishment probabilities of new saplings
605
        // (2) calculate the establishment probabilities of new saplings
590
        for (QList<ResourceUnitSpecies*>::const_iterator rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
606
        for (QList<ResourceUnitSpecies*>::const_iterator rus=unit->ruSpecies().cbegin(); rus!=unit->ruSpecies().cend(); ++rus)
591
            (*rus)->calculateEstablishment();
607
            (*rus)->calculateEstablishment();
592
608
593
        }
609
        }
594
610
595
    } catch (const IException& e) {
611
    } catch (const IException& e) {
596
        GlobalSettings::instance()->controller()->throwError(e.message());
612
        GlobalSettings::instance()->controller()->throwError(e.message());
597
    }
613
    }
598
614
599
    unit->setSaplingHeightMap(0); // invalidate again
615
    unit->setSaplingHeightMap(0); // invalidate again
600
    return unit;
616
    return unit;
601
617
602
}
618
}
603
619
604
620
605
/// multithreaded execution of the carbon cycle routine
621
/// multithreaded execution of the carbon cycle routine
606
ResourceUnit *nc_carbonCycle(ResourceUnit *unit)
622
ResourceUnit *nc_carbonCycle(ResourceUnit *unit)
607
{
623
{
608
    try {
624
    try {
609
        // (1) do calculations on snag dynamics for the resource unit
625
        // (1) do calculations on snag dynamics for the resource unit
610
        unit->calculateCarbonCycle();
626
        unit->calculateCarbonCycle();
611
        // (2) do the soil carbon and nitrogen dynamics calculations (ICBM/2N)
627
        // (2) do the soil carbon and nitrogen dynamics calculations (ICBM/2N)
612
    } catch (const IException& e) {
628
    } catch (const IException& e) {
613
        GlobalSettings::instance()->controller()->throwError(e.message());
629
        GlobalSettings::instance()->controller()->throwError(e.message());
614
    }
630
    }
615
631
616
    return unit;
632
    return unit;
617
}
633
}
618
634
619
/// beforeRun performs several steps before the models starts running.
635
/// beforeRun performs several steps before the models starts running.
620
/// inter alia: * setup of the stands
636
/// inter alia: * setup of the stands
621
///             * setup of the climates
637
///             * setup of the climates
622
void Model::beforeRun()
638
void Model::beforeRun()
623
{
639
{
624
    // setup outputs
640
    // setup outputs
625
    // setup output database
641
    // setup output database
626
    if (GlobalSettings::instance()->dbout().isOpen())
642
    if (GlobalSettings::instance()->dbout().isOpen())
627
        GlobalSettings::instance()->dbout().close();
643
        GlobalSettings::instance()->dbout().close();
628
    initOutputDatabase();
644
    initOutputDatabase();
629
    GlobalSettings::instance()->outputManager()->setup();
645
    GlobalSettings::instance()->outputManager()->setup();
630
    GlobalSettings::instance()->clearDebugLists();
646
    GlobalSettings::instance()->clearDebugLists();
631
647
632
    // initialize stands
648
    // initialize stands
633
    StandLoader loader(this);
649
    StandLoader loader(this);
634
    {
650
    {
635
    DebugTimer loadtrees("load trees");
651
    DebugTimer loadtrees("load trees");
636
    loader.processInit();
652
    loader.processInit();
637
    }
653
    }
638
    // initalization of ABE
654
    // initalization of ABE
639
    if (mABEManagement) {
655
    if (mABEManagement) {
640
        mABEManagement->setup();
656
        mABEManagement->setup();
641
        mABEManagement->runOnInit(true);
657
        mABEManagement->runOnInit(true);
642
    }
658
    }
643
659
644
    // load climate
660
    // load climate
645
    {
661
    {
646
        if (logLevelDebug()) qDebug() << "attempting to load climate..." ;
662
        if (logLevelDebug()) qDebug() << "attempting to load climate..." ;
647
        DebugTimer loadclim("load climate");
663
        DebugTimer loadclim("load climate");
648
        foreach(Climate *c, mClimates) {
664
        foreach(Climate *c, mClimates) {
649
            if (!c->isSetup())
665
            if (!c->isSetup())
650
                c->setup();
666
                c->setup();
651
        }
667
        }
652
        // load the first year of the climate database
668
        // load the first year of the climate database
653
        foreach(Climate *c, mClimates)
669
        foreach(Climate *c, mClimates)
654
            c->nextYear();
670
            c->nextYear();
655
671
656
    }
672
    }
657
673
658
674
659
    { DebugTimer loadinit("load standstatistics");
675
    { DebugTimer loadinit("load standstatistics");
660
    if (logLevelDebug()) qDebug() << "attempting to calculate initial stand statistics (incl. apply and read pattern)..." ;
676
    if (logLevelDebug()) qDebug() << "attempting to calculate initial stand statistics (incl. apply and read pattern)..." ;
661
    Tree::setGrid(mGrid, mHeightGrid);
677
    Tree::setGrid(mGrid, mHeightGrid);
662
    // debugCheckAllTrees(); // introduced for debugging session (2012-04-06)
678
    // debugCheckAllTrees(); // introduced for debugging session (2012-04-06)
663
    applyPattern();
679
    applyPattern();
664
    readPattern();
680
    readPattern();
665
    loader.processAfterInit(); // e.g. initialization of saplings
681
    loader.processAfterInit(); // e.g. initialization of saplings
666
682
667
    // force the compilation of initial stand statistics
683
    // force the compilation of initial stand statistics
668
    createStandStatistics();
684
    createStandStatistics();
669
    }
685
    }
670
686
671
    // initalization of ABE (now all stands are properly set up)
687
    // initalization of ABE (now all stands are properly set up)
672
    if (mABEManagement) {
688
    if (mABEManagement) {
673
        mABEManagement->initialize();
689
        mABEManagement->initialize();
674
        mABEManagement->runOnInit(false);
690
        mABEManagement->runOnInit(false);
675
    }
691
    }
676
692
677
693
678
    // outputs to create with inital state (without any growth) are called here:
694
    // outputs to create with inital state (without any growth) are called here:
679
    GlobalSettings::instance()->setCurrentYear(0); // set clock to "0" (for outputs with initial state)
695
    GlobalSettings::instance()->setCurrentYear(0); // set clock to "0" (for outputs with initial state)
680
696
681
    GlobalSettings::instance()->outputManager()->execute("stand"); // year=0
697
    GlobalSettings::instance()->outputManager()->execute("stand"); // year=0
682
    GlobalSettings::instance()->outputManager()->execute("landscape"); // year=0
698
    GlobalSettings::instance()->outputManager()->execute("landscape"); // year=0
683
    GlobalSettings::instance()->outputManager()->execute("sapling"); // year=0
699
    GlobalSettings::instance()->outputManager()->execute("sapling"); // year=0
684
    GlobalSettings::instance()->outputManager()->execute("tree"); // year=0
700
    GlobalSettings::instance()->outputManager()->execute("tree"); // year=0
685
    GlobalSettings::instance()->outputManager()->execute("dynamicstand"); // year=0
701
    GlobalSettings::instance()->outputManager()->execute("dynamicstand"); // year=0
686
702
687
    GlobalSettings::instance()->setCurrentYear(1); // set to first year
703
    GlobalSettings::instance()->setCurrentYear(1); // set to first year
688
704
689
}
705
}
690
706
691
/** Main model runner.
707
/** Main model runner.
692
  The sequence of actions is as follows:
708
  The sequence of actions is as follows:
693
  (1) Load the climate of the new year
709
  (1) Load the climate of the new year
694
  (2) Reset statistics for resource unit as well as for dead/managed trees
710
  (2) Reset statistics for resource unit as well as for dead/managed trees
695
  (3) Invoke Management.
711
  (3) Invoke Management.
696
  (4) *after* that, calculate Light patterns
712
  (4) *after* that, calculate Light patterns
697
  (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)
713
  (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)
698
  (6) execute Regeneration
714
  (6) execute Regeneration
699
  (7) invoke disturbance modules
715
  (7) invoke disturbance modules
700
  (8) calculate statistics for the year
716
  (8) calculate statistics for the year
701
  (9) write database outputs
717
  (9) write database outputs
702
  */
718
  */
703
void Model::runYear()
719
void Model::runYear()
704
{
720
{
705
    DebugTimer t("Model::runYear()");
721
    DebugTimer t("Model::runYear()");
706
    GlobalSettings::instance()->systemStatistics()->reset();
722
    GlobalSettings::instance()->systemStatistics()->reset();
707
    RandomGenerator::checkGenerator(); // see if we need to generate new numbers...
723
    RandomGenerator::checkGenerator(); // see if we need to generate new numbers...
708
    // initalization at start of year for external modules
724
    // initalization at start of year for external modules
709
    mModules->yearBegin();
725
    mModules->yearBegin();
710
726
711
    // execute scheduled events for the current year
727
    // execute scheduled events for the current year
712
    if (mTimeEvents)
728
    if (mTimeEvents)
713
        mTimeEvents->run();
729
        mTimeEvents->run();
714
730
715
    // load the next year of the climate database (except for the first year - the first climate year is loaded immediately
731
    // load the next year of the climate database (except for the first year - the first climate year is loaded immediately
716
    if (GlobalSettings::instance()->currentYear()>1) {
732
    if (GlobalSettings::instance()->currentYear()>1) {
717
        foreach(Climate *c, mClimates)
733
        foreach(Climate *c, mClimates)
718
            c->nextYear();
734
            c->nextYear();
719
    }
735
    }
720
736
721
    // reset statistics
737
    // reset statistics
722
    foreach(ResourceUnit *ru, mRU)
738
    foreach(ResourceUnit *ru, mRU)
723
        ru->newYear();
739
        ru->newYear();
724
740
725
    foreach(SpeciesSet *set, mSpeciesSets)
741
    foreach(SpeciesSet *set, mSpeciesSets)
726
        set->newYear();
742
        set->newYear();
727
    // management classic
743
    // management classic
728
    if (mManagement) {
744
    if (mManagement) {
729
        DebugTimer t("management");
745
        DebugTimer t("management");
730
        mManagement->run();
746
        mManagement->run();
731
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
747
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
732
    }
748
    }
733
    // ... or ABE (the agent based variant)
749
    // ... or ABE (the agent based variant)
734
    if (mABEManagement) {
750
    if (mABEManagement) {
735
        DebugTimer t("ABE:run");
751
        DebugTimer t("ABE:run");
736
        mABEManagement->run();
752
        mABEManagement->run();
737
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
753
        GlobalSettings::instance()->systemStatistics()->tManagement+=t.elapsed();
738
    }
754
    }
739
755
740
    // if trees are dead/removed because of management, the tree lists
756
    // if trees are dead/removed because of management, the tree lists
741
    // need to be cleaned (and the statistics need to be recreated)
757
    // need to be cleaned (and the statistics need to be recreated)
742
    cleanTreeLists();
758
    cleanTreeLists();
743
759
744
    // process a cycle of individual growth
760
    // process a cycle of individual growth
745
    applyPattern(); // create Light Influence Patterns
761
    applyPattern(); // create Light Influence Patterns
746
    readPattern(); // readout light state of individual trees
762
    readPattern(); // readout light state of individual trees
747
    grow(); // let the trees grow (growth on stand-level, tree-level, mortality)
763
    grow(); // let the trees grow (growth on stand-level, tree-level, mortality)
748
    mGrassCover->execute(); // evaluate the grass / herb cover (and its effect on regeneration)
764
    mGrassCover->execute(); // evaluate the grass / herb cover (and its effect on regeneration)
749
765
750
    // regeneration
766
    // regeneration
751
    if (settings().regenerationEnabled) {
767
    if (settings().regenerationEnabled) {
752
        // seed dispersal
768
        // seed dispersal
753
        DebugTimer tseed("Regeneration and Establishment");
769
        DebugTimer tseed("Regeneration and Establishment");
754
        foreach(SpeciesSet *set, mSpeciesSets)
770
        foreach(SpeciesSet *set, mSpeciesSets)
755
            set->regeneration(); // parallel execution for each species set
771
            set->regeneration(); // parallel execution for each species set
756
772
757
        GlobalSettings::instance()->systemStatistics()->tSeedDistribution+=tseed.elapsed();
773
        GlobalSettings::instance()->systemStatistics()->tSeedDistribution+=tseed.elapsed();
758
        // establishment
774
        // establishment
759
        Sapling::updateBrowsingPressure();
775
        Sapling::updateBrowsingPressure();
760
776
761
        { DebugTimer t("saplingGrowthEstablishment");
777
        { DebugTimer t("saplingGrowthEstablishment");
762
        executePerResourceUnit( nc_sapling_growth_establishment, false /* true: force single thraeded operation */);
778
        executePerResourceUnit( nc_sapling_growth_establishment, false /* true: force single thraeded operation */);
763
        GlobalSettings::instance()->systemStatistics()->tSaplingAndEstablishment+=t.elapsed();
779
        GlobalSettings::instance()->systemStatistics()->tSaplingAndEstablishment+=t.elapsed();
764
        }
780
        }
765
781
766
        Establishment::debugInfo(); // debug test
782
        Establishment::debugInfo(); // debug test
767
783
768
    }
784
    }
769
785
770
    // calculate soil / snag dynamics
786
    // calculate soil / snag dynamics
771
    if (settings().carbonCycleEnabled) {
787
    if (settings().carbonCycleEnabled) {
772
        DebugTimer ccycle("carbon cylce");
788
        DebugTimer ccycle("carbon cylce");
773
        executePerResourceUnit( nc_carbonCycle, false /* true: force single threaded operation */);
789
        executePerResourceUnit( nc_carbonCycle, false /* true: force single threaded operation */);
774
        GlobalSettings::instance()->systemStatistics()->tCarbonCycle+=ccycle.elapsed();
790
        GlobalSettings::instance()->systemStatistics()->tCarbonCycle+=ccycle.elapsed();
775
791
776
    }
792
    }
777
793
778
    // external modules/disturbances
794
    // external modules/disturbances
779
    mModules->run();
795
    mModules->run();
780
796
781
    // cleanup of tree lists if external modules removed trees.
797
    // cleanup of tree lists if external modules removed trees.
782
    cleanTreeLists();
798
    cleanTreeLists();
783
799
784
800
785
    DebugTimer toutput("outputs");
801
    DebugTimer toutput("outputs");
786
    // calculate statistics
802
    // calculate statistics
787
    foreach(ResourceUnit *ru, mRU)
803
    foreach(ResourceUnit *ru, mRU)
788
        ru->yearEnd();
804
        ru->yearEnd();
789
805
790
    // create outputs
806
    // create outputs
791
    OutputManager *om = GlobalSettings::instance()->outputManager();
807
    OutputManager *om = GlobalSettings::instance()->outputManager();
792
    om->execute("tree"); // single tree output
808
    om->execute("tree"); // single tree output
793
    om->execute("treeremoval"); // single removed tree output
809
    om->execute("treeremoval"); // single removed tree output
794
    om->execute("stand"); //resource unit level x species
810
    om->execute("stand"); //resource unit level x species
795
    om->execute("landscape"); //landscape x species
811
    om->execute("landscape"); //landscape x species
796
    om->execute("sapling"); // sapling layer per RU x species
812
    om->execute("sapling"); // sapling layer per RU x species
797
    om->execute("production_month"); // 3pg responses growth per species x RU x month
813
    om->execute("production_month"); // 3pg responses growth per species x RU x month
798
    om->execute("dynamicstand"); // output with user-defined columns (based on species x RU)
814
    om->execute("dynamicstand"); // output with user-defined columns (based on species x RU)
799
    om->execute("standdead"); // resource unit level x species
815
    om->execute("standdead"); // resource unit level x species
800
    om->execute("management"); // resource unit level x species
816
    om->execute("management"); // resource unit level x species
801
    om->execute("carbon"); // resource unit level, carbon pools above and belowground
817
    om->execute("carbon"); // resource unit level, carbon pools above and belowground
802
    om->execute("carbonflow"); // resource unit level, GPP, NPP and total carbon flows (atmosphere, harvest, ...)
818
    om->execute("carbonflow"); // resource unit level, GPP, NPP and total carbon flows (atmosphere, harvest, ...)
803
819
804
    GlobalSettings::instance()->systemStatistics()->tWriteOutput+=toutput.elapsed();
820
    GlobalSettings::instance()->systemStatistics()->tWriteOutput+=toutput.elapsed();
805
    GlobalSettings::instance()->systemStatistics()->tTotalYear+=t.elapsed();
821
    GlobalSettings::instance()->systemStatistics()->tTotalYear+=t.elapsed();
806
    GlobalSettings::instance()->systemStatistics()->writeOutput();
822
    GlobalSettings::instance()->systemStatistics()->writeOutput();
807
823
808
    GlobalSettings::instance()->setCurrentYear(GlobalSettings::instance()->currentYear()+1);
824
    GlobalSettings::instance()->setCurrentYear(GlobalSettings::instance()->currentYear()+1);
809
825
810
    // try to clean up a bit of memory (useful if many large JS objects (e.g., grids) are used)
826
    // try to clean up a bit of memory (useful if many large JS objects (e.g., grids) are used)
811
    GlobalSettings::instance()->scriptEngine()->collectGarbage();
827
    GlobalSettings::instance()->scriptEngine()->collectGarbage();
812
}
828
}
813
829
814
830
815
831
816
void Model::afterStop()
832
void Model::afterStop()
817
{
833
{
818
    // do some cleanup
834
    // do some cleanup
819
}
835
}
820
836
821
/// multithreaded running function for LIP printing
837
/// multithreaded running function for LIP printing
822
ResourceUnit* nc_applyPattern(ResourceUnit *unit)
838
ResourceUnit* nc_applyPattern(ResourceUnit *unit)
823
{
839
{
824
840
825
    QVector<Tree>::iterator tit;
841
    QVector<Tree>::iterator tit;
826
    QVector<Tree>::iterator tend = unit->trees().end();
842
    QVector<Tree>::iterator tend = unit->trees().end();
827
843
828
    try {
844
    try {
829
845
830
        // light concurrence influence
846
        // light concurrence influence
831
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
847
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
832
            // height dominance grid
848
            // height dominance grid
833
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
849
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
834
                (*tit).heightGrid(); // just do it ;)
850
                (*tit).heightGrid(); // just do it ;)
835
851
836
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
852
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
837
                (*tit).applyLIP(); // just do it ;)
853
                (*tit).applyLIP(); // just do it ;)
838
854
839
        } else {
855
        } else {
840
            // height dominance grid
856
            // height dominance grid
841
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
857
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
842
                (*tit).heightGrid_torus(); // just do it ;)
858
                (*tit).heightGrid_torus(); // just do it ;)
843
859
844
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
860
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
845
                (*tit).applyLIP_torus(); // do it the wraparound way
861
                (*tit).applyLIP_torus(); // do it the wraparound way
846
        }
862
        }
847
        return unit;
863
        return unit;
848
    } catch (const IException &e) {
864
    } catch (const IException &e) {
849
        GlobalSettings::instance()->controller()->throwError(e.message());
865
        GlobalSettings::instance()->controller()->throwError(e.message());
850
    }
866
    }
851
    return unit;
867
    return unit;
852
}
868
}
853
869
854
/// multithreaded running function for LIP value extraction
870
/// multithreaded running function for LIP value extraction
855
ResourceUnit *nc_readPattern(ResourceUnit *unit)
871
ResourceUnit *nc_readPattern(ResourceUnit *unit)
856
{
872
{
857
    QVector<Tree>::iterator tit;
873
    QVector<Tree>::iterator tit;
858
    QVector<Tree>::iterator  tend = unit->trees().end();
874
    QVector<Tree>::iterator  tend = unit->trees().end();
859
    try {
875
    try {
860
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
876
        if (!GlobalSettings::instance()->settings().paramValueBool("torus")) {
861
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
877
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
862
                (*tit).readLIF(); // multipliactive approach
878
                (*tit).readLIF(); // multipliactive approach
863
        } else {
879
        } else {
864
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
880
            for (tit=unit->trees().begin(); tit!=tend; ++tit)
865
                (*tit).readLIF_torus(); // do it the wraparound way
881
                (*tit).readLIF_torus(); // do it the wraparound way
866
        }
882
        }
867
    } catch (const IException &e) {
883
    } catch (const IException &e) {
868
        GlobalSettings::instance()->controller()->throwError(e.message());
884
        GlobalSettings::instance()->controller()->throwError(e.message());
869
    }
885
    }
870
    return unit;
886
    return unit;
871
}
887
}
872
888
873
/// multithreaded running function for the growth of individual trees
889
/// multithreaded running function for the growth of individual trees
874
ResourceUnit *nc_grow(ResourceUnit *unit)
890
ResourceUnit *nc_grow(ResourceUnit *unit)
875
{
891
{
876
    QVector<Tree>::iterator tit;
892
    QVector<Tree>::iterator tit;
877
    QVector<Tree>::iterator  tend = unit->trees().end();
893
    QVector<Tree>::iterator  tend = unit->trees().end();
878
    try {
894
    try {
879
        unit->beforeGrow(); // reset statistics
895
        unit->beforeGrow(); // reset statistics
880
        // calculate light responses
896
        // calculate light responses
881
        // responses are based on *modified* values for LightResourceIndex
897
        // responses are based on *modified* values for LightResourceIndex
882
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
898
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
883
            (*tit).calcLightResponse();
899
            (*tit).calcLightResponse();
884
        }
900
        }
885
901
886
        unit->calculateInterceptedArea();
902
        unit->calculateInterceptedArea();
887
903
888
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
904
        for (tit=unit->trees().begin(); tit!=tend; ++tit) {
889
            (*tit).grow(); // actual growth of individual trees
905
            (*tit).grow(); // actual growth of individual trees
890
        }
906
        }
891
    } catch (const IException &e) {
907
    } catch (const IException &e) {
892
        GlobalSettings::instance()->controller()->throwError(e.message());
908
        GlobalSettings::instance()->controller()->throwError(e.message());
893
    }
909
    }
894
910
895
    GlobalSettings::instance()->systemStatistics()->treeCount+=unit->trees().count();
911
    GlobalSettings::instance()->systemStatistics()->treeCount+=unit->trees().count();
896
    return unit;
912
    return unit;
897
}
913
}
898
914
899
/// multithreaded running function for the resource level production
915
/// multithreaded running function for the resource level production
900
ResourceUnit *nc_production(ResourceUnit *unit)
916
ResourceUnit *nc_production(ResourceUnit *unit)
901
{
917
{
902
    try {
918
    try {
903
        unit->production();
919
        unit->production();
904
    } catch (const IException &e) {
920
    } catch (const IException &e) {
905
        GlobalSettings::instance()->controller()->throwError(e.message());
921
        GlobalSettings::instance()->controller()->throwError(e.message());
906
    }
922
    }
907
    return unit;
923
    return unit;
908
}
924
}
909
925
910
926
911
void Model::test()
927
void Model::test()
912
{
928
{
913
    // Test-funktion: braucht 1/3 time von readGrid()
929
    // Test-funktion: braucht 1/3 time von readGrid()
914
    DebugTimer t("test");
930
    DebugTimer t("test");
915
    FloatGrid averaged = mGrid->averaged(10);
931
    FloatGrid averaged = mGrid->averaged(10);
916
    int count = 0;
932
    int count = 0;
917
    float *end = averaged.end();
933
    float *end = averaged.end();
918
    for (float *p=averaged.begin(); p!=end; ++p)
934
    for (float *p=averaged.begin(); p!=end; ++p)
919
        if (*p > 0.9)
935
        if (*p > 0.9)
920
            count++;
936
            count++;
921
    qDebug() << count << "LIF>0.9 of " << averaged.count();
937
    qDebug() << count << "LIF>0.9 of " << averaged.count();
922
}
938
}
923
939
924
void Model::debugCheckAllTrees()
940
void Model::debugCheckAllTrees()
925
{
941
{
926
    AllTreeIterator at(this);
942
    AllTreeIterator at(this);
927
    bool has_errors = false; double dummy=0.;
943
    bool has_errors = false; double dummy=0.;
928
    while (Tree *t = at.next()) {
944
    while (Tree *t = at.next()) {
929
        // plausibility
945
        // plausibility
930
        if (t->dbh()<0 || t->dbh()>10000. || t->biomassFoliage()<0. || t->height()>1000. || t->height() < 0.
946
        if (t->dbh()<0 || t->dbh()>10000. || t->biomassFoliage()<0. || t->height()>1000. || t->height() < 0.
931
                || t->biomassFoliage() <0.)
947
                || t->biomassFoliage() <0.)
932
            has_errors = true;
948
            has_errors = true;
933
        // check for objects....
949
        // check for objects....
934
        dummy = t->stamp()->offset() + t->ru()->ruSpecies()[1]->statistics().count();
950
        dummy = t->stamp()->offset() + t->ru()->ruSpecies()[1]->statistics().count();
935
    }
951
    }
936
    if (has_errors)
952
    if (has_errors)
937
        qDebug() << "model: debugCheckAllTrees found problems" << dummy;
953
        qDebug() << "model: debugCheckAllTrees found problems" << dummy;
938
}
954
}
939
955
940
void Model::applyPattern()
956
void Model::applyPattern()
941
{
957
{
942
958
943
    DebugTimer t("applyPattern()");
959
    DebugTimer t("applyPattern()");
944
    // intialize grids...
960
    // intialize grids...
945
    initializeGrid();
961
    initializeGrid();
946
962
947
    // initialize height grid with a value of 4m. This is the height of the regeneration layer
963
    // initialize height grid with a value of 4m. This is the height of the regeneration layer
948
    for (HeightGridValue *h=mHeightGrid->begin();h!=mHeightGrid->end();++h) {
964
    for (HeightGridValue *h=mHeightGrid->begin();h!=mHeightGrid->end();++h) {
949
        h->resetCount(); // set count = 0, but do not touch the flags
965
        h->resetCount(); // set count = 0, but do not touch the flags
950
        h->height = 4.f;
966
        h->height = 4.f;
951
    }
967
    }
952
968
953
    threadRunner.run(nc_applyPattern);
969
    threadRunner.run(nc_applyPattern);
954
    GlobalSettings::instance()->systemStatistics()->tApplyPattern+=t.elapsed();
970
    GlobalSettings::instance()->systemStatistics()->tApplyPattern+=t.elapsed();
955
}
971
}
956
972
957
void Model::readPattern()
973
void Model::readPattern()
958
{
974
{
959
    DebugTimer t("readPattern()");
975
    DebugTimer t("readPattern()");
960
    threadRunner.run(nc_readPattern);
976
    threadRunner.run(nc_readPattern);
961
    GlobalSettings::instance()->systemStatistics()->tReadPattern+=t.elapsed();
977
    GlobalSettings::instance()->systemStatistics()->tReadPattern+=t.elapsed();
962
978
963
}
979
}
964
980
965
/** Main function for the growth of stands and trees.
981
/** Main function for the growth of stands and trees.
966
   This includes several steps.
982
   This includes several steps.
967
   (1) calculate the stocked area (i.e. count pixels in height grid)
983
   (1) calculate the stocked area (i.e. count pixels in height grid)
968
   (2) 3PG production (including response calculation, water cycle)
984
   (2) 3PG production (including response calculation, water cycle)
969
   (3) single tree growth (including mortality)
985
   (3) single tree growth (including mortality)
970
   (4) cleanup of tree lists (remove dead trees)
986
   (4) cleanup of tree lists (remove dead trees)
971
  */
987
  */
972
void Model::grow()
988
void Model::grow()
973
{
989
{
974
990
975
    if (!settings().growthEnabled)
991
    if (!settings().growthEnabled)
976
        return;
992
        return;
977
    { DebugTimer t("growRU()");
993
    { DebugTimer t("growRU()");
978
    calculateStockedArea();
994
    calculateStockedArea();
979
995
980
    // multithreaded: mutex for the message handler in mainwindow solved the crashes.
996
    // multithreaded: mutex for the message handler in mainwindow solved the crashes.
981
    threadRunner.run(nc_production);
997
    threadRunner.run(nc_production);
982
    }
998
    }
983
999
984
    DebugTimer t("growTrees()");
1000
    DebugTimer t("growTrees()");
985
    threadRunner.run(nc_grow); // actual growth of individual trees
1001
    threadRunner.run(nc_grow); // actual growth of individual trees
986
1002
987
    foreach(ResourceUnit *ru, mRU) {
1003
    foreach(ResourceUnit *ru, mRU) {
988
       ru->cleanTreeList();
1004
       ru->cleanTreeList();
989
       ru->afterGrow();
1005
       ru->afterGrow();
990
       //qDebug() << (b-n) << "trees died (of" << b << ").";
1006
       //qDebug() << (b-n) << "trees died (of" << b << ").";
991
   }
1007
   }
992
   GlobalSettings::instance()->systemStatistics()->tTreeGrowth+=t.elapsed();
1008
   GlobalSettings::instance()->systemStatistics()->tTreeGrowth+=t.elapsed();
993
}
1009
}
994
1010
995
/** calculate for each resource unit the fraction of area which is stocked.
1011
/** calculate for each resource unit the fraction of area which is stocked.
996
  This is done by checking the pixels of the global height grid.
1012
  This is done by checking the pixels of the global height grid.
997
  */
1013
  */
998
void Model::calculateStockedArea()
1014
void Model::calculateStockedArea()
999
{
1015
{
1000
    // iterate over the whole heightgrid and count pixels for each ressource unit
1016
    // iterate over the whole heightgrid and count pixels for each ressource unit
1001
    HeightGridValue *end = mHeightGrid->end();
1017
    HeightGridValue *end = mHeightGrid->end();
1002
    QPointF cp;
1018
    QPointF cp;
1003
    ResourceUnit *ru;
1019
    ResourceUnit *ru;
1004
    for (HeightGridValue *i=mHeightGrid->begin(); i!=end; ++i) {
1020
    for (HeightGridValue *i=mHeightGrid->begin(); i!=end; ++i) {
1005
        cp = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
1021
        cp = mHeightGrid->cellCenterPoint(mHeightGrid->indexOf(i));
1006
        if (mRUmap.coordValid(cp)) {
1022
        if (mRUmap.coordValid(cp)) {
1007
            ru = mRUmap.valueAt(cp);
1023
            ru = mRUmap.valueAt(cp);
1008
            if (ru) {
1024
            if (ru) {
1009
                ru->countStockedPixel( (*i).count()>0 );
1025
                ru->countStockedPixel( (*i).count()>0 );
1010
            }
1026
            }
1011
        }
1027
        }
1012
1028
1013
    }
1029
    }
1014
}
1030
}
1015
1031
1016
/** calculate for each resource unit the stockable area.
1032
/** calculate for each resource unit the stockable area.
1017
  "stockability" is determined by the isValid flag of resource units which in turn
1033
  "stockability" is determined by the isValid flag of resource units which in turn
1018
  is derived from stand grid values.
1034
  is derived from stand grid values.
1019
  */
1035
  */
1020
void Model::calculateStockableArea()
1036
void Model::calculateStockableArea()
1021
{
1037
{
1022
1038
1023
    foreach(ResourceUnit *ru, mRU) {
1039
    foreach(ResourceUnit *ru, mRU) {
1024
        // //
1040
        // //
1025
        //        if (ru->id()==-1) {
1041
        //        if (ru->id()==-1) {
1026
        //            ru->setStockableArea(0.);
1042
        //            ru->setStockableArea(0.);
1027
        //            continue;
1043
        //            continue;
1028
        //        }
1044
        //        }
1029
        GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1045
        GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1030
        int valid=0, total=0;
1046
        int valid=0, total=0;
1031
        while (runner.next()) {
1047
        while (runner.next()) {
1032
            if ( runner.current()->isValid() )
1048
            if ( runner.current()->isValid() )
1033
                valid++;
1049
                valid++;
1034
            total++;
1050
            total++;
1035
        }
1051
        }
1036
        if (total) {
1052
        if (total) {
1037
            ru->setStockableArea( cHeightPixelArea * valid);
1053
            ru->setStockableArea( cHeightPixelArea * valid);
1038
            if (valid==0 && ru->id()>-1) {
1054
            if (valid==0 && ru->id()>-1) {
1039
                // invalidate this resource unit
1055
                // invalidate this resource unit
1040
                ru->setID(-1);
1056
                ru->setID(-1);
1041
            }
1057
            }
1042
            if (valid>0 && ru->id()==-1) {
1058
            if (valid>0 && ru->id()==-1) {
1043
                qDebug() << "Warning: a resource unit has id=-1 but stockable area (id was set to 0)!!! ru: " << ru->boundingBox() << "with index" << ru->index();
1059
                qDebug() << "Warning: a resource unit has id=-1 but stockable area (id was set to 0)!!! ru: " << ru->boundingBox() << "with index" << ru->index();
1044
                ru->setID(0);
1060
                ru->setID(0);
1045
                // test-code
1061
                // test-code
1046
                //GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1062
                //GridRunner<HeightGridValue> runner(*mHeightGrid, ru->boundingBox());
1047
                //while (runner.next()) {
1063
                //while (runner.next()) {
1048
                //    qDebug() << mHeightGrid->cellCenterPoint(mHeightGrid->indexOf( runner.current() )) << ": " << runner.current()->isValid();
1064
                //    qDebug() << mHeightGrid->cellCenterPoint(mHeightGrid->indexOf( runner.current() )) << ": " << runner.current()->isValid();
1049
                //}
1065
                //}
1050
1066
1051
            }
1067
            }
1052
        } else
1068
        } else
1053
            throw IException("calculateStockableArea: resource unit without pixels!");
1069
            throw IException("calculateStockableArea: resource unit without pixels!");
1054
1070
1055
    }
1071
    }
1056
    // mark those pixels that are at the edge of a "forest-out-of-area"
1072
    // mark those pixels that are at the edge of a "forest-out-of-area"
1057
    GridRunner<HeightGridValue> runner(*mHeightGrid, mHeightGrid->metricRect());
1073
    GridRunner<HeightGridValue> runner(*mHeightGrid, mHeightGrid->metricRect());
1058
    HeightGridValue* neighbors[8];
1074
    HeightGridValue* neighbors[8];
1059
    while (runner.next()) {
1075
    while (runner.next()) {
1060
        if (runner.current()->isForestOutside()) {
1076
        if (runner.current()->isForestOutside()) {
1061
            // if the current pixel is a "radiating" border pixel,
1077
            // if the current pixel is a "radiating" border pixel,
1062
            // then check the neighbors and set a flag if the pixel is a neighbor of a in-project-area pixel.
1078
            // then check the neighbors and set a flag if the pixel is a neighbor of a in-project-area pixel.
1063
            runner.neighbors8(neighbors);
1079
            runner.neighbors8(neighbors);
1064
            for (int i=0;i<8;++i)
1080
            for (int i=0;i<8;++i)
1065
                if (neighbors[i] &&  neighbors[i]->isValid())
1081
                if (neighbors[i] &&  neighbors[i]->isValid())
1066
                    runner.current()->setIsRadiating();
1082
                    runner.current()->setIsRadiating();
1067
1083
1068
        }
1084
        }
1069
    }
1085
    }
1070
1086
1071
}
1087
}
1072
1088
1073
void Model::initializeGrid()
1089
void Model::initializeGrid()
1074
{
1090
{
1075
    // fill the whole grid with a value of "1."
1091
    // fill the whole grid with a value of "1."
1076
    mGrid->initialize(1.f);
1092
    mGrid->initialize(1.f);
1077
1093
1078
    // apply special values for grid cells border regions where out-of-area cells
1094
    // apply special values for grid cells border regions where out-of-area cells
1079
    // radiate into the main LIF grid.
1095
    // radiate into the main LIF grid.
1080
    QPoint p;
1096
    QPoint p;
1081
    int ix_min, ix_max, iy_min, iy_max, ix_center, iy_center;
1097
    int ix_min, ix_max, iy_min, iy_max, ix_center, iy_center;
1082
    const int px_offset = cPxPerHeight / 2; // for 5 px per height grid cell, the offset is 2
1098
    const int px_offset = cPxPerHeight / 2; // for 5 px per height grid cell, the offset is 2
1083
    const int max_radiate_distance = 7;
1099
    const int max_radiate_distance = 7;
1084
    const float step_width = 1.f / (float)max_radiate_distance;
1100
    const float step_width = 1.f / (float)max_radiate_distance;
1085
    int c_rad = 0;
1101
    int c_rad = 0;
1086
    for (HeightGridValue *hgv=mHeightGrid->begin(); hgv!=mHeightGrid->end(); ++hgv) {
1102
    for (HeightGridValue *hgv=mHeightGrid->begin(); hgv!=mHeightGrid->end(); ++hgv) {
1087
        if (hgv->isRadiating()) {
1103
        if (hgv->isRadiating()) {
1088
            p=mHeightGrid->indexOf(hgv);
1104
            p=mHeightGrid->indexOf(hgv);
1089
            ix_min = p.x() * cPxPerHeight - max_radiate_distance + px_offset;
1105
            ix_min = p.x() * cPxPerHeight - max_radiate_distance + px_offset;
1090
            ix_max = ix_min + 2*max_radiate_distance + 1;
1106
            ix_max = ix_min + 2*max_radiate_distance + 1;
1091
            ix_center = ix_min + max_radiate_distance;
1107
            ix_center = ix_min + max_radiate_distance;
1092
            iy_min = p.y() * cPxPerHeight - max_radiate_distance + px_offset;
1108
            iy_min = p.y() * cPxPerHeight - max_radiate_distance + px_offset;
1093
            iy_max = iy_min + 2*max_radiate_distance + 1;
1109
            iy_max = iy_min + 2*max_radiate_distance + 1;
1094
            iy_center = iy_min + max_radiate_distance;
1110
            iy_center = iy_min + max_radiate_distance;
1095
            for (int y=iy_min; y<=iy_max; ++y) {
1111
            for (int y=iy_min; y<=iy_max; ++y) {
1096
                for (int x=ix_min; x<=ix_max; ++x) {
1112
                for (int x=ix_min; x<=ix_max; ++x) {
1097
                    if (!mGrid->isIndexValid(x,y) ||  !(*mHeightGrid)(x/cPxPerHeight, y/cPxPerHeight).isValid())
1113
                    if (!mGrid->isIndexValid(x,y) ||  !(*mHeightGrid)(x/cPxPerHeight, y/cPxPerHeight).isValid())
1098
                        continue;
1114
                        continue;
1099
                    float value = qMax(qAbs(x-ix_center), qAbs(y-iy_center)) * step_width;
1115
                    float value = qMax(qAbs(x-ix_center), qAbs(y-iy_center)) * step_width;
1100
                    float &v = mGrid->valueAtIndex(x, y);
1116
                    float &v = mGrid->valueAtIndex(x, y);
1101
                    if (value>=0.f && v>value)
1117
                    if (value>=0.f && v>value)
1102
                        v = value;
1118
                        v = value;
1103
                }
1119
                }
1104
            }
1120
            }
1105
            c_rad++;
1121
            c_rad++;
1106
        }
1122
        }
1107
    }
1123
    }
1108
    if (logLevelDebug())
1124
    if (logLevelDebug())
1109
        qDebug() << "initialize grid:" << c_rad << "radiating pixels...";
1125
        qDebug() << "initialize grid:" << c_rad << "radiating pixels...";
1110
1126
1111
}
1127
}
1112
1128
1113
1129
1114
/// Force the creation of stand statistics.
1130
/// Force the creation of stand statistics.
1115
/// - stocked area (for resourceunit-areas)
1131
/// - stocked area (for resourceunit-areas)
1116
/// - ru - statistics
1132
/// - ru - statistics
1117
void Model::createStandStatistics()
1133
void Model::createStandStatistics()
1118
{
1134
{
1119
    calculateStockedArea();
1135
    calculateStockedArea();
1120
    foreach(ResourceUnit *ru, mRU) {
1136
    foreach(ResourceUnit *ru, mRU) {
1121
        ru->addTreeAgingForAllTrees();
1137
        ru->addTreeAgingForAllTrees();
1122
        ru->createStandStatistics();
1138
        ru->createStandStatistics();
1123
    }
1139
    }
1124
}
1140
}
1125
1141
1126
void Model::cleanTreeLists()
1142
void Model::cleanTreeLists()
1127
{
1143
{
1128
    foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
1144
    foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
1129
        if (ru->hasDiedTrees()) {
1145
        if (ru->hasDiedTrees()) {
1130
            ru->cleanTreeList();
1146
            ru->cleanTreeList();
1131
            ru->recreateStandStatistics();
1147
            ru->recreateStandStatistics();
1132
        }
1148
        }
1133
    }
1149
    }
1134
}
1150
}
1135
1151
1136
1152
1137
 
1153