Subversion Repositories public iLand

Rev

Rev 566 | Rev 579 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1
 
185 werner 2
#include "global.h"
3
#include "management.h"
4
#include "helper.h"
186 werner 5
#include "model.h"
189 iland 6
#include "resourceunit.h"
186 werner 7
#include "tree.h"
216 werner 8
#include "expressionwrapper.h"
564 werner 9
#include "sapling.h"
566 werner 10
#include "soil.h"
186 werner 11
 
242 werner 12
#include "climateconverter.h"
245 werner 13
#include "csvfile.h"
247 werner 14
#include "scriptglobal.h"
552 werner 15
#include "mapgrid.h"
186 werner 16
 
185 werner 17
#include <QtScript>
216 werner 18
#include <QTextEdit>
19
QObject *Management::scriptOutput = 0;
185 werner 20
 
216 werner 21
QScriptValue script_debug(QScriptContext *ctx, QScriptEngine *eng)
294 werner 22
{
23
    QString value;
24
    for (int i = 0; i < ctx->argumentCount(); ++i) {
25
        if (i > 0)
26
            value.append(" ");
27
        value.append(ctx->argument(i).toString());
28
    }
29
    if (Management::scriptOutput) {
30
        QTextEdit *e = qobject_cast<QTextEdit*>(Management::scriptOutput);
31
        if (e)
32
            e->append(value);
33
    } else {
34
        qDebug() << "Script:" << value;
35
    }
36
    return eng->undefinedValue();
37
}
186 werner 38
 
294 werner 39
QScriptValue script_include(QScriptContext *ctx, QScriptEngine *eng)
40
{
552 werner 41
 
294 werner 42
    QString fileName = ctx->argument(0).toString();
43
    QString path =GlobalSettings::instance()->path(fileName, "script") ;
44
    QString includeFile=Helper::loadTextFile(path);
552 werner 45
 
46
    ctx->setActivationObject(ctx->parentContext()->activationObject());
47
    ctx->setThisObject(ctx->parentContext()->thisObject());
48
 
49
    QScriptValue ret = eng->evaluate(includeFile, fileName);
294 werner 50
    if (eng->hasUncaughtException())
51
        qDebug() << "Error in include:" << eng->uncaughtException().toString();
552 werner 52
    return ret;
294 werner 53
}
54
 
55
QScriptValue script_alert(QScriptContext *ctx, QScriptEngine *eng)
56
{
57
    QString value = ctx->argument(0).toString();
58
    Helper::msg(value);
59
    return eng->undefinedValue();
60
}
216 werner 61
// global output function
62
QString Management::executeScript(QString cmd)
63
{
64
    DebugTimer t("execute javascript");
65
    if (mEngine)
66
        mEngine->evaluate(cmd);
295 werner 67
    if (mEngine->hasUncaughtException()) {
321 werner 68
        //int line = mEngine->uncaughtExceptionLineNumber();
295 werner 69
        QString msg = QString( "Script Error occured: %1\n").arg( mEngine->uncaughtException().toString());
70
        msg+=mEngine->uncaughtExceptionBacktrace().join("\n");
71
        return msg;
72
    } else {
216 werner 73
        return QString();
295 werner 74
    }
216 werner 75
}
76
 
185 werner 77
Management::Management()
78
{
564 werner 79
    // setup the scripting engine
185 werner 80
    mEngine = new QScriptEngine();
81
    QScriptValue objectValue = mEngine->newQObject(this);
216 werner 82
    QScriptValue dbgprint = mEngine->newFunction(script_debug);
294 werner 83
    QScriptValue sinclude = mEngine->newFunction(script_include);
84
    QScriptValue alert = mEngine->newFunction(script_alert);
185 werner 85
    mEngine->globalObject().setProperty("management", objectValue);
216 werner 86
    mEngine->globalObject().setProperty("print",dbgprint);
294 werner 87
    mEngine->globalObject().setProperty("include",sinclude);
88
    mEngine->globalObject().setProperty("alert", alert);
247 werner 89
 
90
    // globals object: instatiate here, but ownership goes to script engine
91
    ScriptGlobal *global = new ScriptGlobal();
92
    QScriptValue glb = mEngine->newQObject(global,QScriptEngine::ScriptOwnership);
93
    mEngine->globalObject().setProperty("Globals", glb);
242 werner 94
    // other object types
95
    ClimateConverter::addToScriptEngine(*mEngine);
245 werner 96
    CSVFile::addToScriptEngine(*mEngine);
552 werner 97
    MapGridWrapper::addToScriptEngine(*mEngine);
216 werner 98
 
564 werner 99
    // default values for removal fractions
100
    // 100% of the stem, 0% of foliage and branches
101
    mRemoveFoliage = 0.;
102
    mRemoveBranch = 0.;
103
    mRemoveStem = 1.;
247 werner 104
 
564 werner 105
 
185 werner 106
}
107
 
