Subversion Repositories public iLand

Rev

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

Rev 393 Rev 431
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/standloader.cpp':
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/standloader.cpp':
2
#include "global.h"
2
#include "global.h"
3
#include "standloader.h"
3
#include "standloader.h"
4
4
5
5
6
#include "grid.h"
6
#include "grid.h"
7
#include "model.h"
7
#include "model.h"
8
#include "resourceunit.h"
8
#include "resourceunit.h"
9
#include "speciesset.h"
9
#include "speciesset.h"
10
10
11
#include "helper.h"
11
#include "helper.h"
12
#include "random.h"
12
#include "random.h"
13
#include "expression.h"
13
#include "expression.h"
14
#include "expressionwrapper.h"
14
#include "expressionwrapper.h"
15
#include "environment.h"
15
#include "environment.h"
16
#include "csvfile.h"
16
#include "csvfile.h"
17
17
18
// provide a mapping between "Picus"-style and "iLand"-style species Ids
18
// provide a mapping between "Picus"-style and "iLand"-style species Ids
19
QVector<int> picusSpeciesIds = QVector<int>() << 0 << 1 << 17;
19
QVector<int> picusSpeciesIds = QVector<int>() << 0 << 1 << 17;
20
QStringList iLandSpeciesIds = QStringList() << "piab" << "piab" << "fasy";
20
QStringList iLandSpeciesIds = QStringList() << "piab" << "piab" << "fasy";
21
StandLoader::~StandLoader()
21
StandLoader::~StandLoader()
22
{
22
{
23
    if (mRandom)
23
    if (mRandom)
24
        delete mRandom;
24
        delete mRandom;
25
}
25
}
26
26
27
27
28
void StandLoader::copyTrees()
28
void StandLoader::copyTrees()
29
{
29
{
30
    // we assume that all stands are equal, so wie simply COPY the trees and modify them afterwards
30
    // we assume that all stands are equal, so wie simply COPY the trees and modify them afterwards
31
    const Grid<ResourceUnit*> &ruGrid=mModel->RUgrid();
31
    const Grid<ResourceUnit*> &ruGrid=mModel->RUgrid();
32
    ResourceUnit **p = ruGrid.begin();
32
    ResourceUnit **p = ruGrid.begin();
33
    if (!p)
33
    if (!p)
34
        throw IException("Standloader: invalid resource unit pointer!");
34
        throw IException("Standloader: invalid resource unit pointer!");
35
    ++p; // skip the first...
35
    ++p; // skip the first...
36
    const QVector<Tree> &tocopy = mModel->ru()->trees();
36
    const QVector<Tree> &tocopy = mModel->ru()->trees();
37
    for (; p!=ruGrid.end(); ++p) {
37
    for (; p!=ruGrid.end(); ++p) {
38
        QRectF rect = (*p)->boundingBox();
38
        QRectF rect = (*p)->boundingBox();
39
        foreach(const Tree& tree, tocopy) {
39
        foreach(const Tree& tree, tocopy) {
40
            Tree &newtree = (*p)->newTree();
40
            Tree &newtree = (*p)->newTree();
41
            newtree = tree; // copy tree data...
41
            newtree = tree; // copy tree data...
42
            newtree.setPosition(tree.position()+(*p)->boundingBox().topLeft());
42
            newtree.setPosition(tree.position()+(*p)->boundingBox().topLeft());
43
            newtree.setRU(*p);
43
            newtree.setRU(*p);
44
            newtree.setNewId();
44
            newtree.setNewId();
45
        }
45
        }
46
    }
46
    }
47
    qDebug() << Tree::statCreated() << "trees loaded / copied.";
-
 
-
 
47
    if (logLevelInfo()) qDebug() << Tree::statCreated() << "trees loaded / copied.";
48
}
48
}
49
49
50
/** main routine of the stand setup.
50
/** main routine of the stand setup.
51
*/
51
*/
52
void StandLoader::processInit()
52
void StandLoader::processInit()
53
{
53
{
54
    GlobalSettings *g = GlobalSettings::instance();
54
    GlobalSettings *g = GlobalSettings::instance();
55
    XmlHelper xml(g->settings().node("model.initialization"));
55
    XmlHelper xml(g->settings().node("model.initialization"));
56
56
57
    QString copy_mode = xml.value("mode", "copy");
57
    QString copy_mode = xml.value("mode", "copy");
58
    QString type = xml.value("type", "");
58
    QString type = xml.value("type", "");
59
    QString  fileName = xml.value("file", "");
59
    QString  fileName = xml.value("file", "");
60
60
61
    Tree::resetStatistics();
61
    Tree::resetStatistics();
62
62
63
    // one global init-file for the whole area:
63
    // one global init-file for the whole area:
64
    if (copy_mode=="single") {
64
    if (copy_mode=="single") {
65
        loadInitFile(fileName, type);
65
        loadInitFile(fileName, type);
66
        evaluateDebugTrees();
66
        evaluateDebugTrees();
67
        return;
67
        return;
68
    }
68
    }
69
69
70
    // copy trees from first unit to all other units:
70
    // copy trees from first unit to all other units:
71
    if (copy_mode=="copy") {
71
    if (copy_mode=="copy") {
72
        loadInitFile(fileName, type);
72
        loadInitFile(fileName, type);
73
        copyTrees();
73
        copyTrees();
74
        evaluateDebugTrees();
74
        evaluateDebugTrees();
75
        return;
75
        return;
76
    }
76
    }
77
77
78
    // call a single tree init for each resource unit
78
    // call a single tree init for each resource unit
79
    if (copy_mode=="unit") {
79
    if (copy_mode=="unit") {
80
        foreach( const ResourceUnit *const_ru, g->model()->ruList()) {
80
        foreach( const ResourceUnit *const_ru, g->model()->ruList()) {
81
            ResourceUnit *ru = const_cast<ResourceUnit*>(const_ru);
81
            ResourceUnit *ru = const_cast<ResourceUnit*>(const_ru);
82
            // set environment
82
            // set environment
83
            g->model()->environment()->setPosition(ru->boundingBox().center());
83
            g->model()->environment()->setPosition(ru->boundingBox().center());
84
            type = xml.value("type", "");
84
            type = xml.value("type", "");
85
            fileName = xml.value("file", "");
85
            fileName = xml.value("file", "");
86
            if (fileName.isEmpty())
86
            if (fileName.isEmpty())
87
                continue;
87
                continue;
88
            loadInitFile(fileName, type, ru);
88
            loadInitFile(fileName, type, ru);
89
            qDebug() << "loaded" << fileName << "on" << ru->boundingBox() << "," << ru->trees().count() << "trees.";
-
 
-
 
89
            if (logLevelInfo()) qDebug() << "loaded" << fileName << "on" << ru->boundingBox() << "," << ru->trees().count() << "trees.";
90
        }
90
        }
91
        evaluateDebugTrees();
91
        evaluateDebugTrees();
92
        return;
92
        return;
93
    }
93
    }
94
94
95
    throw IException("StandLoader::processInit: invalid initalization.mode!");
95
    throw IException("StandLoader::processInit: invalid initalization.mode!");
96
}
96
}
97
97
98
void StandLoader::evaluateDebugTrees()
98
void StandLoader::evaluateDebugTrees()
99
{
99
{
100
    // evaluate debugging
100
    // evaluate debugging
101
    QString dbg_str = GlobalSettings::instance()->settings().paramValueString("debug_tree");
101
    QString dbg_str = GlobalSettings::instance()->settings().paramValueString("debug_tree");
102
    int counter=0;
102
    int counter=0;
103
    if (!dbg_str.isEmpty()) {
103
    if (!dbg_str.isEmpty()) {
104
       TreeWrapper tw;
104
       TreeWrapper tw;
105
       Expression dexp(dbg_str, &tw); // load expression dbg_str and enable external model variables
105
       Expression dexp(dbg_str, &tw); // load expression dbg_str and enable external model variables
106
        AllTreeIterator at(GlobalSettings::instance()->model());
106
        AllTreeIterator at(GlobalSettings::instance()->model());
107
        double result;
107
        double result;
108
        while (Tree *t = at.next()) {
108
        while (Tree *t = at.next()) {
109
            tw.setTree(t);
109
            tw.setTree(t);
110
            result = dexp.execute();
110
            result = dexp.execute();
111
            if (result) {
111
            if (result) {
112
                t->enableDebugging();
112
                t->enableDebugging();
113
                counter++;
113
                counter++;
114
            }
114
            }
115
        }
115
        }
116
    }
116
    }
117
    qDebug() << "evaluateDebugTrees: enabled debugging for" << counter << "trees.";
117
    qDebug() << "evaluateDebugTrees: enabled debugging for" << counter << "trees.";
118
}
118
}
119
119
120
int StandLoader::loadInitFile(const QString &fileName, const QString &type, ResourceUnit *ru)
120
int StandLoader::loadInitFile(const QString &fileName, const QString &type, ResourceUnit *ru)
121
{
121
{
122
    QString pathFileName = GlobalSettings::instance()->path(fileName, "init");
122
    QString pathFileName = GlobalSettings::instance()->path(fileName, "init");
123
    if (!QFile::exists(pathFileName))
123
    if (!QFile::exists(pathFileName))
124
        throw IException(QString("StandLoader::loadInitFile: File %1 does not exist!").arg(pathFileName));
124
        throw IException(QString("StandLoader::loadInitFile: File %1 does not exist!").arg(pathFileName));
125
125
126
    if (type=="picus" || type=="single")
126
    if (type=="picus" || type=="single")
127
        return loadPicusFile(pathFileName, ru);
127
        return loadPicusFile(pathFileName, ru);
128
    if (type=="iland" || type=="distribution")
128
    if (type=="iland" || type=="distribution")
129
        return loadiLandFile(pathFileName, ru);
129
        return loadiLandFile(pathFileName, ru);
130
130
131
    throw IException(QLatin1String("StandLoader::loadInitFile: unknown initalization.type:")+type);
131
    throw IException(QLatin1String("StandLoader::loadInitFile: unknown initalization.type:")+type);
132
}
132
}
133
133
134
int StandLoader::loadPicusFile(const QString &fileName, ResourceUnit *ru)
134
int StandLoader::loadPicusFile(const QString &fileName, ResourceUnit *ru)
135
{
135
{
136
    QString content = Helper::loadTextFile(fileName);
136
    QString content = Helper::loadTextFile(fileName);
137
    if (content.isEmpty()) {
137
    if (content.isEmpty()) {
138
        qDebug() << "file not found: " + fileName;
138
        qDebug() << "file not found: " + fileName;
139
        return 0;
139
        return 0;
140
    }
140
    }
141
    return loadSingleTreeList(content, ru, fileName);
141
    return loadSingleTreeList(content, ru, fileName);
142
}
142
}
143
143
144
/** load a list of trees (given by content) to a resource unit. Param fileName is just for error reporting.
144
/** load a list of trees (given by content) to a resource unit. Param fileName is just for error reporting.
145
  returns the number of loaded trees.
145
  returns the number of loaded trees.
146
  */
