Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
677 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
#include "snapshot.h"
20
#include "global.h"
21
#include "globalsettings.h"
22
#include "model.h"
23
#include "resourceunit.h"
24
#include "species.h"
25
#include "tree.h"
26
#include "soil.h"
27
#include "snag.h"
1117 werner 28
#include "saplings.h"
808 werner 29
#include "debugtimer.h"
975 werner 30
#include "watercycle.h"
1045 werner 31
#include "expressionwrapper.h"
32
#include "helper.h"
33
#include "gisgrid.h"
1213 werner 34
#include "mapgrid.h"
677 werner 35
 
36
#include <QString>
37
#include <QtSql>
1157 werner 38
//#include <QVector3D>
677 werner 39
 
40
 
41
Snapshot::Snapshot()
42
{
43
}
44
 
45
bool Snapshot::openDatabase(const QString &file_name, const bool read)
46
{
683 werner 47
    if (!GlobalSettings::instance()->setupDatabaseConnection("snapshot", file_name, read)) {
48
        throw IException("Snapshot:createDatabase: database could not be created / opened");
677 werner 49
    }
50
    QSqlDatabase db=QSqlDatabase::database("snapshot");
51
    if (!read) {
52
        // create tables
53
        QSqlQuery q(db);
54
        // trees
55
        q.exec("drop table trees");
56
        q.exec("create table trees (ID integer, RUindex integer, posX integer, posY integer, species text,  age integer, height real, dbh real, leafArea real, opacity real, foliageMass real, woodyMass real, fineRootMass real, coarseRootMass real, NPPReserve real, stressIndex real)");
57
        // soil
58
        q.exec("drop table soil");
975 werner 59
        q.exec("create table soil (RUindex integer, kyl real, kyr real, inLabC real, inLabN real, inLabP real, inRefC real, inRefN real, inRefP real, YLC real, YLN real, YLP real, YRC real, YRN real, YRP real, SOMC real, SOMN real, WaterContent, SnowPack real)");
695 werner 60
        // snag
677 werner 61
        q.exec("drop table snag");
62
        q.exec("create table snag(RUIndex integer, climateFactor real, SWD1C real, SWD1N real, SWD2C real, SWD2N real, SWD3C real, SWD3N real, " \
63
               "totalSWDC real, totalSWDN real, NSnags1 real, NSnags2 real, NSnags3 real, dbh1 real, dbh2 real, dbh3 real, height1 real, height2 real, height3 real, " \
64
               "volume1 real, volume2 real, volume3 real, tsd1 real, tsd2 real, tsd3 real, ksw1 real, ksw2 real, ksw3 real, halflife1 real, halflife2 real, halflife3 real, " \
65
               "branch1C real, branch1N real, branch2C real, branch2N real, branch3C real, branch3N real, branch4C real, branch4N real, branch5C real, branch5N real, branchIndex integer)");
695 werner 66
        // saplings/regeneration
67
        q.exec("drop table saplings");
68
        q.exec("create table saplings (RUindex integer, species text, posx integer, posy integer, age integer, height float, stress_years integer)");
69
        qDebug() << "Snapshot - tables created. Database" << file_name;
677 werner 70
    }
71
    return true;
72
}
73
 
1213 werner 74
bool Snapshot::openStandDatabase(const QString &file_name, bool read)
75
{
76
    if (!GlobalSettings::instance()->setupDatabaseConnection("snapshotstand", file_name, read)) {
77
        throw IException("Snapshot:createDatabase: database could not be created / opened");
78
    }
79
    return true;
80
 
81
}
82
 
677 werner 83
bool Snapshot::createSnapshot(const QString &file_name)
84
{
85
    openDatabase(file_name, false);
86
    // save the trees
87
    saveTrees();
88
    // save soil pools
89
    saveSoil();
90
    // save snags / deadwood pools
91
    saveSnags();
695 werner 92
    // save saplings
93
    saveSaplings();
677 werner 94
    QSqlDatabase::database("snapshot").close();
1045 werner 95
    // save a grid of the indices
96
    QFileInfo fi(file_name);
97
    QString grid_file = fi.absolutePath() + "/" + fi.completeBaseName() + ".asc";
98
    Grid<double> index_grid;
99
    index_grid.setup( GlobalSettings::instance()->model()->RUgrid().metricRect(), GlobalSettings::instance()->model()->RUgrid().cellsize());
100
    RUWrapper ru_wrap;
101
    Expression ru_value("index", &ru_wrap);
102
    double *grid_ptr = index_grid.begin();
103
    for (ResourceUnit **ru = GlobalSettings::instance()->model()->RUgrid().begin(); ru!=GlobalSettings::instance()->model()->RUgrid().end(); ++ru, ++grid_ptr) {
1047 werner 104
        if (*ru) {
1045 werner 105
            ru_wrap.setResourceUnit(*ru);
106
            *grid_ptr = ru_value.execute();
107
        } else
108
            *grid_ptr = -1.;
109
    }
110
    QString grid_text = gridToESRIRaster(index_grid);
111
    Helper::saveToTextFile(grid_file, grid_text);
112
    qDebug() << "saved grid to " << grid_file;
113
 
677 werner 114
    return true;
115
}
116
 