108
Management::~Management()
109
{
110
    delete mEngine;
111
}
112
 
113
void Management::loadScript(const QString &fileName)
114
{
216 werner 115
    mScriptFile = fileName;
185 werner 116
    QString program = Helper::loadTextFile(fileName);
117
    if (program.isEmpty())
118
        return;
119
 
120
    mEngine->evaluate(program);
121
    qDebug() << "management script loaded";
122
    if (mEngine->hasUncaughtException())
123
        qDebug() << "Script Error occured: " << mEngine->uncaughtExceptionBacktrace();
124
 
125
}
126
 
566 werner 127
int Management::remain(int number)
185 werner 128
{
129
    qDebug() << "remain called (number): " << number;
186 werner 130
    Model *m = GlobalSettings::instance()->model();
131
    AllTreeIterator at(m);
132
    QList<Tree*> trees;
133
    while (Tree *t=at.next())
134
        trees.push_back(t);
135
    int to_kill = trees.count() - number;
136
    qDebug() << trees.count() << " standing, targetsize" << number << ", hence " << to_kill << "trees to remove";
137
    for (int i=0;i<to_kill;i++) {
349 werner 138
        int index = irandom(0, trees.count()-1);
278 werner 139
        trees[index]->remove();
186 werner 140
        trees.removeAt(index);
141
    }
142
    mRemoved += to_kill;
566 werner 143
    return to_kill;
185 werner 144
}
145
 
146
 
564 werner 147
int Management::kill()
252 werner 148
{
564 werner 149
    int c = mTrees.count();
252 werner 150
    for (int i=0;i<mTrees.count();i++)
278 werner 151
        mTrees[i].first->remove();
252 werner 152
    mTrees.clear();
564 werner 153
    return c;
252 werner 154
}
155
 
564 werner 156
int Management::remove_percentiles(int pctfrom, int pctto, int number, bool management)
216 werner 157
{
158
    if (mTrees.isEmpty())
159
        return 0;
160
    int index_from = limit(int(pctfrom/100. * mTrees.count()), 0, mTrees.count());
346 werner 161
    int index_to = limit(int(pctto/100. * mTrees.count()), 0, mTrees.count()-1);
216 werner 162
    if (index_from>=index_to)
163
        return 0;
217 werner 164
    qDebug() << "attempting to remove" << number << "trees between indices" << index_from << "and" << index_to;
216 werner 165
    int i;
166
    int count = number;
217 werner 167
    if (index_to-index_from <= number)  {
216 werner 168
        // kill all
564 werner 169
        if (management) {
170
            // management
171
            for (i=index_from; i<index_to; i++)
172
                mTrees.at(i).first->remove(removeFoliage(), removeBranch(), removeStem());
173
        } else {
174
            // just kill...
175
            for (i=index_from; i<index_to; i++)
176
                mTrees.at(i).first->remove();
177
        }
216 werner 178
        count = index_to - index_from;
179
    } else {
180
        // kill randomly the provided number
181
        int cancel = 1000;
182
        while(number>=0) {
183
            int rnd_index = irandom(index_from, index_to);
184
            if (mTrees[rnd_index].first->isDead()) {
185
                if (--cancel<0) {
186
                    qDebug() << "Management::kill: canceling search." << number << "trees left.";
217 werner 187
                    count-=number; // not all trees were killed
216 werner 188
                    break;
189
                }
190
                continue;
191
            }
192
            cancel = 1000;
193
            number--;
564 werner 194
            if (management) {
195
                mTrees[rnd_index].first->remove( removeFoliage(), removeBranch(), removeStem() );
196
            } else {
197
                mTrees[rnd_index].first->remove();
198
            }
216 werner 199
        }
200
    }
217 werner 201
    qDebug() << count << "removed.";
564 werner 202
    // clean up the tree list...
203
    for (int i=mTrees.count()-1; i>=0; --i) {
204
        if (mTrees[i].first->isDead())
205
            mTrees.removeAt(i);
206
    }
207
    return count; // killed or manages
216 werner 208
}
209
 