146
  */
147
int StandLoader::loadSingleTreeList(const QString &content, ResourceUnit *ru, const QString &fileName)
147
int StandLoader::loadSingleTreeList(const QString &content, ResourceUnit *ru, const QString &fileName)
148
{
148
{
149
    if (!ru)
149
    if (!ru)
150
        ru = mModel->ru();
150
        ru = mModel->ru();
151
    Q_ASSERT(ru!=0);
151
    Q_ASSERT(ru!=0);
152
152
153
    QPointF offset = ru->boundingBox().topLeft();
153
    QPointF offset = ru->boundingBox().topLeft();
154
    SpeciesSet *speciesSet = ru->speciesSet(); // of default RU
154
    SpeciesSet *speciesSet = ru->speciesSet(); // of default RU
155
155
156
    QString my_content(content);
156
    QString my_content(content);
157
    // cut out the <trees> </trees> part if present
157
    // cut out the <trees> </trees> part if present
158
    if (content.contains("<trees>")) {
158
    if (content.contains("<trees>")) {
159
        QRegExp rx(".*<trees>(.*)</trees>.*");
159
        QRegExp rx(".*<trees>(.*)</trees>.*");
160
        rx.indexIn(content, 0);
160
        rx.indexIn(content, 0);
161
        if (rx.capturedTexts().count()<1)
161
        if (rx.capturedTexts().count()<1)
162
            return 0;
162
            return 0;
163
        my_content = rx.cap(1).trimmed();
163
        my_content = rx.cap(1).trimmed();
164
    }
164
    }
165
165
166
    QStringList lines=my_content.split('\n');
166
    QStringList lines=my_content.split('\n');
167
    if (lines.count()<2)
167
    if (lines.count()<2)
168
        return 0;
168
        return 0;
169
    // drop comments
169
    // drop comments
170
    while (!lines.isEmpty() && lines.front().startsWith('#') )
170
    while (!lines.isEmpty() && lines.front().startsWith('#') )
171
        lines.pop_front();
171
        lines.pop_front();
172
    while (!lines.isEmpty() && lines.last().isEmpty())
172
    while (!lines.isEmpty() && lines.last().isEmpty())
173
        lines.removeLast();
173
        lines.removeLast();
174
174
175
    char sep='\t';
175
    char sep='\t';
176
    if (!lines[0].contains(sep))
176
    if (!lines[0].contains(sep))
177
        sep=';';
177
        sep=';';
178
    QStringList headers = lines[0].trimmed().split(sep);
178
    QStringList headers = lines[0].trimmed().split(sep);
179
179
180
    int iID = headers.indexOf("id");
180
    int iID = headers.indexOf("id");
181
    int iX = headers.indexOf("x");
181
    int iX = headers.indexOf("x");
182
    int iY = headers.indexOf("y");
182
    int iY = headers.indexOf("y");
183
    int iBhd = headers.indexOf("bhdfrom");
183
    int iBhd = headers.indexOf("bhdfrom");
184
    if (iBhd<0)
184
    if (iBhd<0)
185
        iBhd = headers.indexOf("dbh");
185
        iBhd = headers.indexOf("dbh");
186
    double height_conversion = 100.;
186
    double height_conversion = 100.;
187
    int iHeight = headers.indexOf("treeheight");
187
    int iHeight = headers.indexOf("treeheight");
188
    if (iHeight<0) {
188
    if (iHeight<0) {
189
        iHeight = headers.indexOf("height");
189
        iHeight = headers.indexOf("height");
190
        height_conversion = 1.; // in meter
190
        height_conversion = 1.; // in meter
191
    }
191
    }
192
    int iSpecies = headers.indexOf("species");
192
    int iSpecies = headers.indexOf("species");
193
    int iAge = headers.indexOf("age");
193
    int iAge = headers.indexOf("age");
194
    if (iX==-1 || iY==-1 || iBhd==-1 || iSpecies==-1 || iHeight==-1)
194
    if (iX==-1 || iY==-1 || iBhd==-1 || iSpecies==-1 || iHeight==-1)
195
        throw IException(QString("Initfile %1 is not valid!\nObligatory columns are: x,y, bhdfrom or dbh, species, treeheight or height.").arg(fileName));
195
        throw IException(QString("Initfile %1 is not valid!\nObligatory columns are: x,y, bhdfrom or dbh, species, treeheight or height.").arg(fileName));
196
196
197
    double dbh;
197
    double dbh;
198
    bool ok;
198
    bool ok;
199
    int cnt=0;
199
    int cnt=0;
200
    QString speciesid;
200
    QString speciesid;
201
    for (int i=1;i<lines.count();i++) {
201
    for (int i=1;i<lines.count();i++) {
202
        QString &line = lines[i];
202
        QString &line = lines[i];
203
        dbh = line.section(sep, iBhd, iBhd).toDouble();
203
        dbh = line.section(sep, iBhd, iBhd).toDouble();
204
        if (dbh<5.)
204
        if (dbh<5.)
205
            continue;
205
            continue;
206
206
207
        QPointF f;
207
        QPointF f;
208
        if (iX>=0 && iY>=0) {
208
        if (iX>=0 && iY>=0) {
209
           f.setX( line.section(sep, iX, iX).toDouble() );
209
           f.setX( line.section(sep, iX, iX).toDouble() );
210
           f.setY( line.section(sep, iY, iY).toDouble() );
210
           f.setY( line.section(sep, iY, iY).toDouble() );
211
           f+=offset;
211
           f+=offset;
212
212
213
        }
213
        }
214
        // position valid?
214
        // position valid?
215
        if (!mModel->heightGrid()->valueAt(f).isValid())
215
        if (!mModel->heightGrid()->valueAt(f).isValid())
216
            continue;
216
            continue;
217
        Tree &tree = ru->newTree();
217
        Tree &tree = ru->newTree();
218
        tree.setPosition(f);
218
        tree.setPosition(f);
219
        if (iID>=0)
219
        if (iID>=0)
220
            tree.setId(line.section(sep, iID, iID).toInt() );
220
            tree.setId(line.section(sep, iID, iID).toInt() );
221
221
222
        tree.setDbh(dbh);
222
        tree.setDbh(dbh);
223
        tree.setHeight(line.section(sep, iHeight, iHeight).toDouble()/height_conversion); // convert from Picus-cm to m if necessary
223
        tree.setHeight(line.section(sep, iHeight, iHeight).toDouble()/height_conversion); // convert from Picus-cm to m if necessary
224
224
225
        speciesid = line.section(sep, iSpecies, iSpecies).trimmed();
225
        speciesid = line.section(sep, iSpecies, iSpecies).trimmed();
226
        int picusid = speciesid.toInt(&ok);
226
        int picusid = speciesid.toInt(&ok);
227
        if (ok) {
227
        if (ok) {
228
            int idx = picusSpeciesIds.indexOf(picusid);
228
            int idx = picusSpeciesIds.indexOf(picusid);
229
            if (idx==-1)
229
            if (idx==-1)
230
                throw IException(QString("Loading init-file: invalid Picus-species-id. Species: %1").arg(picusid));
230
                throw IException(QString("Loading init-file: invalid Picus-species-id. Species: %1").arg(picusid));
231
            speciesid = iLandSpeciesIds[idx];
231
            speciesid = iLandSpeciesIds[idx];
232
        }
232
        }
233
        Species *s = speciesSet->species(speciesid);
233
        Species *s = speciesSet->species(speciesid);
234
        if (!ru || !s)
234
        if (!ru || !s)
235
            throw IException(QString("Loading init-file: either resource unit or species invalid. Species: %1").arg(speciesid));
235
            throw IException(QString("Loading init-file: either resource unit or species invalid. Species: %1").arg(speciesid));
236
        tree.setSpecies(s);
236
        tree.setSpecies(s);
237
237
238
        ok = true;
238
        ok = true;
239
        if (iAge>=0)
239
        if (iAge>=0)
240
           tree.setAge(line.section(sep, iAge, iAge).toInt(&ok), tree.height()); // this is a *real* age
240
           tree.setAge(line.section(sep, iAge, iAge).toInt(&ok), tree.height()); // this is a *real* age
241
        if (iAge<0 || !ok || tree.age()==0)
241
        if (iAge<0 || !ok || tree.age()==0)
242
           tree.setAge(0, tree.height()); // no real tree age available
242
           tree.setAge(0, tree.height()); // no real tree age available
243
243
244
        tree.setRU(ru);
244
        tree.setRU(ru);
245
        tree.setup();
245
        tree.setup();
246
        cnt++;
246
        cnt++;
247
    }
247
    }
248
    return cnt;
248
    return cnt;
249
    //qDebug() << "loaded init-file contained" << lines.count() <<"lines.";
249
    //qDebug() << "loaded init-file contained" << lines.count() <<"lines.";
250
    //qDebug() << "lines: " << lines;
250
    //qDebug() << "lines: " << lines;
251
}
251
}
252
252
253
/** initialize trees on a resource unit based on dbh distributions.
253
/** initialize trees on a resource unit based on dbh distributions.
254
  use a fairly clever algorithm to determine tree positions.
254
  use a fairly clever algorithm to determine tree positions.
255
  see http://iland.boku.ac.at/initialize+trees
255
  see http://iland.boku.ac.at/initialize+trees
256
  @param content tree init file (including headers) in a string
256
  @param content tree init file (including headers) in a string
257
  @param ru resource unit
257
  @param ru resource unit
258
  @param fileName source file name (for error reporting)
258
  @param fileName source file name (for error reporting)
259
  @return number of trees added
259
  @return number of trees added
260
  */
