Subversion Repositories public iLand

Rev

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