117
bool Snapshot::loadSnapshot(const QString &file_name)
118
{
688 werner 119
    DebugTimer t("loadSnapshot");
677 werner 120
    openDatabase(file_name, true);
1045 werner 121
 
122
 
123
    QFileInfo fi(file_name);
124
    QString grid_file = fi.absolutePath() + "/" + fi.completeBaseName() + ".asc";
125
    GisGrid grid;
126
    mRUHash.clear();
127
 
128
    if (!grid.loadFromFile(grid_file)) {
129
        qDebug() << "loading of snapshot: not a valid grid file (containing resource unit inidices) expected at:" << grid_file;
130
        for (ResourceUnit **ru = GlobalSettings::instance()->model()->RUgrid().begin(); ru!=GlobalSettings::instance()->model()->RUgrid().end();++ru) {
1047 werner 131
            if (*ru)
1045 werner 132
                mRUHash[ (*ru)->index() ] = *ru;
133
        }
134
    } else {
135
        // setup link between resource unit index and index grid:
136
        // store for each resource unit *in the snapshot database* the corresponding
137
        // resource unit index of the *current* simulation.
1157 werner 138
        QPointF to=GisGrid::worldToModel(grid.origin());
1045 werner 139
 
1157 werner 140
        if (fmod(to.x(), cRUSize) != 0. || fmod(to.y(), cRUSize) != 0.) {
141
            QPointF world_offset = GisGrid::modelToWorld(QPointF(0., 0.));
142
            throw IException(QString("Loading of the snapshot '%1' failed: The offset from the current location of the project (%4/%5) " \
143
                                     "is not a multiple of the resource unit size (100m) relative to grid of the snapshot (origin-x: %2, origin-y: %3).").arg(file_name)
144
                             .arg(grid.origin().x()).arg(grid.origin().y()).arg(world_offset.x()).arg(world_offset.y()));
145
        }
146
 
147
 
1045 werner 148
        const Grid<ResourceUnit*> &rugrid = GlobalSettings::instance()->model()->RUgrid();
149
        for (int i=0;i<rugrid.count();++i) {
150
            const ResourceUnit *ru = rugrid.constValueAtIndex(i);
151
            if (ru && ru->index()>-1) {
152
               int value = grid.value( rugrid.cellCenterPoint(i) );
153
               if (value>-1)
154
                   mRUHash[value] = const_cast<ResourceUnit*>(ru);
155
            }
156
        }
157
 
158
    }
159
 
160
 
677 werner 161
    loadTrees();
162
    loadSoil();
163
    loadSnags();
1076 werner 164
    // load saplings only when regeneration is enabled (this can save a lot of time)
1117 werner 165
    if (GlobalSettings::instance()->model()->settings().regenerationEnabled) {
1076 werner 166
        loadSaplings();
1117 werner 167
        //loadSaplingsOld();
168
    }
975 werner 169
    QSqlDatabase::database("snapshot").close();
170
 
677 werner 171
    // after changing the trees, do a complete apply/read pattern cycle over the landscape...
172
    GlobalSettings::instance()->model()->onlyApplyLightPattern();
173
    qDebug() << "applied light pattern...";
975 werner 174
 
175
    // refresh the stand statistics
176
    foreach (ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
1157 werner 177
         ru->recreateStandStatistics(true); // true: recalculate statistics
975 werner 178
     }
179
 
180
    qDebug() << "created stand statistics...";
181
    qDebug() << "loading of snapshot completed.";
182
 
677 werner 183
    return true;
184
}
185
 
1213 werner 186
bool Snapshot::saveStandSnapshot(const int stand_id, const MapGrid *stand_grid, const QString &file_name)
187
{
188
    // Check database
189
    QSqlDatabase db=QSqlDatabase::database("snapshotstand");
190
    if (!db.isOpen()) {
191
        openStandDatabase(GlobalSettings::instance()->path(file_name), false);
192
        db=QSqlDatabase::database("snapshotstand");
193
        // check if tree/sapling tables are already present
194
        if (!db.tables().contains("trees_stand") || !db.tables().contains("saplings_stand")) {
195
            // create tables
196
            QSqlQuery q(db);
197
            // trees
198
            q.exec("drop table trees_stand");
199
            q.exec("create table trees_stand (standID integer, ID integer, posX integer, posY integer, species text,  age integer, height real, dbh real, leafArea real, opacity real, foliageMass real, woodyMass real, fineRootMass real, coarseRootMass real, NPPReserve real, stressIndex real)");
200
            // saplings/regeneration
201
            q.exec("drop table saplings_stand");
202
            q.exec("create table saplings_stand (standID integer, posx integer, posy integer, species_index integer, age integer, height float, stress_years integer, flags integer)");
203
 
204
        }
205
    }
206
    // save trees
207
    QSqlQuery q(db);
208
    q.exec(QString("delete from trees_stand where standID=%1").arg(stand_id));
209
 
210
    if (!q.prepare(QString("insert into trees_stand (standID, ID, posX, posY, species,  age, height, dbh, leafArea, opacity, foliageMass, woodyMass, fineRootMass, coarseRootMass, NPPReserve, stressIndex) " \
211
                      "values (:standid, :id, :x, :y, :spec, :age, :h, :d, :la, :opa, :mfol, :mwood, :mfr, :mcr, :npp, :si)")))
212
        throw IException(QString("Snapshot::saveTrees: prepare:") + q.lastError().text());
213
 
214
    db.transaction();
215
    QPointF offset = GisGrid::modelToWorld(QPointF(0.,0.));
216
    QList<Tree*> tree_list = stand_grid->trees(stand_id);
217
    QList<Tree*>::const_iterator it;
218
    for (it = tree_list.constBegin(); it!= tree_list.constEnd(); ++it)
219
    {
220
        Tree *t = *it;
221
        q.addBindValue(stand_id);
222
        q.addBindValue(t->id());
223
        q.addBindValue(t->position().x() + offset.x());
224
        q.addBindValue(t->position().y() + offset.y());
225
        q.addBindValue(t->species()->id());
226
        q.addBindValue(t->age());
227
        q.addBindValue(t->height());
228
        q.addBindValue(t->dbh());
229
        q.addBindValue(t->leafArea());
230
        q.addBindValue(t->mOpacity);
231
        q.addBindValue(t->biomassFoliage());
232
        q.addBindValue(t->biomassStem());
233
        q.addBindValue(t->biomassFineRoot());
234
        q.addBindValue(t->biomassCoarseRoot());
235
        q.addBindValue(t->mNPPReserve);
236
        q.addBindValue(t->mStressIndex);
237
        if (!q.exec()) {
238
            throw IException(QString("Snapshot::saveStandSnapshot, Trees: execute:") + q.lastError().text());
239
        }
240
 
241
    }
242
    // save saplings
243
    // loop over all pixels, only when regeneration is enabled
244
    if (GlobalSettings::instance()->model()->settings().regenerationEnabled) {
245
        q.exec(QString("delete from saplings_stand where standID=%1").arg(stand_id));
246
 
247
        if (!q.prepare(QString("insert into saplings_stand (standID, posx, posy, species_index, age, height, stress_years, flags) " \
248
                               "values (?,?,?,?,?,?,?,?)")))
249
            throw IException(QString("Snapshot::saveSaplings: prepare:") + q.lastError().text());
250
 
251
 
252
        SaplingCellRunner scr(stand_id, stand_grid);
253
        while (SaplingCell *sc = scr.next()) {
254
            for (int i=0;i<NSAPCELLS;++i)
255
                if (sc->saplings[i].is_occupied()) {
256
                    q.addBindValue(stand_id);
257
                    QPointF t = scr.currentCoord();
258
                    q.addBindValue(t.x() + offset.x());
259
                    q.addBindValue(t.y() + offset.y());
260
                    q.addBindValue(sc->saplings[i].species_index);
261
                    q.addBindValue(sc->saplings[i].age);
262
                    q.addBindValue(sc->saplings[i].height);
263
                    q.addBindValue(sc->saplings[i].stress_years);
264
                    q.addBindValue(sc->saplings[i].flags);
265
                    if (!q.exec()) {
266
                        throw IException(QString("Snapshot::saveStandSnapshot, saplings: execute:") + q.lastError().text());
267
                    }
268
                }
269
        }
270
    }
271
 
272
    db.commit();
273
 
274
    return true;
275
}
276
 
