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