Subversion Repositories public iLand

Rev

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

Rev 1011 Rev 1064
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
            qDebug() << "creating climatae: " << climateNames;
-
 
-
 
140
            if (logLevelDebug())
-
 
141
                qDebug() << "creating climatae: " << climateNames;
-
 
142
            qDebug() << "Environment: climate: # of climates in environment file:" << climateNames.count();
141
            foreach (QString name, climateNames) {
143
            foreach (QString name, climateNames) {
142
                // create an entry in the list of created objects, but
144
                // create an entry in the list of created objects, but
143
                // really create the climate only if required (see setPosition() )
145
                // really create the climate only if required (see setPosition() )
144
                mCreatedObjects[name]=(void*)0;
146
                mCreatedObjects[name]=(void*)0;
145
                xml.setNodeValue(climateKey,name); // set xml value
147
                xml.setNodeValue(climateKey,name); // set xml value
146
            }
148
            }
147
        } else {
149
        } else {
148
            // no climate defined - setup default climate
150
            // no climate defined - setup default climate
149
            Climate *c = new Climate();
151
            Climate *c = new Climate();
150
            mClimate.push_back(c);
152
            mClimate.push_back(c);
151
            c->setup();
153
            c->setup();
152
            mCurrentClimate = c;
154
            mCurrentClimate = c;
153
        }
155
        }
154
        if (!mCurrentClimate && mClimate.count()>0)
156
        if (!mCurrentClimate && mClimate.count()>0)
155
            mCurrentClimate = mClimate[0];
157
            mCurrentClimate = mClimate[0];
156
        if (!mCurrentSpeciesSet && mSpeciesSets.count()>0)
158
        if (!mCurrentSpeciesSet && mSpeciesSets.count()>0)
157
            mCurrentSpeciesSet = mSpeciesSets[0];
159
            mCurrentSpeciesSet = mSpeciesSets[0];
158
        return true;
160
        return true;
159
161
160
    } catch(const IException &e) {
162
    } catch(const IException &e) {
161
        QString addMsg;
163
        QString addMsg;
162
        if (!mClimate.isEmpty())
164
        if (!mClimate.isEmpty())
163
            addMsg = QString("last Climate: %1 ").arg(mClimate.last()->name());
165
            addMsg = QString("last Climate: %1 ").arg(mClimate.last()->name());
164
        if (!mSpeciesSets.isEmpty())
166
        if (!mSpeciesSets.isEmpty())
165
            addMsg += QString("last Speciesset table: %1").arg(mSpeciesSets.last()->name());
167
            addMsg += QString("last Speciesset table: %1").arg(mSpeciesSets.last()->name());
166
        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);
167
        qDebug() << error_msg;
169
        qDebug() << error_msg;
168
        Helper::msg(error_msg);
170
        Helper::msg(error_msg);
169
        return false;
171
        return false;
170
    }
172
    }