277
bool Snapshot::loadStandSnapshot(const int stand_id, const MapGrid *stand_grid, const QString &file_name)
278
{
279
    QSqlDatabase db=QSqlDatabase::database("snapshotstand");
280
    if (!db.isOpen()) {
281
        openStandDatabase(GlobalSettings::instance()->path(file_name), true);
282
        db=QSqlDatabase::database("snapshotstand");
283
    }
284
    // load trees
285
    // kill all living trees on the stand
286
    QList<Tree*> tree_list = stand_grid->trees(stand_id);
287
    QList<Tree*>::const_iterator it;
288
    int n_removed = tree_list.count();
289
    for (it = tree_list.constBegin(); it!= tree_list.constEnd(); ++it) {
290
        (*it)->remove(1., 1., 1.);
291
    }
292
 
293
    // load from database
294
    QSqlQuery q(db);
295
    q.setForwardOnly(true);
296
    q.exec(QString("select standID, ID, posX, posY, species,  age, height, dbh, leafArea, opacity, "
297
                   "foliageMass, woodyMass, fineRootMass, coarseRootMass, NPPReserve, stressIndex "
298
                   "from trees_stand where standID=%1").arg(stand_id));
299
    QRectF extent = GlobalSettings::instance()->model()->extent();
1214 werner 300
    int n=0, sap_n=0, n_sap_removed=0;
1213 werner 301
    while (q.next()) {
302
        QPointF coord(GisGrid::worldToModel(QPointF(q.value(2).toInt(), q.value(3).toInt())));
303
        if (!extent.contains(coord))
304
            continue;
305
        ResourceUnit *ru = GlobalSettings::instance()->model()->ru(coord);
306
        if (!ru)
307
            continue;
308
        Tree &t = ru->newTree();
309
        t.setRU(ru);
310
        t.mId = q.value(1).toInt();
311
        t.setPosition(coord);
312
        Species *s = GlobalSettings::instance()->model()->speciesSet()->species(q.value(4).toString());
313
        if (!s)
314
            throw IException("Snapshot::loadTrees: Invalid species");
315
        t.setSpecies(s);
316
        t.mAge = q.value(5).toInt();
317
        t.mHeight = q.value(6).toFloat();
318
        t.mDbh = q.value(7).toFloat();
319
        t.mLeafArea = q.value(8).toFloat();
320
        t.mOpacity = q.value(9).toFloat();
321
        t.mFoliageMass = q.value(10).toFloat();
322
        t.mWoodyMass = q.value(11).toFloat();
323
        t.mFineRootMass = q.value(12).toFloat();
324
        t.mCoarseRootMass = q.value(13).toFloat();
325
        t.mNPPReserve = q.value(14).toFloat();
326
        t.mStressIndex = q.value(15).toFloat();
327
        t.mStamp = s->stamp(t.mDbh, t.mHeight);
328
        n++;
329
    }
330
 
331
    // now the saplings
332
    if (GlobalSettings::instance()->model()->settings().regenerationEnabled) {
333
        // (1) remove all saplings:
334
        SaplingCellRunner scr(stand_id, stand_grid);
335
        while (SaplingCell *sc = scr.next()) {
336
            n_sap_removed += sc->n_occupied();
337
            GlobalSettings::instance()->model()->saplings()->clearSaplings(sc, scr.ru(),true);
338
        }
339
 
340
        // (2) load saplings from database
341
        q.exec(QString("select posx, posy, species_index, age, height, stress_years, flags "
342
                       "from saplings_stand where standID=%1").arg(stand_id));
343
        while (q.next()) {
344
            QPointF coord(GisGrid::worldToModel(QPointF(q.value(0).toInt(), q.value(1).toInt())));
345
            if (!extent.contains(coord))
346
                continue;
347
            SaplingCell *sc = GlobalSettings::instance()->model()->saplings()->cell(GlobalSettings::instance()->model()->grid()->indexAt(coord));
348
            if (!sc)
349
                continue;
350
            if (SaplingTree *st = sc->addSapling(q.value(4).toFloat(),
351
                                                 q.value(3).toInt(),
352
                                                 q.value(2).toInt())) {
1214 werner 353
                st->stress_years = static_cast<unsigned char>(q.value(5).toChar().toLatin1());
354
                st->flags = static_cast<unsigned char>(q.value(6).toChar().toLatin1());
1213 werner 355
            }
356
            sap_n++;
357
 
358
        }
359
 
360
    }
1214 werner 361
    // clean up
362
    GlobalSettings::instance()->model()->cleanTreeLists(true);
1213 werner 363
 
1214 werner 364
    qDebug() << "load stand snapshot for stand "<< stand_id << ": trees (removed/loaded): " <<n_removed<<"/" << n <<", saplings (removed/loaded):" << n_sap_removed << "/" << sap_n;
365
 
1213 werner 366
    return true;
367
}
368
 
