Subversion Repositories public iLand

Rev

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

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

380

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