171
}
173
}
172
174
173
/** sets the "pointer" to a "position" (metric coordinates).
175
/** sets the "pointer" to a "position" (metric coordinates).
174
    All specified values are set (also the climate/species-set pointers).
176
    All specified values are set (also the climate/species-set pointers).
175
*/
177
*/
176
void Environment::setPosition(const QPointF position)
178
void Environment::setPosition(const QPointF position)
177
{
179
{
178
    // no changes occur, when the "environment" is not loaded
180
    // no changes occur, when the "environment" is not loaded
179
    if (!isSetup())
181
    if (!isSetup())
180
        return;
182
        return;
181
    QString key;
183
    QString key;
182
    int ix=-1, iy=-1, id=-1;
184
    int ix=-1, iy=-1, id=-1;
183
    if (mGridMode) {
185
    if (mGridMode) {
184
        // grid mode
186
        // grid mode
185
        id = mGrid->value(position);
187
        id = mGrid->value(position);
186
        mCurrentID = id;
188
        mCurrentID = id;
187
        key = QString::number(id);
189
        key = QString::number(id);
188
        if (id==-1)
190
        if (id==-1)
189
            return; // no data for the resource unit
191
            return; // no data for the resource unit
190
    } else {
192
    } else {
191
        // access data in the matrix by resource unit indices
193
        // access data in the matrix by resource unit indices
192
        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
193
        iy = int(position.y() / 100.);
195
        iy = int(position.y() / 100.);
194
        mCurrentID++; // to have Ids for each resource unit
196
        mCurrentID++; // to have Ids for each resource unit
195
197
196
        key=QString("%1_%2").arg(ix).arg(iy);
198
        key=QString("%1_%2").arg(ix).arg(iy);
197
    }
199
    }
198
200
199
    if (mRowCoordinates.contains(key)) {
201
    if (mRowCoordinates.contains(key)) {
200
        XmlHelper xml(GlobalSettings::instance()->settings());
202
        XmlHelper xml(GlobalSettings::instance()->settings());
201
        int row = mRowCoordinates[key];
203
        int row = mRowCoordinates[key];
202
        QString value;
204
        QString value;
203
        if (logLevelInfo()) qDebug() << "settting up point" << position << "with row" << row;
205
        if (logLevelInfo()) qDebug() << "settting up point" << position << "with row" << row;
204
        for (int col=0;col<mInfile->colCount(); col++) {
206
        for (int col=0;col<mInfile->colCount(); col++) {
205
            if (mKeys[col]=="id") {
207
            if (mKeys[col]=="id") {
206
                mCurrentID = mInfile->value(row, col).toInt();
208
                mCurrentID = mInfile->value(row, col).toInt();
207
                continue;
209
                continue;
208
            }
210
            }
209
            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
210
                continue;
212
                continue;
211
            value = mInfile->value(row,col).toString();
213
            value = mInfile->value(row,col).toString();
212
            if (logLevelInfo()) qDebug() << "set" << mKeys[col] << "to" << value;
214
            if (logLevelInfo()) qDebug() << "set" << mKeys[col] << "to" << value;
213
            xml.setNodeValue(mKeys[col], value);
215
            xml.setNodeValue(mKeys[col], value);
214
            // special handling for constructed objects:
216
            // special handling for constructed objects:
215
            if (mKeys[col]==speciesKey)
217
            if (mKeys[col]==speciesKey)
216
                mCurrentSpeciesSet = (SpeciesSet*)mCreatedObjects[value];
218
                mCurrentSpeciesSet = (SpeciesSet*)mCreatedObjects[value];
217
            if (mKeys[col]==climateKey) {
219
            if (mKeys[col]==climateKey) {
218
                mCurrentClimate = (Climate*)mCreatedObjects[value];
220
                mCurrentClimate = (Climate*)mCreatedObjects[value];
219
                if (mCurrentClimate==0) {
221
                if (mCurrentClimate==0) {
220
                    // 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
221
                    Climate *climate = new Climate();
223
                    Climate *climate = new Climate();
222
                    mClimate.push_back(climate);
224
                    mClimate.push_back(climate);
223
                    mCreatedObjects[value]=(void*)climate;
225
                    mCreatedObjects[value]=(void*)climate;
224
                    climate->setup();
226
                    climate->setup();
225
                    mCurrentClimate = climate;
227
                    mCurrentClimate = climate;
226
228
227
                }
229
                }
228
            }
230
            }
229
231
230
232
231
        }
233
        }
232
234
233
    } else {
235
    } else {
234
        if (mGridMode)
236
        if (mGridMode)
235
            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).")
236
                             .arg(position.x()).arg(position.y()).arg(id));
238
                             .arg(position.x()).arg(position.y()).arg(id));
237
        else
239
        else
238
            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).")
239
                             .arg(position.x()).arg(position.y()).arg(ix).arg(iy));
241
                             .arg(position.x()).arg(position.y()).arg(ix).arg(iy));
240
    }
242
    }
241
}
243
}
242
244
243
bool Environment::setGridMode(const QString &grid_file_name)
245
bool Environment::setGridMode(const QString &grid_file_name)
244
{
246
{
245
    mGrid = new GisGrid();
247
    mGrid = new GisGrid();
246
    mGrid->loadFromFile(grid_file_name);
248
    mGrid->loadFromFile(grid_file_name);
247
    mGridMode = true;
249
    mGridMode = true;
248
    return true;
250
    return true;
249
}
251
}
250
 
252