677 werner 369
void Snapshot::saveTrees()
370
{
371
    QSqlDatabase db=QSqlDatabase::database("snapshot");
372
    AllTreeIterator at(GlobalSettings::instance()->model());
373
    QSqlQuery q(db);
374
    if (!q.prepare(QString("insert into trees (ID, RUindex, posX, posY, species,  age, height, dbh, leafArea, opacity, foliageMass, woodyMass, fineRootMass, coarseRootMass, NPPReserve, stressIndex) " \
375
                      "values (:id, :index, :x, :y, :spec, :age, :h, :d, :la, :opa, :mfol, :mwood, :mfr, :mcr, :npp, :si)")))
376
        throw IException(QString("Snapshot::saveTrees: prepare:") + q.lastError().text());
377
 
378
    int n = 0;
379
    db.transaction();
380
    while (Tree *t = at.next()) {
381
        q.addBindValue(t->id());
382
        q.addBindValue(t->ru()->index());
383
        q.addBindValue(t->mPositionIndex.x());
384
        q.addBindValue(t->mPositionIndex.y());
385
        q.addBindValue(t->species()->id());
386
        q.addBindValue(t->age());
387
        q.addBindValue(t->height());
388
        q.addBindValue(t->dbh());
389
        q.addBindValue(t->leafArea());
390
        q.addBindValue(t->mOpacity);
391
        q.addBindValue(t->biomassFoliage());
392
        q.addBindValue(t->biomassStem());
393
        q.addBindValue(t->biomassFineRoot());
394
        q.addBindValue(t->biomassCoarseRoot());
395
        q.addBindValue(t->mNPPReserve);
396
        q.addBindValue(t->mStressIndex);
397
        if (!q.exec()) {
398
            throw IException(QString("Snapshot::saveTrees: execute:") + q.lastError().text());
399
        }
400
        if (++n % 10000 == 0) {
401
            qDebug() << n << "trees saved...";
402
            QCoreApplication::processEvents();
403
        }
404
    }
405
    db.commit();
406
    qDebug() << "Snapshot: finished trees. N=" << n;
407
}
408
 
409
void Snapshot::loadTrees()
410
{
411
    QSqlDatabase db=QSqlDatabase::database("snapshot");
412
    QSqlQuery q(db);
688 werner 413
    // setForwardOnly() -> helps avoiding that the query caches all the data
414
    // during iterating
415
    q.setForwardOnly(true);
941 werner 416
    q.exec("select ID, RUindex, posX, posY, species,  age, height, dbh, leafArea, opacity, foliageMass, woodyMass, fineRootMass, coarseRootMass, NPPReserve, stressIndex from trees");
677 werner 417
    int ru_index = -1;
418
    int new_ru;
1099 werner 419
    int offsetx=0, offsety=0;
677 werner 420
    ResourceUnit *ru = 0;
1049 werner 421
    int n=0, ntotal=0;
688 werner 422
    try {
695 werner 423
        // clear all trees on the landscape
424
        foreach (ResourceUnit *ru, GlobalSettings::instance()->model()->ruList())
756 werner 425
            ru->trees().clear();
695 werner 426
        // load the trees from the database
427
        while (q.next()) {
428
            new_ru = q.value(1).toInt();
1049 werner 429
            ++ntotal;
695 werner 430
            if (new_ru != ru_index) {
431
                ru_index = new_ru;
1045 werner 432
                ru = mRUHash[ru_index];
433
                if (ru) {
434
                    offsetx = ru->cornerPointOffset().x();
435
                    offsety = ru->cornerPointOffset().y();
436
                }
437
 
695 werner 438
            }
1000 werner 439
            if (!ru)
440
                continue;
695 werner 441
            // add a new tree to the tree list
442
            //ru->trees().append(Tree());
443
            //Tree &t = ru->trees().back();
444
            Tree &t = ru->newTree();
445
            t.setRU(ru);
446
            t.mId = q.value(0).toInt();
1045 werner 447
            t.mPositionIndex.setX(offsetx + q.value(2).toInt() % cPxPerRU);
448
            t.mPositionIndex.setY(offsety + q.value(3).toInt() % cPxPerRU);
695 werner 449
            Species *s = GlobalSettings::instance()->model()->speciesSet()->species(q.value(4).toString());
450
            if (!s)
451
                throw IException("Snapshot::loadTrees: Invalid species");
452
            t.setSpecies(s);
453
            t.mAge = q.value(5).toInt();
454
            t.mHeight = q.value(6).toFloat();
455
            t.mDbh = q.value(7).toFloat();
456
            t.mLeafArea = q.value(8).toFloat();
457
            t.mOpacity = q.value(9).toFloat();
458
            t.mFoliageMass = q.value(10).toFloat();
459
            t.mWoodyMass = q.value(11).toFloat();
460
            t.mFineRootMass = q.value(12).toFloat();
461
            t.mCoarseRootMass = q.value(13).toFloat();
462
            t.mNPPReserve = q.value(14).toFloat();
463
            t.mStressIndex = q.value(15).toFloat();
464
            t.mStamp = s->stamp(t.mDbh, t.mHeight);
688 werner 465
 
802 werner 466
 
995 werner 467
            if (n<10000000 && ++n % 10000 == 0) {
695 werner 468
                qDebug() << n << "trees loaded...";
469
                QCoreApplication::processEvents();
470
            }
687 werner 471
 
677 werner 472
        }
780 werner 473
    } catch (const std::bad_alloc &) {
688 werner 474
        throw IException(QString("bad_alloc exception after %1 trees!!!!").arg(n));
475
    }
476
 
975 werner 477
 
1049 werner 478
    qDebug() << "Snapshot: finished trees. N=" << n << "from trees in snapshot:" << ntotal;
677 werner 479
}
480
 
