Rev 1064 | Rev 1217 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1064 | Rev 1104 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/environment.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/environment.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 | #include "global.h"
|
21 | #include "global.h"
|
22 | #include "environment.h"
|
22 | #include "environment.h"
|
23 | #include "debugtimer.h"
|
23 | #include "debugtimer.h"
|
24 | #include "helper.h"
|
24 | #include "helper.h"
|
25 | #include "csvfile.h"
|
25 | #include "csvfile.h"
|
26 | #include "gisgrid.h"
|
26 | #include "gisgrid.h"
|
27 | 27 | ||
28 | #include "climate.h"
|
28 | #include "climate.h"
|
29 | #include "speciesset.h"
|
29 | #include "speciesset.h"
|
30 | 30 | ||
31 | 31 | ||
32 | /** Represents the input of various variables with regard to climate, soil properties and more.
|
32 | /** Represents the input of various variables with regard to climate, soil properties and more.
|
33 | @ingroup tools
|
33 | @ingroup tools
|
34 | Data is read from various sources and presented to the core model with a standardized interface.
|
34 | Data is read from various sources and presented to the core model with a standardized interface.
|
35 | see http://iland.boku.ac.at/simulation+extent
|
35 | see http://iland.boku.ac.at/simulation+extent
|
36 | */
|
36 | */
|
37 | Environment::Environment() |
37 | Environment::Environment() |
38 | {
|
38 | {
|
39 | mInfile = 0; |
39 | mInfile = 0; |
40 | mGrid = 0; |
40 | mGrid = 0; |
41 | mGridMode = false; |
41 | mGridMode = false; |
42 | mCurrentSpeciesSet = 0; |
42 | mCurrentSpeciesSet = 0; |
43 | mCurrentClimate = 0; |
43 | mCurrentClimate = 0; |
44 | mCurrentID = 0; |
44 | mCurrentID = 0; |
45 | }
|
45 | }
|
46 | Environment::~Environment() |
46 | Environment::~Environment() |
47 | {
|
47 | {
|
48 | if (mInfile) { |
48 | if (mInfile) { |
49 | delete mInfile; |
49 | delete mInfile; |
50 | }
|
50 | }
|
51 | if (mGrid) |
51 | if (mGrid) |
52 | delete mGrid; |
52 | delete mGrid; |
53 | }
|
53 | }
|
54 | 54 | ||
55 | bool Environment::loadFromFile(const QString &fileName) |
55 | bool Environment::loadFromFile(const QString &fileName) |
56 | {
|
56 | {
|
57 | QString source = Helper::loadTextFile(GlobalSettings::instance()->path(fileName)); |
57 | QString source = Helper::loadTextFile(GlobalSettings::instance()->path(fileName)); |
58 | if (source.isEmpty()) |
58 | if (source.isEmpty()) |
59 | throw IException(QString("Environment: input file does not exist or is empty (%1)").arg(fileName)); |
59 | throw IException(QString("Environment: input file does not exist or is empty (%1)").arg(fileName)); |
60 | return loadFromString(source); |
60 | return loadFromString(source); |
61 | }
|
61 | }
|
62 | 62 | ||
63 | // ******** specific keys *******
|
63 | // ******** specific keys *******
|
64 | const QString speciesKey = "model.species.source"; |
64 | const QString speciesKey = "model.species.source"; |
65 | const QString climateKey = "model.climate.tableName"; |
65 | const QString climateKey = "model.climate.tableName"; |
66 | 66 | ||
67 | bool Environment::loadFromString(const QString &source) |
67 | bool Environment::loadFromString(const QString &source) |
68 | {
|
68 | {
|
69 | try { |
69 | try { |
70 | if (mInfile) |
70 | if (mInfile) |
71 | delete mInfile; |
71 | delete mInfile; |
72 | mInfile = new CSVFile(); |
72 | mInfile = new CSVFile(); |
73 | 73 | ||
74 | mInfile->loadFromString(source); |
74 | mInfile->loadFromString(source); |
75 | mKeys = mInfile->captions(); |
75 | mKeys = mInfile->captions(); |
76 | 76 | ||
77 | XmlHelper xml(GlobalSettings::instance()->settings()); |
77 | XmlHelper xml(GlobalSettings::instance()->settings()); |
78 | mSpeciesSets.clear(); // note: the objects are not destroyed - potential memory leak. |
78 | mSpeciesSets.clear(); // note: the objects are not destroyed - potential memory leak. |
79 | mClimate.clear(); |
79 | mClimate.clear(); |
80 | mRowCoordinates.clear(); |
80 | mRowCoordinates.clear(); |
81 | mCreatedObjects.clear(); |
81 | mCreatedObjects.clear(); |
82 | mCurrentID = 0; |
82 | mCurrentID = 0; |
83 | 83 | ||
84 | int index; |
84 | int index; |
85 | if (mGridMode) { |
85 | if (mGridMode) { |
86 | int id = mInfile->columnIndex("id"); |
86 | int id = mInfile->columnIndex("id"); |
87 | if (id<0) |
87 | if (id<0) |
88 | throw IException("Environment:: (grid mode) input file has no 'id' column!"); |
88 | throw IException("Environment:: (grid mode) input file has no 'id' column!"); |
89 | for (int row=0;row<mInfile->rowCount();row++) { |
89 | for (int row=0;row<mInfile->rowCount();row++) { |
90 | mRowCoordinates[mInfile->value(row, id).toString()] = row; |
90 | mRowCoordinates[mInfile->value(row, id).toString()] = row; |
91 | }
|
91 | }
|
92 | 92 | ||
93 | } else { |
93 | } else { |
94 | // *** Matrix mode ******
|
94 | // *** Matrix mode ******
|
95 | // each row must contain 'x' and 'y' coordinates
|
95 | // each row must contain 'x' and 'y' coordinates
|
96 | // setup coordinates (x,y)
|
96 | // setup coordinates (x,y)
|
97 | int ix,iy; |
97 | int ix,iy; |
98 | ix = mInfile->columnIndex("x"); |
98 | ix = mInfile->columnIndex("x"); |
99 | iy = mInfile->columnIndex("y"); |
99 | iy = mInfile->columnIndex("y"); |
100 | if (ix<0 || iy<0) |
100 | if (ix<0 || iy<0) |
101 | throw IException("Environment:: (matrix mode) input file has no x/y coordinates!"); |
101 | throw IException("Environment:: (matrix mode) input file has no x/y coordinates!"); |
102 | for (int row=0;row<mInfile->rowCount();row++) { |
102 | for (int row=0;row<mInfile->rowCount();row++) { |
103 | QString key=QString("%1_%2") |
103 | QString key=QString("%1_%2") |
104 | .arg(mInfile->value(row, ix).toString()) |
104 | .arg(mInfile->value(row, ix).toString()) |
105 | .arg(mInfile->value(row, iy).toString()); |
105 | .arg(mInfile->value(row, iy).toString()); |
106 | mRowCoordinates[key] = row; |
106 | mRowCoordinates[key] = row; |
107 | }
|
107 | }
|
108 | }
|
108 | }
|
109 | 109 | ||
110 | 110 | ||
111 | 111 | ||
112 | // ******** setup of Species Sets *******
|
112 | // ******** setup of Species Sets *******
|
113 | if ((index = mKeys.indexOf(speciesKey))>-1) { |
113 | if ((index = mKeys.indexOf(speciesKey))>-1) { |
114 | DebugTimer t("environment:load species"); |
114 | DebugTimer t("environment:load species"); |
115 | QStringList speciesNames = mInfile->column(index); |
115 | QStringList speciesNames = mInfile->column(index); |
116 | speciesNames.removeDuplicates(); |
116 | speciesNames.removeDuplicates(); |
117 | qDebug() << "creating species sets:" << speciesNames; |
117 | qDebug() << "creating species sets:" << speciesNames; |
118 | foreach (const QString &name, speciesNames) { |
118 | foreach (const QString &name, speciesNames) { |
119 | xml.setNodeValue(speciesKey,name); // set xml value |
119 | xml.setNodeValue(speciesKey,name); // set xml value |
120 | // create species sets
|
120 | // create species sets
|
121 | SpeciesSet *set = new SpeciesSet(); |
121 | SpeciesSet *set = new SpeciesSet(); |
122 | mSpeciesSets.push_back(set); |
122 | mSpeciesSets.push_back(set); |
123 | mCreatedObjects[name] = (void*)set; |
123 | mCreatedObjects[name] = (void*)set; |
124 | set->setup(); |
124 | set->setup(); |
125 | }
|
125 | }
|
126 | qDebug() << mSpeciesSets.count() << "species sets created."; |
126 | qDebug() << mSpeciesSets.count() << "species sets created."; |
127 | } else { |
127 | } else { |
128 | // no species sets specified
|
128 | // no species sets specified
|
129 | SpeciesSet *speciesSet = new SpeciesSet(); |
129 | SpeciesSet *speciesSet = new SpeciesSet(); |
130 | mSpeciesSets.push_back(speciesSet); |
130 | mSpeciesSets.push_back(speciesSet); |
131 | speciesSet->setup(); |
131 | speciesSet->setup(); |
132 | mCurrentSpeciesSet = speciesSet; |
132 | mCurrentSpeciesSet = speciesSet; |
133 | }
|
133 | }
|
134 | 134 | ||
135 | // ******** setup of Climate *******
|
135 | // ******** setup of Climate *******
|
136 | if ((index = mKeys.indexOf(climateKey))>-1) { |
136 | if ((index = mKeys.indexOf(climateKey))>-1) { |
137 | DebugTimer t("environment:load climate"); |
137 | DebugTimer t("environment:load climate"); |
138 | QStringList climateNames = mInfile->column(index); |
138 | QStringList climateNames = mInfile->column(index); |
139 | climateNames.removeDuplicates(); |
139 | climateNames.removeDuplicates(); |
140 | if (logLevelDebug()) |
140 | if (logLevelDebug()) |
141 | qDebug() << "creating climatae: " << climateNames; |
141 | qDebug() << "creating climatae: " << climateNames; |
142 | qDebug() << "Environment: climate: # of climates in environment file:" << climateNames.count(); |
142 | qDebug() << "Environment: climate: # of climates in environment file:" << climateNames.count(); |
143 | foreach (QString name, climateNames) { |
143 | foreach (QString name, climateNames) { |
144 | // create an entry in the list of created objects, but
|
144 | // create an entry in the list of created objects, but
|
145 | // really create the climate only if required (see setPosition() )
|
145 | // really create the climate only if required (see setPosition() )
|
146 | mCreatedObjects[name]=(void*)0; |
146 | mCreatedObjects[name]=(void*)0; |
147 | xml.setNodeValue(climateKey,name); // set xml value |
147 | xml.setNodeValue(climateKey,name); // set xml value |
148 | }
|
148 | }
|
149 | } else { |
149 | } else { |
150 | // no climate defined - setup default climate
|
150 | // no climate defined - setup default climate
|
151 | Climate *c = new Climate(); |
151 | Climate *c = new Climate(); |
152 | mClimate.push_back(c); |
152 | mClimate.push_back(c); |
153 | c->setup(); |
153 | c->setup(); |
154 | mCurrentClimate = c; |
154 | mCurrentClimate = c; |
155 | }
|
155 | }
|
156 | if (!mCurrentClimate && mClimate.count()>0) |
156 | if (!mCurrentClimate && mClimate.count()>0) |
157 | mCurrentClimate = mClimate[0]; |
157 | mCurrentClimate = mClimate[0]; |
158 | if (!mCurrentSpeciesSet && mSpeciesSets.count()>0) |
158 | if (!mCurrentSpeciesSet && mSpeciesSets.count()>0) |
159 | mCurrentSpeciesSet = mSpeciesSets[0]; |
159 | mCurrentSpeciesSet = mSpeciesSets[0]; |
160 | return true; |
160 | return true; |
161 | 161 | ||
162 | } catch(const IException &e) { |
162 | } catch(const IException &e) { |
163 | QString addMsg;
|
163 | QString addMsg;
|
164 | if (!mClimate.isEmpty()) |
164 | if (!mClimate.isEmpty()) |
165 | addMsg = QString("last Climate: %1 ").arg(mClimate.last()->name()); |
165 | addMsg = QString("last Climate: %1 ").arg(mClimate.last()->name()); |
166 | if (!mSpeciesSets.isEmpty()) |
166 | if (!mSpeciesSets.isEmpty()) |
167 | addMsg += QString("last Speciesset table: %1").arg(mSpeciesSets.last()->name()); |
167 | addMsg += QString("last Speciesset table: %1").arg(mSpeciesSets.last()->name()); |
168 | QString error_msg = QString("An error occured during the setup of the environment: \n%1\n%2").arg(e.message()).arg(addMsg); |
168 | QString error_msg = QString("An error occured during the setup of the environment: \n%1\n%2").arg(e.message()).arg(addMsg); |
169 | qDebug() << error_msg; |
169 | qDebug() << error_msg; |
170 | Helper::msg(error_msg); |
170 | Helper::msg(error_msg); |
171 | return false; |
171 | return false; |
172 | }
|
172 | }
|
173 | }
|
173 | }
|
174 | 174 | ||
175 | /** sets the "pointer" to a "position" (metric coordinates).
|
175 | /** sets the "pointer" to a "position" (metric coordinates).
|
176 | All specified values are set (also the climate/species-set pointers).
|
176 | All specified values are set (also the climate/species-set pointers).
|
177 | */
|
177 | */
|
178 | void Environment::setPosition(const QPointF position) |
178 | void Environment::setPosition(const QPointF position) |
179 | {
|
179 | {
|
180 | // no changes occur, when the "environment" is not loaded
|
180 | // no changes occur, when the "environment" is not loaded
|
181 | if (!isSetup()) |
181 | if (!isSetup()) |
182 | return; |
182 | return; |
183 | QString key;
|
183 | QString key;
|
184 | int ix=-1, iy=-1, id=-1; |
184 | int ix=-1, iy=-1, id=-1; |
185 | if (mGridMode) { |
185 | if (mGridMode) { |
186 | // grid mode
|
186 | // grid mode
|
187 | id = mGrid->value(position); |
187 | id = mGrid->value(position); |
188 | mCurrentID = id; |
188 | mCurrentID = id; |
189 | key = QString::number(id); |
189 | key = QString::number(id); |
190 | if (id==-1) |
190 | if (id==-1) |
191 | return; // no data for the resource unit |
191 | return; // no data for the resource unit |
192 | } else { |
192 | } else { |
193 | // access data in the matrix by resource unit indices
|
193 | // access data in the matrix by resource unit indices
|
194 | ix = int(position.x() / 100.); // suppose size of 1 ha for each coordinate |
194 | ix = int(position.x() / 100.); // suppose size of 1 ha for each coordinate |
195 | iy = int(position.y() / 100.); |
195 | iy = int(position.y() / 100.); |
196 | mCurrentID++; // to have Ids for each resource unit |
196 | mCurrentID++; // to have Ids for each resource unit |
197 | 197 | ||
198 | key=QString("%1_%2").arg(ix).arg(iy); |
198 | key=QString("%1_%2").arg(ix).arg(iy); |
199 | }
|
199 | }
|
200 | 200 | ||
201 | if (mRowCoordinates.contains(key)) { |
201 | if (mRowCoordinates.contains(key)) { |
202 | XmlHelper xml(GlobalSettings::instance()->settings()); |
202 | XmlHelper xml(GlobalSettings::instance()->settings()); |
203 | int row = mRowCoordinates[key]; |
203 | int row = mRowCoordinates[key]; |
204 | QString value;
|
204 | QString value;
|
205 | if (logLevelInfo()) qDebug() << "settting up point" << position << "with row" << row; |
205 | if (logLevelInfo()) qDebug() << "settting up point" << position << "with row" << row; |
206 | for (int col=0;col<mInfile->colCount(); col++) { |
206 | for (int col=0;col<mInfile->colCount(); col++) { |
207 | if (mKeys[col]=="id") { |
207 | if (mKeys[col]=="id") { |
208 | mCurrentID = mInfile->value(row, col).toInt(); |
208 | mCurrentID = mInfile->value(row, col).toInt(); |
209 | continue; |
209 | continue; |
210 | }
|
210 | }
|
211 | if (mKeys[col]=="x" || mKeys[col]=="y") // ignore "x" and "y" keys |
211 | if (mKeys[col]=="x" || mKeys[col]=="y") // ignore "x" and "y" keys |
212 | continue; |
212 | continue; |
213 | value = mInfile->value(row,col).toString(); |
213 | value = mInfile->value(row,col).toString(); |
214 | if (logLevelInfo()) qDebug() << "set" << mKeys[col] << "to" << value; |
214 | if (logLevelInfo()) qDebug() << "set" << mKeys[col] << "to" << value; |
215 | xml.setNodeValue(mKeys[col], value); |
215 | xml.setNodeValue(mKeys[col], value); |
216 | // special handling for constructed objects:
|
216 | // special handling for constructed objects:
|
217 | if (mKeys[col]==speciesKey) |
217 | if (mKeys[col]==speciesKey) |
218 | mCurrentSpeciesSet = (SpeciesSet*)mCreatedObjects[value]; |
218 | mCurrentSpeciesSet = (SpeciesSet*)mCreatedObjects[value]; |
219 | if (mKeys[col]==climateKey) { |
219 | if (mKeys[col]==climateKey) { |
220 | mCurrentClimate = (Climate*)mCreatedObjects[value]; |
220 | mCurrentClimate = (Climate*)mCreatedObjects[value]; |
221 | if (mCurrentClimate==0) { |
221 | if (mCurrentClimate==0) { |
222 | // create only those climate sets that are really used in the current landscape
|
222 | // create only those climate sets that are really used in the current landscape
|
223 | Climate *climate = new Climate(); |
223 | Climate *climate = new Climate(); |
224 | mClimate.push_back(climate); |
224 | mClimate.push_back(climate); |
225 | mCreatedObjects[value]=(void*)climate; |
225 | mCreatedObjects[value]=(void*)climate; |
226 | climate->setup(); |
226 | climate->setup(); |
227 | mCurrentClimate = climate; |
227 | mCurrentClimate = climate; |
228 | 228 | ||
229 | }
|
229 | }
|
230 | }
|
230 | }
|
231 | 231 | ||
232 | 232 | ||
233 | }
|
233 | }
|
234 | 234 | ||
235 | } else { |
235 | } else { |
236 | if (mGridMode) |
236 | if (mGridMode) |
237 | throw IException(QString("Environment:setposition: invalid grid id (or not present in input file): %1m/%2m (mapped to id %3).") |
237 | throw IException(QString("Environment:setposition: invalid grid id (or not present in input file): %1m/%2m (mapped to id %3).") |
238 | .arg(position.x()).arg(position.y()).arg(id)); |
238 | .arg(position.x()).arg(position.y()).arg(id)); |
239 | else
|
239 | else
|
240 | throw IException(QString("Environment:setposition: invalid coordinates (or not present in input file): %1m/%2m (mapped to indices %3/%4).") |
240 | throw IException(QString("Environment:setposition: invalid coordinates (or not present in input file): %1m/%2m (mapped to indices %3/%4).") |
241 | .arg(position.x()).arg(position.y()).arg(ix).arg(iy)); |
241 | .arg(position.x()).arg(position.y()).arg(ix).arg(iy)); |
242 | }
|
242 | }
|
243 | }
|
243 | }
|
244 | 244 | ||
245 | bool Environment::setGridMode(const QString &grid_file_name) |
245 | bool Environment::setGridMode(const QString &grid_file_name) |
246 | {
|
246 | {
|
247 | mGrid = new GisGrid(); |
247 | mGrid = new GisGrid(); |
248 | mGrid->loadFromFile(grid_file_name); |
248 | mGrid->loadFromFile(grid_file_name); |
249 | mGridMode = true; |
249 | mGridMode = true; |
250 | return true; |
250 | return true; |
251 | }
|
251 | }
|
252 | 252 |