564 werner 210
// from the range percentile range pctfrom to pctto (each 1..100)
211
int Management::kill(int pctfrom, int pctto, int number)
212
{
213
    return remove_percentiles(pctfrom, pctto, number, false);
214
}
215
 
216
// from the range percentile range pctfrom to pctto (each 1..100)
217
int Management::manage(int pctfrom, int pctto, int number)
218
{
219
    return remove_percentiles(pctfrom, pctto, number, true);
220
}
221
 
222
int Management::manage()
223
{
224
    int c = mTrees.count();
225
    for (int i=0;i<mTrees.count();i++)
226
        mTrees[i].first->remove(removeFoliage(),
227
                                removeBranch(),
228
                                removeStem()); // remove with current removal fractions
229
    mTrees.clear();
230
    return c;
231
}
232
 
233
 
234
 
185 werner 235
void Management::run()
236
{
216 werner 237
    mTrees.clear();
186 werner 238
    mRemoved=0;
185 werner 239
    qDebug() << "Management::run() called";
240
    QScriptValue mgmt = mEngine->globalObject().property("manage");
241
    int year = GlobalSettings::instance()->currentYear();
242
    mgmt.call(QScriptValue(), QScriptValueList()<<year);
243
    if (mEngine->hasUncaughtException())
244
        qDebug() << "Script Error occured: " << mEngine->uncaughtExceptionBacktrace();
245
 
186 werner 246
    if (mRemoved>0) {
187 iland 247
        foreach(ResourceUnit *ru, GlobalSettings::instance()->model()->ruList())
186 werner 248
           ru->cleanTreeList();
249
   }
185 werner 250
}
216 werner 251
 
250 werner 252
int Management::filter(QVariantList idList)
253
{
389 werner 254
    QVector<int> ids;
250 werner 255
    foreach(const QVariant &v, idList)
389 werner 256
        if (!v.isNull())
257
            ids << v.toInt();
258
//    QHash<int, int> ids;
259
//    foreach(const QVariant &v, idList)
260
//        ids[v.toInt()] = 1;
216 werner 261
 
250 werner 262
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
263
    while (tp!=mTrees.end()) {
264
        if (!ids.contains(tp->first->id()) )
265
            tp = mTrees.erase(tp);
266
        else
267
            tp++;
268
    }
389 werner 269
    qDebug() << "Management::filter by id-list:" << mTrees.count();
250 werner 270
    return mTrees.count();
271
}
272
 
273
int Management::filter(QString filter)
274
{
275
    TreeWrapper tw;
276
    Expression expr(filter,&tw);
575 werner 277
    int n_before = mTrees.count();
250 werner 278
    QList<QPair<Tree*, double> >::iterator tp=mTrees.begin();
575 werner 279
    try {
280
        while (tp!=mTrees.end()) {
281
            tw.setTree(tp->first);
282
            if (!expr.calculate(tw))
283
                tp = mTrees.erase(tp);
284
            else
285
                tp++;
286
        }
287
    } catch(const IException &e) {
288
        context()->throwError(e.message());
250 werner 289
    }
575 werner 290
 
291
    qDebug() << "filtering with" << filter << "N=" << n_before << "/" << mTrees.count()  << "trees (before/after filtering).";
250 werner 292
    return mTrees.count();
293
}
294
 
294 werner 295
int Management::load(int ruindex)
296
{
297
    Model *m = GlobalSettings::instance()->model();
298
    ResourceUnit *ru = m->ru(ruindex);
299
    if (!ru)
300
        return -1;
301
    mTrees.clear();
302
    for (int i=0;i<ru->trees().count();i++)
303
        mTrees.push_back(QPair<Tree*,double>(ru->tree(i), 0.));
304
    return mTrees.count();
305
}
306
 
216 werner 307
int Management::load(QString filter)
308
{
309
    TreeWrapper tw;
310
    Model *m = GlobalSettings::instance()->model();
311
    mTrees.clear();
312
    AllTreeIterator at(m);
313
    if (filter.isEmpty()) {
314
        while (Tree *t=at.next())
315
            if (!t->isDead())
316
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
317
    } else {
318
        Expression expr(filter,&tw);
319
        qDebug() << "filtering with" << filter;
320
        while (Tree *t=at.next()) {
321
            tw.setTree(t);
322
            if (!t->isDead() && expr.execute())
323
                mTrees.push_back(QPair<Tree*, double>(t, 0.));
324
        }
325
    }
326
    return mTrees.count();
327
}
328
 