481
 
482
void Snapshot::saveSoil()
483
{
484
    QSqlDatabase db=QSqlDatabase::database("snapshot");
485
    QSqlQuery q(db);
975 werner 486
    if (!q.prepare(QString("insert into soil (RUindex, kyl, kyr, inLabC, inLabN, inLabP, inRefC, inRefN, inRefP, YLC, YLN, YLP, YRC, YRN, YRP, SOMC, SOMN, WaterContent, SnowPack) " \
487
                      "values (:idx, :kyl, :kyr, :inLabC, :iLN, :iLP, :iRC, :iRN, :iRP, :ylc, :yln, :ylp, :yrc, :yrn, :yrp, :somc, :somn, :wc, :snowpack)")))
677 werner 488
        throw IException(QString("Snapshot::saveSoil: prepare:") + q.lastError().text());
489
 
490
    int n = 0;
491
    db.transaction();
492
    foreach (ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
493
        Soil *s = ru->soil();
745 werner 494
        if (s) {
495
            q.addBindValue(s->mRU->index());
496
            q.addBindValue(s->mKyl);
497
            q.addBindValue(s->mKyr);
498
            q.addBindValue(s->mInputLab.C);
499
            q.addBindValue(s->mInputLab.N);
941 werner 500
            q.addBindValue(s->mInputLab.parameter());
745 werner 501
            q.addBindValue(s->mInputRef.C);
502
            q.addBindValue(s->mInputRef.N);
941 werner 503
            q.addBindValue(s->mInputRef.parameter());
745 werner 504
            q.addBindValue(s->mYL.C);
505
            q.addBindValue(s->mYL.N);
941 werner 506
            q.addBindValue(s->mYL.parameter());
745 werner 507
            q.addBindValue(s->mYR.C);
508
            q.addBindValue(s->mYR.N);
941 werner 509
            q.addBindValue(s->mYR.parameter());
745 werner 510
            q.addBindValue(s->mSOM.C);
511
            q.addBindValue(s->mSOM.N);
975 werner 512
            q.addBindValue(ru->waterCycle()->currentContent());
513
            q.addBindValue(ru->waterCycle()->currentSnowPack());
745 werner 514
            if (!q.exec()) {
515
                throw IException(QString("Snapshot::saveSoil: execute:") + q.lastError().text());
516
            }
517
            if (++n % 1000 == 0) {
518
                qDebug() << n << "soil resource units saved...";
519
                QCoreApplication::processEvents();
520
            }
677 werner 521
        }
522
    }
523
 
524
    db.commit();
525
    qDebug() << "Snapshot: finished Soil. N=" << n;
526
}
527
 
528
void Snapshot::loadSoil()
529
{
530
    QSqlDatabase db=QSqlDatabase::database("snapshot");
531
    QSqlQuery q(db);
975 werner 532
    q.exec("select RUindex, kyl, kyr, inLabC, inLabN, inLabP, inRefC, inRefN, inRefP, YLC, YLN, YLP, YRC, YRN, YRP, SOMC, SOMN, WaterContent, SnowPack from soil");
677 werner 533
    int ru_index = -1;
534
    ResourceUnit *ru = 0;
535
    int n=0;
536
    while (q.next()) {
537
        ru_index = q.value(0).toInt();
1053 werner 538
        ru = mRUHash[ru_index];
677 werner 539
        if (!ru)
1000 werner 540
            continue;
677 werner 541
        Soil *s = ru->soil();
745 werner 542
        if (!s) {
543
            throw IException("Snapshot::loadSoil: trying to load soil data but soil module is disabled.");
544
        }
677 werner 545
        s->mKyl = q.value(1).toDouble();
546
        s->mKyr = q.value(2).toDouble();
547
        s->mInputLab.C = q.value(3).toDouble();
548
        s->mInputLab.N = q.value(4).toDouble();
941 werner 549
        s->mInputLab.setParameter( q.value(5).toDouble());
550
        s->mInputRef.C = q.value(6).toDouble();
551
        s->mInputRef.N = q.value(7).toDouble();
552
        s->mInputRef.setParameter( q.value(8).toDouble());
553
        s->mYL.C = q.value(9).toDouble();
554
        s->mYL.N = q.value(10).toDouble();
555
        s->mYL.setParameter( q.value(11).toDouble());
556
        s->mYR.C = q.value(12).toDouble();
557
        s->mYR.N = q.value(13).toDouble();
558
        s->mYR.setParameter( q.value(14).toDouble());
559
        s->mSOM.C = q.value(15).toDouble();
560
        s->mSOM.N = q.value(16).toDouble();
975 werner 561
        const_cast<WaterCycle*>(ru->waterCycle())->setContent(q.value(17).toDouble(), q.value(18).toDouble());
677 werner 562
 
563
        if (++n % 1000 == 0) {
564
            qDebug() << n << "soil units loaded...";
565
            QCoreApplication::processEvents();
566
        }
567
    }
568
    qDebug() << "Snapshot: finished soil. N=" << n;
569
 
570
}
571
 
