Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

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