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