Subversion Repositories public iLand

Rev

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

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

394

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