572
 
573
void Snapshot::saveSnags()
574
{
575
    QSqlDatabase db=QSqlDatabase::database("snapshot");
576
    QSqlQuery q(db);
577
    if (!q.prepare(QString("insert into snag(RUIndex, climateFactor, SWD1C, SWD1N, SWD2C, SWD2N, SWD3C, SWD3N, " \
578
                           "totalSWDC, totalSWDN, NSnags1, NSnags2, NSnags3, dbh1, dbh2, dbh3, height1, height2, height3, " \
579
                           "volume1, volume2, volume3, tsd1, tsd2, tsd3, ksw1, ksw2, ksw3, halflife1, halflife2, halflife3, " \
580
                           "branch1C, branch1N, branch2C, branch2N, branch3C, branch3N, branch4C, branch4N, branch5C, branch5N, branchIndex) " \
581
                          "values (?,?,?,?,?,?,?,?, " \
582
                           "?,?,?,?,?,?,?,?,?,?,?," \
583
                           "?,?,?,?,?,?,?,?,?,?,?,?," \
584
                           "?,?,?,?,?,?,?,?,?,?,?)")))
585
        throw IException(QString("Snapshot::saveSnag: prepare:") + q.lastError().text());
586
 
587
    int n = 0;
588
    db.transaction();
589
    foreach (ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
590
        Snag *s = ru->snag();
975 werner 591
        if (!s)
592
            continue;
677 werner 593
        q.addBindValue(s->mRU->index());
594
        q.addBindValue(s->mClimateFactor);
595
        q.addBindValue(s->mSWD[0].C);
596
        q.addBindValue(s->mSWD[0].N);
597
        q.addBindValue(s->mSWD[1].C);
678 werner 598
        q.addBindValue(s->mSWD[1].N);
599
        q.addBindValue(s->mSWD[2].C);
677 werner 600
        q.addBindValue(s->mSWD[2].N);
601
        q.addBindValue(s->mTotalSWD.C);
602
        q.addBindValue(s->mTotalSWD.N);
603
        q.addBindValue(s->mNumberOfSnags[0]);
604
        q.addBindValue(s->mNumberOfSnags[1]);
605
        q.addBindValue(s->mNumberOfSnags[2]);
606
        q.addBindValue(s->mAvgDbh[0]);
607
        q.addBindValue(s->mAvgDbh[1]);
608
        q.addBindValue(s->mAvgDbh[2]);
609
        q.addBindValue(s->mAvgHeight[0]);
610
        q.addBindValue(s->mAvgHeight[1]);
611
        q.addBindValue(s->mAvgHeight[2]);
612
        q.addBindValue(s->mAvgVolume[0]);
613
        q.addBindValue(s->mAvgVolume[1]);
614
        q.addBindValue(s->mAvgVolume[2]);
615
        q.addBindValue(s->mTimeSinceDeath[0]);
616
        q.addBindValue(s->mTimeSinceDeath[1]);
617
        q.addBindValue(s->mTimeSinceDeath[2]);
618
        q.addBindValue(s->mKSW[0]);
619
        q.addBindValue(s->mKSW[1]);
620
        q.addBindValue(s->mKSW[2]);
621
        q.addBindValue(s->mHalfLife[0]);
622
        q.addBindValue(s->mHalfLife[1]);
623
        q.addBindValue(s->mHalfLife[2]);
624
        q.addBindValue(s->mOtherWood[0].C); q.addBindValue(s->mOtherWood[0].N);
625
        q.addBindValue(s->mOtherWood[1].C); q.addBindValue(s->mOtherWood[1].N);
626
        q.addBindValue(s->mOtherWood[2].C); q.addBindValue(s->mOtherWood[2].N);
627
        q.addBindValue(s->mOtherWood[3].C); q.addBindValue(s->mOtherWood[3].N);
628
        q.addBindValue(s->mOtherWood[4].C); q.addBindValue(s->mOtherWood[4].N);
629
        q.addBindValue(s->mBranchCounter);
630
 
631
        if (!q.exec()) {
632
            throw IException(QString("Snapshot::saveSnag: execute:") + q.lastError().text());
633
        }
634
        if (++n % 1000 == 0) {
635
            qDebug() << n << "snags saved...";
636
            QCoreApplication::processEvents();
637
        }
638
    }
639
 
640
    db.commit();
641
    qDebug() << "Snapshot: finished Snags. N=" << n;
642
}
643
 