555 werner 329
/**
330
*/
544 werner 331
void Management::loadFromTreeList(QList<Tree*>tree_list)
332
{
333
    mTrees.clear();
334
    for (int i=0;i<tree_list.count();++i)
335
        mTrees.append(QPair<Tree*, double>(tree_list[i], 0.));
336
}
337
 
555 werner 338
// loadFromMap: script access
339
void Management::loadFromMap(QScriptValue map_grid_object, int key)
552 werner 340
{
555 werner 341
    MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
342
    if (!wrap) {
343
        context()->throwError("loadFromMap called with invalid map object!");
344
        return;
345
    }
346
    loadFromMap(wrap->map(), key);
347
}
348
 
564 werner 349
void Management::killSaplings(QScriptValue map_grid_object, int key)
350
{
351
    MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
352
    if (!wrap) {
353
        context()->throwError("loadFromMap called with invalid map object!");
354
        return;
355
    }
356
    //loadFromMap(wrap->map(), key);
357
    // retrieve all sapling trees on the stand:
358
    QList<QPair<ResourceUnitSpecies *, SaplingTree *> > list = wrap->map()->saplingTrees(key);
359
    // for now, just kill em all...
360
    for (QList<QPair<ResourceUnitSpecies *, SaplingTree *> >::iterator it = list.begin(); it!=list.end(); ++it)
361
        (*it).second->pixel = 0;
362
    // the storage for unused/invalid saplingtrees is released lazily (once a year, after growth)
363
}
364
 
566 werner 365
void Management::removeSoilCarbon(QScriptValue map_grid_object, int key, double SWDfrac, double DWDfrac, double litterFrac, double soilFrac)
565 werner 366
{
367
    MapGridWrapper *wrap = qobject_cast<MapGridWrapper*>(map_grid_object.toQObject());
368
    if (!wrap) {
369
        context()->throwError("loadFromMap called with invalid map object!");
370
        return;
371
    }
372
    QList<QPair<ResourceUnit*, double> > ru_areas = wrap->map()->resourceUnitAreas(key);
373
    double total_area = 0.;
374
    for (int i=0;i<ru_areas.size();++i) {
375
        ResourceUnit *ru = ru_areas[i].first;
376
        double area_factor = ru_areas[i].second; // 0..1
377
        total_area += area_factor;
566 werner 378
        // swd
379
        ru->snag()->removeCarbon(1. - SWDfrac*area_factor);
380
        // soil pools
381
        ru->soil()->disturbance(DWDfrac*area_factor, litterFrac*area_factor, soilFrac*area_factor);
565 werner 382
        qDebug() << ru->index() << area_factor;
383
    }
384
    qDebug() << "total area" << total_area << "of" << wrap->map()->area(key);
385
}
386
 
555 werner 387
/** loadFromMap selects trees located on pixels with value 'key' within the grid 'map_grid'.
388
*/
389
void Management::loadFromMap(const MapGrid *map_grid, int key)
390
{
391
    if (!map_grid) {
552 werner 392
        qDebug() << "invalid parameter for Management::loadFromMap: Map expected!";
393
        return;
394
    }
555 werner 395
    if (map_grid->isValid()) {
396
        QList<Tree*> tree_list = map_grid->trees(key);
552 werner 397
        loadFromTreeList( tree_list );
398
    } else {
399
        qDebug() << "Management::loadFromMap: grid is not valid - no trees loaded";
400
    }
401
 
402
}
403
 
216 werner 404
bool treePairValue(const QPair<Tree*, double> &p1, const QPair<Tree*, double> &p2)
405
{
406
    return p1.second < p2.second;
407
}
408
 
409
void Management::sort(QString statement)
410
{
411
    TreeWrapper tw;
412
    Expression sorter(statement, &tw);
413
    // fill the "value" part of the tree storage with a value for each tree
414
    for (int i=0;i<mTrees.count(); ++i) {
415
        tw.setTree(mTrees.at(i).first);
416
        mTrees[i].second = sorter.execute();
417
   }
418
   // now sort the list....
419
   qSort(mTrees.begin(), mTrees.end(), treePairValue);
420
}
421
 
422
double Management::percentile(int pct)
423
{
424
    if (mTrees.count()==0)
425
        return -1.;
426
    int idx = int( (pct/100.) * mTrees.count());
427
    if (idx>=0 && idx<mTrees.count())
428
        return mTrees.at(idx).second;
429
    else
430
        return -1;
431
}
564 werner 432