260
  */
261
int StandLoader::loadDistributionList(const QString &content, ResourceUnit *ru, const QString &fileName)
261
int StandLoader::loadDistributionList(const QString &content, ResourceUnit *ru, const QString &fileName)
262
{
262
{
263
    if (!ru)
263
    if (!ru)
264
        ru = mModel->ru();
264
        ru = mModel->ru();
265
    Q_ASSERT(ru!=0);
265
    Q_ASSERT(ru!=0);
266
    SpeciesSet *speciesSet = ru->speciesSet(); // of default RU
266
    SpeciesSet *speciesSet = ru->speciesSet(); // of default RU
267
    Q_ASSERT(speciesSet!=0);
267
    Q_ASSERT(speciesSet!=0);
268
268
269
    DebugTimer t("StandLoader::loadiLandFile");
-
 
-
 
269
    //DebugTimer t("StandLoader::loadiLandFile");
270
    CSVFile infile;
270
    CSVFile infile;
271
    infile.loadFromString(content);
271
    infile.loadFromString(content);
272
272
273
    int icount = infile.columnIndex("count");
273
    int icount = infile.columnIndex("count");
274
    int ispecies = infile.columnIndex("species");
274
    int ispecies = infile.columnIndex("species");
275
    int idbh_from = infile.columnIndex("dbh_from");
275
    int idbh_from = infile.columnIndex("dbh_from");
276
    int idbh_to = infile.columnIndex("dbh_to");
276
    int idbh_to = infile.columnIndex("dbh_to");
277
    int ihd = infile.columnIndex("hd");
277
    int ihd = infile.columnIndex("hd");
278
    int iage = infile.columnIndex("age");
278
    int iage = infile.columnIndex("age");
279
    int idensity = infile.columnIndex("density");
279
    int idensity = infile.columnIndex("density");
280
    if (icount<0 || ispecies<0 || idbh_from<0 || idbh_to<0 || ihd<0 || iage<0)
280
    if (icount<0 || ispecies<0 || idbh_from<0 || idbh_to<0 || ihd<0 || iage<0)
281
        throw IException(QString("load-ini-file: file '%1' containts not all required fields (count, species, dbh_from, dbh_to, hd, age).").arg(fileName));
281
        throw IException(QString("load-ini-file: file '%1' containts not all required fields (count, species, dbh_from, dbh_to, hd, age).").arg(fileName));
282
282
283
    mInitItems.clear();
283
    mInitItems.clear();
284
    InitFileItem item;
284
    InitFileItem item;
285
    bool ok;
285
    bool ok;
286
    int total_count = 0;
286
    int total_count = 0;
287
    for (int row=0;row<infile.rowCount();row++) {
287
    for (int row=0;row<infile.rowCount();row++) {
288
         item.count = infile.value(row, icount).toInt();
288
         item.count = infile.value(row, icount).toInt();
289
         total_count += item.count;
289
         total_count += item.count;
290
         item.dbh_from = infile.value(row, idbh_from).toDouble();
290
         item.dbh_from = infile.value(row, idbh_from).toDouble();
291
         item.dbh_to = infile.value(row, idbh_to).toDouble();
291
         item.dbh_to = infile.value(row, idbh_to).toDouble();
292
         item.hd = infile.value(row, ihd).toDouble();
292
         item.hd = infile.value(row, ihd).toDouble();
293
         ok = true;
293
         ok = true;
294
         if (iage>=0)
294
         if (iage>=0)
295
             item.age = infile.value(row, iage).toInt(&ok);
295
             item.age = infile.value(row, iage).toInt(&ok);
296
         if (iage<0 || !ok)
296
         if (iage<0 || !ok)
297
             item.age = 0;
297
             item.age = 0;
298
298
299
         item.species = speciesSet->species(infile.value(row, ispecies).toString());
299
         item.species = speciesSet->species(infile.value(row, ispecies).toString());
300
         if (idensity>=0)
300
         if (idensity>=0)
301
             item.density = infile.value(row, idensity).toDouble();
301
             item.density = infile.value(row, idensity).toDouble();
302
         else
302
         else
303
             item.density = 0.;
303
             item.density = 0.;
304
         if (item.density<-1 || item.density>1)
304
         if (item.density<-1 || item.density>1)
305
             throw IException(QString("load-ini-file: invalid value for density. Allowed range is -1..1: '%1' in file '%2', line %3.")
305
             throw IException(QString("load-ini-file: invalid value for density. Allowed range is -1..1: '%1' in file '%2', line %3.")
306
                              .arg(item.density)
306
                              .arg(item.density)
307
                              .arg(fileName)
307
                              .arg(fileName)
308
                              .arg(row));
308
                              .arg(row));
309
         if (!item.species) {
309
         if (!item.species) {
310
             throw IException(QString("load-ini-file: unknown speices '%1' in file '%2', line %3.")
310
             throw IException(QString("load-ini-file: unknown speices '%1' in file '%2', line %3.")
311
                              .arg(infile.value(row, ispecies).toString())
311
                              .arg(infile.value(row, ispecies).toString())
312
                              .arg(fileName)
312
                              .arg(fileName)
313
                              .arg(row));
313
                              .arg(row));
314
         }
314
         }
315
         mInitItems.push_back(item);
315
         mInitItems.push_back(item);
316
    }
316
    }
317
    // setup the random distribution
317
    // setup the random distribution
318
    QString density_func = GlobalSettings::instance()->settings().value("model.initialization.randomFunction", "1-x^2");
318
    QString density_func = GlobalSettings::instance()->settings().value("model.initialization.randomFunction", "1-x^2");
319
    qDebug() << "density function:" << density_func;
-
 
-
 
319
    if (logLevelInfo())  qDebug() << "density function:" << density_func;
320
    if (!mRandom || (mRandom->densityFunction()!= density_func)) {
320
    if (!mRandom || (mRandom->densityFunction()!= density_func)) {
321
        if (mRandom)
321
        if (mRandom)
322
            delete mRandom;
322
            delete mRandom;
323
        mRandom=new RandomCustomPDF(density_func);
323
        mRandom=new RandomCustomPDF(density_func);
324
        qDebug() << "new probabilty density function:" << density_func;
-
 
-
 
324
        if (logLevelInfo()) qDebug() << "new probabilty density function:" << density_func;
325
    }
325
    }
326
326
327
    // exeucte the
327
    // exeucte the
328
    executeiLandInit(ru);
328
    executeiLandInit(ru);
329
    ru->cleanTreeList();
329
    ru->cleanTreeList();
330
    return total_count;
330
    return total_count;
331
331
332
}
332
}
333
333
334
int StandLoader::loadiLandFile(const QString &fileName, ResourceUnit *ru)
334
int StandLoader::loadiLandFile(const QString &fileName, ResourceUnit *ru)
335
{
335
{
336
    if (!QFile::exists(fileName))
336
    if (!QFile::exists(fileName))
337
        throw IException(QString("load-ini-file: file '%1' does not exist.").arg(fileName));
337
        throw IException(QString("load-ini-file: file '%1' does not exist.").arg(fileName));
338
    QString content = Helper::loadTextFile(fileName);
338
    QString content = Helper::loadTextFile(fileName);
339
    return loadDistributionList(content, ru, fileName);
339
    return loadDistributionList(content, ru, fileName);
340
}
340
}
341
341
342
// evenlist: tentative order of pixel-indices (within a 5x5 grid) used as tree positions.
342
// evenlist: tentative order of pixel-indices (within a 5x5 grid) used as tree positions.
343
// e.g. 12 = centerpixel, 0: upper left corner, ...
343
// e.g. 12 = centerpixel, 0: upper left corner, ...
344
int evenlist[25] = { 12, 6, 18, 16, 8, 22, 2, 10, 14, 0, 24, 20, 4,
344
int evenlist[25] = { 12, 6, 18, 16, 8, 22, 2, 10, 14, 0, 24, 20, 4,
345
                     1, 13, 15, 19, 21, 3, 7, 11, 17, 23, 5, 9};
345
                     1, 13, 15, 19, 21, 3, 7, 11, 17, 23, 5, 9};