644
void Snapshot::loadSnags()
645
{
646
    QSqlDatabase db=QSqlDatabase::database("snapshot");
647
    QSqlQuery q(db);
941 werner 648
    q.exec("select RUIndex, climateFactor, SWD1C, SWD1N, SWD2C, SWD2N, SWD3C, SWD3N, totalSWDC, totalSWDN, NSnags1, NSnags2, NSnags3, dbh1, dbh2, dbh3, height1, height2, height3, volume1, volume2, volume3, tsd1, tsd2, tsd3, ksw1, ksw2, ksw3, halflife1, halflife2, halflife3, branch1C, branch1N, branch2C, branch2N, branch3C, branch3N, branch4C, branch4N, branch5C, branch5N, branchIndex from snag");
677 werner 649
    int ru_index = -1;
650
    ResourceUnit *ru = 0;
651
    int n=0;
652
    int ci=0;
653
    while (q.next()) {
654
        ru_index = q.value(ci++).toInt();
1045 werner 655
        ru = mRUHash[ru_index];
677 werner 656
        if (!ru)
1000 werner 657
            continue;
677 werner 658
        Snag *s = ru->snag();
975 werner 659
        if (!s)
660
            continue;
677 werner 661
        s->mClimateFactor = q.value(ci++).toDouble();
662
        s->mSWD[0].C = q.value(ci++).toDouble();
663
        s->mSWD[0].N = q.value(ci++).toDouble();
664
        s->mSWD[1].C = q.value(ci++).toDouble();
665
        s->mSWD[1].N = q.value(ci++).toDouble();
666
        s->mSWD[2].C = q.value(ci++).toDouble();
667
        s->mSWD[2].N = q.value(ci++).toDouble();
668
        s->mTotalSWD.C = q.value(ci++).toDouble();
669
        s->mTotalSWD.N = q.value(ci++).toDouble();
670
        s->mNumberOfSnags[0] = q.value(ci++).toDouble();
671
        s->mNumberOfSnags[1] = q.value(ci++).toDouble();
672
        s->mNumberOfSnags[2] = q.value(ci++).toDouble();
673
        s->mAvgDbh[0] = q.value(ci++).toDouble();
674
        s->mAvgDbh[1] = q.value(ci++).toDouble();
675
        s->mAvgDbh[2] = q.value(ci++).toDouble();
676
        s->mAvgHeight[0] = q.value(ci++).toDouble();
677
        s->mAvgHeight[1] = q.value(ci++).toDouble();
678
        s->mAvgHeight[2] = q.value(ci++).toDouble();
679
        s->mAvgVolume[0] = q.value(ci++).toDouble();
680
        s->mAvgVolume[1] = q.value(ci++).toDouble();
681
        s->mAvgVolume[2] = q.value(ci++).toDouble();
682
        s->mTimeSinceDeath[0] = q.value(ci++).toDouble();
683
        s->mTimeSinceDeath[1] = q.value(ci++).toDouble();
684
        s->mTimeSinceDeath[2] = q.value(ci++).toDouble();
685
        s->mKSW[0] = q.value(ci++).toDouble();
686
        s->mKSW[1] = q.value(ci++).toDouble();
687
        s->mKSW[2] = q.value(ci++).toDouble();
688
        s->mHalfLife[0] = q.value(ci++).toDouble();
689
        s->mHalfLife[1] = q.value(ci++).toDouble();
690
        s->mHalfLife[2] = q.value(ci++).toDouble();
691
        s->mOtherWood[0].C = q.value(ci++).toDouble(); s->mOtherWood[0].N = q.value(ci++).toDouble();
692
        s->mOtherWood[1].C = q.value(ci++).toDouble(); s->mOtherWood[1].N = q.value(ci++).toDouble();
693
        s->mOtherWood[2].C = q.value(ci++).toDouble(); s->mOtherWood[2].N = q.value(ci++).toDouble();
694
        s->mOtherWood[3].C = q.value(ci++).toDouble(); s->mOtherWood[3].N = q.value(ci++).toDouble();
695
        s->mOtherWood[4].C = q.value(ci++).toDouble(); s->mOtherWood[4].N = q.value(ci++).toDouble();
696
        s->mBranchCounter = q.value(ci++).toInt();
697
 
698
        if (++n % 1000 == 0) {
699
            qDebug() << n << "snags loaded...";
700
            QCoreApplication::processEvents();
701
        }
702
    }
703
    qDebug() << "Snapshot: finished snags. N=" << n;
704
 
705
}
706
 
695 werner 707
void Snapshot::saveSaplings()
708
{
709
    QSqlDatabase db=QSqlDatabase::database("snapshot");
710
    QSqlQuery q(db);
711
    if (!q.prepare(QString("insert into saplings (RUindex, species, posx, posy, age, height, stress_years) " \
712
                           "values (?,?,?,?,?,?,?)")))
713
        throw IException(QString("Snapshot::saveSaplings: prepare:") + q.lastError().text());
677 werner 714
 
695 werner 715
    int n = 0;
716
    db.transaction();
1162 werner 717
    throw IException("Snapshot::saveSaplings() not implemented");
718
//    foreach (const ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
719
//        foreach (const ResourceUnitSpecies *rus, ru->ruSpecies()) {
720
//            const Sapling &sap = rus->sapling();
721
//            if (sap.saplings().isEmpty())
722
//                continue;
723
//            foreach (const SaplingTreeOld &t, sap.saplings()) {
724
//                if (!t.pixel)
725
//                    continue;
726
//                q.addBindValue(ru->index());
727
//                q.addBindValue(rus->species()->id());
728
//                QPoint p=t.coords();
729
//                q.addBindValue(p.x());
730
//                q.addBindValue(p.y());
731
//                q.addBindValue(t.age.age);
732
//                q.addBindValue(t.height);
733
//                q.addBindValue(t.age.stress_years);
734
//                if (!q.exec()) {
735
//                    throw IException(QString("Snapshot::saveSaplings: execute:") + q.lastError().text());
736
//                }
737
//                if (++n % 10000 == 0) {
738
//                    qDebug() << n << "saplings saved...";
739
//                    QCoreApplication::processEvents();
740
//                }
741
//            }
742
//        }
743
//    }
695 werner 744
    db.commit();
745
    qDebug() << "Snapshot: finished saplings. N=" << n;
746
}
677 werner 747
 