346
int unevenlist[25] = { 11,13,7,17, 1,19,5,21, 9,23,3,15,
346
int unevenlist[25] = { 11,13,7,17, 1,19,5,21, 9,23,3,15,
347
                       6,18,2,10,4,24,12,0,8,14,20,22};
347
                       6,18,2,10,4,24,12,0,8,14,20,22};
348
348
349
349
350
// sort function
350
// sort function
351
bool sortPairLessThan(const QPair<int, double> &s1, const QPair<int, double> &s2)
351
bool sortPairLessThan(const QPair<int, double> &s1, const QPair<int, double> &s2)
352
{
352
{
353
    return s1.second < s2.second;
353
    return s1.second < s2.second;
354
}
354
}
355
355
356
/**
356
/**
357
*/
357
*/
358
void StandLoader::executeiLandInit(ResourceUnit *ru)
358
void StandLoader::executeiLandInit(ResourceUnit *ru)
359
{
359
{
360
360
361
    QPointF offset = ru->boundingBox().topLeft();
361
    QPointF offset = ru->boundingBox().topLeft();
362
    QPoint offsetIdx = GlobalSettings::instance()->model()->grid()->indexAt(offset);
362
    QPoint offsetIdx = GlobalSettings::instance()->model()->grid()->indexAt(offset);
363
363
364
    // a multimap holds a list for all trees.
364
    // a multimap holds a list for all trees.
365
    // key is the index of a 10x10m pixel within the resource unit
365
    // key is the index of a 10x10m pixel within the resource unit
366
    QMultiMap<int, int> tree_map;
366
    QMultiMap<int, int> tree_map;
367
    QVector<QPair<int, double> > tcount; // counts
367
    QVector<QPair<int, double> > tcount; // counts
368
    for (int i=0;i<100;i++)
368
    for (int i=0;i<100;i++)
369
        tcount.push_back(QPair<int,double>(i,0.));
369
        tcount.push_back(QPair<int,double>(i,0.));
370
370
371
    int key;
371
    int key;
372
    double rand_val, rand_fraction;
372
    double rand_val, rand_fraction;
373
    int total_count = 0;
373
    int total_count = 0;
374
    foreach(const InitFileItem &item, mInitItems) {
374
    foreach(const InitFileItem &item, mInitItems) {
375
        rand_fraction = fabs(double(item.density));
375
        rand_fraction = fabs(double(item.density));
376
        for (int i=0;i<item.count;i++) {
376
        for (int i=0;i<item.count;i++) {
377
            // create trees
377
            // create trees
378
            int tree_idx = ru->newTreeIndex();
378
            int tree_idx = ru->newTreeIndex();
379
            Tree &tree = ru->trees()[tree_idx]; // get reference to modify tree
379
            Tree &tree = ru->trees()[tree_idx]; // get reference to modify tree
380
            tree.setDbh(nrandom(item.dbh_from, item.dbh_to));
380
            tree.setDbh(nrandom(item.dbh_from, item.dbh_to));
381
            tree.setHeight(tree.dbh()/100. * item.hd); // dbh from cm->m, *hd-ratio -> meter height
381
            tree.setHeight(tree.dbh()/100. * item.hd); // dbh from cm->m, *hd-ratio -> meter height
382
            tree.setSpecies(item.species);
382
            tree.setSpecies(item.species);
383
            if (item.age<=0)
383
            if (item.age<=0)
384
                tree.setAge(0,tree.height());
384
                tree.setAge(0,tree.height());
385
            else
385
            else
386
                tree.setAge(item.age, tree.height());
386
                tree.setAge(item.age, tree.height());
387
            tree.setRU(ru);
387
            tree.setRU(ru);
388
            tree.setup();
388
            tree.setup();
389
            total_count++;
389
            total_count++;
390
390
391
            // calculate random value. "density" is from 1..-1.
391
            // calculate random value. "density" is from 1..-1.
392
            rand_val = mRandom->get();
392
            rand_val = mRandom->get();
393
            if (item.density<0)
393
            if (item.density<0)
394
                rand_val = 1. - rand_val;
394
                rand_val = 1. - rand_val;
395
            rand_val = rand_val * rand_fraction + drandom()*(1.-rand_fraction);
395
            rand_val = rand_val * rand_fraction + drandom()*(1.-rand_fraction);
396
396
397
            // key: rank of target pixel
397
            // key: rank of target pixel
398
            // first: index of target pixel
398
            // first: index of target pixel
399
            // second: sum of target pixel
399
            // second: sum of target pixel
400
            key = limit(int(100*rand_val), 0, 99); // get from random number generator
400
            key = limit(int(100*rand_val), 0, 99); // get from random number generator
401
            tree_map.insert(tcount[key].first, tree_idx); // store tree in map
401
            tree_map.insert(tcount[key].first, tree_idx); // store tree in map
402
            tcount[key].second+=tree.basalArea(); // aggregate the basal area for each 10m pixel
402
            tcount[key].second+=tree.basalArea(); // aggregate the basal area for each 10m pixel
403
            if ( (total_count < 20 && i%2==0)
403
            if ( (total_count < 20 && i%2==0)
404
                || (total_count<100 && i%10==0 )
404
                || (total_count<100 && i%10==0 )
405
                || (i%30==0) ) {
405
                || (i%30==0) ) {
406
                qSort(tcount.begin(), tcount.end(), sortPairLessThan);
406
                qSort(tcount.begin(), tcount.end(), sortPairLessThan);
407
            }
407
            }
408
        }
408
        }
409
        qSort(tcount.begin(), tcount.end(), sortPairLessThan);
409
        qSort(tcount.begin(), tcount.end(), sortPairLessThan);
410
    }
410
    }
411
411
412
    int bits, index, pos;
412
    int bits, index, pos;
413
    int c;
413
    int c;
414
    QList<int> trees;
414
    QList<int> trees;
415
    QPoint tree_pos;
415
    QPoint tree_pos;
416
416
417
    for (int i=0;i<100;i++) {
417
    for (int i=0;i<100;i++) {
418
        trees = tree_map.values(i);
418
        trees = tree_map.values(i);
419
        c = trees.count();
419
        c = trees.count();
420
        QPointF pixel_center = ru->boundingBox().topLeft() + QPointF((i/10)*10. + 5., (i%10)*10. + 5.);
420
        QPointF pixel_center = ru->boundingBox().topLeft() + QPointF((i/10)*10. + 5., (i%10)*10. + 5.);
421
        if (!mModel->heightGrid()->valueAt(pixel_center).isValid()) {
421
        if (!mModel->heightGrid()->valueAt(pixel_center).isValid()) {
422
            // no trees on that pixel: let trees die
422
            // no trees on that pixel: let trees die
423
            foreach(int tree_idx, trees) {
423
            foreach(int tree_idx, trees) {
424
                ru->trees()[tree_idx].die();
424
                ru->trees()[tree_idx].die();
425
            }
425
            }
426
            continue;
426
            continue;
427
        }
427
        }
428
428
429
        bits = 0;
429
        bits = 0;
430
        index = -1;
430
        index = -1;
431
        double r;
431
        double r;
432
        foreach(int tree_idx, trees) {
432
        foreach(int tree_idx, trees) {
433
            if (c>18) {
433
            if (c>18) {
434
                index = (index + 1)%25;
434
                index = (index + 1)%25;
435
            } else {
435
            } else {
436
                int stop=1000;
436
                int stop=1000;
437
                index = 0;
437
                index = 0;
438
                do {
438
                do {
439
                    //r = drandom();
439
                    //r = drandom();
440
                    //if (r<0.5)  // skip position with a prob. of 50% -> adds a little "noise"
440
                    //if (r<0.5)  // skip position with a prob. of 50% -> adds a little "noise"
441
                    //    index++;
441
                    //    index++;
442
                    //index = (index + 1)%25; // increase and roll over
442
                    //index = (index + 1)%25; // increase and roll over
443
443
444
                    // search a random position
444
                    // search a random position
445
                    r = drandom();
445
                    r = drandom();
446
                    index = limit(int(25 *  r*r), 0, 24); // use rnd()^2 to search for locations -> higher number of low indices (i.e. 50% of lookups in first 25% of locations)
446
                    index = limit(int(25 *  r*r), 0, 24); // use rnd()^2 to search for locations -> higher number of low indices (i.e. 50% of lookups in first 25% of locations)
447
                } while (isBitSet(bits, index)==true && stop--);
447
                } while (isBitSet(bits, index)==true && stop--);
448
                if (!stop)
448
                if (!stop)
449
                    qDebug() << "executeiLandInit: found no free bit.";
449
                    qDebug() << "executeiLandInit: found no free bit.";
450
                setBit(bits, index, true); // mark position as used
450
                setBit(bits, index, true); // mark position as used
451
            }
451
            }
452
            // get position from fixed lists (one for even, one for uneven resource units)
452
            // get position from fixed lists (one for even, one for uneven resource units)
453
            pos = ru->index()%2?evenlist[index]:unevenlist[index];
453
            pos = ru->index()%2?evenlist[index]:unevenlist[index];
454
            tree_pos = offsetIdx  // position of resource unit
454
            tree_pos = offsetIdx  // position of resource unit
455
                       + QPoint(5*(i/10), 5*(i%10)) // relative position of 10x10m pixel
455
                       + QPoint(5*(i/10), 5*(i%10)) // relative position of 10x10m pixel
456
                       + QPoint(pos/5, pos%5); // relative position within 10x10m pixel
456
                       + QPoint(pos/5, pos%5); // relative position within 10x10m pixel
457
            //qDebug() << tree_no++ << "to" << index;
457
            //qDebug() << tree_no++ << "to" << index;
458
            ru->trees()[tree_idx].setPosition(tree_pos);
458
            ru->trees()[tree_idx].setPosition(tree_pos);
459
        }
459
        }
460
    }
460
    }
461
}
461
}
462
 
462