695 werner 748
void Snapshot::loadSaplings()
749
{
750
    QSqlDatabase db=QSqlDatabase::database("snapshot");
751
    QSqlQuery q(db);
699 werner 752
    q.setForwardOnly(true); // avoid huge memory usage in query component
941 werner 753
    if (!q.exec("select RUindex, species, posx, posy, age, height, stress_years from saplings")) {
699 werner 754
        qDebug() << "Error when loading from saplings table...." << q.lastError().text();
755
        return;
756
    }
695 werner 757
    int ru_index = -1;
758
 
941 werner 759
    // clear all saplings in the whole project area: added for testing/debugging
760
//    foreach( ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
761
//        foreach (ResourceUnitSpecies *rus, ru->ruSpecies()) {
762
//            rus->changeSapling().clear();
763
//            rus->changeSapling().clearStatistics();
764
//        }
765
//    }
766
 
695 werner 767
    ResourceUnit *ru = 0;
1049 werner 768
    int n=0, ntotal=0;
695 werner 769
    int ci;
770
    int posx, posy;
1100 werner 771
    int offsetx=0, offsety=0;
1117 werner 772
    Saplings *saplings = GlobalSettings::instance()->model()->saplings();
1045 werner 773
 
695 werner 774
    while (q.next()) {
775
        ci = 0;
776
        ru_index = q.value(ci++).toInt();
1117 werner 777
        ru = mRUHash[ru_index];
778
        if (!ru)
779
            continue;
780
        Species *species = ru->speciesSet()->species(q.value(ci++).toString());
781
        if (!species)
782
            throw IException("Snapshot::loadSaplings: Invalid species");
783
 
1162 werner 784
        offsetx = ru->cornerPointOffset().x();
785
        offsety = ru->cornerPointOffset().y();
1117 werner 786
 
787
        posx = offsetx + q.value(ci++).toInt() % cPxPerRU;
788
        posy = offsety + q.value(ci++).toInt() % cPxPerRU;
789
 
790
        SaplingCell *sc = saplings->cell(QPoint(posx, posy));
791
        if (!sc)
792
            continue;
793
 
794
        int age=q.value(ci++).toInt();
795
        SaplingTree *st = sc->addSapling(q.value(ci++).toFloat(), age, species->index());
796
        if (!st)
797
            continue;
798
        st->stress_years = static_cast<unsigned char> (q.value(ci++).toInt());
1049 werner 799
        ++ntotal;
1117 werner 800
 
801
 
802
         if (n<10000000 && ++n % 10000 == 0) {
803
            qDebug() << n << "saplings loaded...";
804
            QCoreApplication::processEvents();
805
        }
806
        if (n>=10000000 && ++n % 1000000 == 0) {
807
            qDebug() << n << "saplings loaded...";
808
            QCoreApplication::processEvents();
809
        }
810
 
811
 
812
    }
813
    qDebug() << "Snapshot: finished loading saplings. N=" << n << "from N in snapshot:" << ntotal;
814
 
815
}
816
 
817
 
818
void Snapshot::loadSaplingsOld()
819
{
1162 werner 820
//    QSqlDatabase db=QSqlDatabase::database("snapshot");
821
//    QSqlQuery q(db);
822
//    q.setForwardOnly(true); // avoid huge memory usage in query component
823
//    if (!q.exec("select RUindex, species, posx, posy, age, height, stress_years from saplings")) {
824
//        qDebug() << "Error when loading from saplings table...." << q.lastError().text();
825
//        return;
1117 werner 826
//    }
1162 werner 827
//    int ru_index = -1;
1117 werner 828
 
1162 werner 829
//    // clear all saplings in the whole project area: added for testing/debugging
830
////    foreach( ResourceUnit *ru, GlobalSettings::instance()->model()->ruList()) {
831
////        foreach (ResourceUnitSpecies *rus, ru->ruSpecies()) {
832
////            rus->changeSapling().clear();
833
////            rus->changeSapling().clearStatistics();
834
////        }
835
////    }
1117 werner 836
 
1162 werner 837
//    ResourceUnit *ru = 0;
838
//    int n=0, ntotal=0;
839
//    int ci;
840
//    int posx, posy;
841
//    int offsetx=0, offsety=0;
842
//    Sapling *last_sapling = 0;
695 werner 843
 
1162 werner 844
//    while (q.next()) {
845
//        ci = 0;
846
//        ru_index = q.value(ci++).toInt();
847
//        ++ntotal;
848
//        ru = mRUHash[ru_index];
849
//        if (!ru)
850
//            continue;
851
//        Species *species = ru->speciesSet()->species(q.value(ci++).toString());
852
//        if (!species)
853
//            throw IException("Snapshot::loadSaplings: Invalid species");
854
//        Sapling &sap = ru->resourceUnitSpecies(species).changeSapling();
855
//        if (last_sapling != &sap) {
856
//            last_sapling = &sap;
857
//            sap.clear(); // clears the trees and the bitmap
858
//            sap.clearStatistics();
859
//            offsetx = ru->cornerPointOffset().x();
860
//            offsety = ru->cornerPointOffset().y();
861
//        }
862
//        sap.mSaplingTrees.push_back(SaplingTreeOld());
863
//        SaplingTreeOld &t = sap.mSaplingTrees.back();
864
//        //posx = q.value(ci++).toInt();
865
//        //posy = q.value(ci++).toInt();
866
//        posx = offsetx + q.value(ci++).toInt() % cPxPerRU;
867
//        posy = offsety + q.value(ci++).toInt() % cPxPerRU;
868
//        if (GlobalSettings::instance()->model()->grid()->isIndexValid(posx, posy)) {
869
//            t.pixel = GlobalSettings::instance()->model()->grid()->ptr(posx,posy );
870
//        } else {
871
//            continue;
872
//        }
873
//        t.age.age = static_cast<short unsigned int>( q.value(ci++).toInt() );
874
//        t.height = q.value(ci++).toFloat();
875
//        t.age.stress_years = static_cast<short unsigned int> (q.value(ci++).toInt() );
876
//        sap.setBit(QPoint(posx, posy), true); // set the flag in the bitmap
877
//        if (n<10000000 && ++n % 10000 == 0) {
878
//            qDebug() << n << "saplings loaded...";
879
//            QCoreApplication::processEvents();
880
//        }
881
//        if (n>=10000000 && ++n % 1000000 == 0) {
882
//            qDebug() << n << "saplings loaded...";
883
//            QCoreApplication::processEvents();
884
//        }
695 werner 885
 
886
 
1162 werner 887
//    }
888
//    qDebug() << "Snapshot: finished loading saplings. N=" << n << "from N in snapshot:" << ntotal;
889
 
695 werner 890
}
891
 
892