Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
1
 
91 Werner 2
#include <QtCore>
3
#include <QtSql>
4
#include "global.h"
102 Werner 5
#include "xmlhelper.h"
90 Werner 6
#include "speciesset.h"
91 Werner 7
#include "species.h"
387 werner 8
#include "model.h"
9
#include "seeddispersal.h"
90 Werner 10
 
11
SpeciesSet::SpeciesSet()
12
{
91 Werner 13
    mSetupQuery = 0;
90 Werner 14
}
91 Werner 15
 
16
SpeciesSet::~SpeciesSet()
17
{
18
   clear();
19
}
20
 
21
void SpeciesSet::clear()
22
{
23
    qDeleteAll(mSpecies.values());
387 werner 24
    qDeleteAll(mSeedDispersal);
91 Werner 25
    mSpecies.clear();
179 werner 26
    mActiveSpecies.clear();
91 Werner 27
}
28
 
111 Werner 29
const Species *SpeciesSet::species(const int &index)
30
{
31
    foreach(Species *s, mSpecies)
32
        if (s->index() == index)
33
            return s;
34
    return NULL;
35
}
91 Werner 36
 
37
/** loads active species from a database table and creates/setups the species.
38
    The function uses the global database-connection.
39
  */
102 Werner 40
int SpeciesSet::setup()
91 Werner 41
{
102 Werner 42
    const XmlHelper &xml = GlobalSettings::instance()->settings();
191 werner 43
    QString tableName = xml.value("model.species.source", "species");
318 werner 44
    mName = tableName;
191 werner 45
    QString readerFile = xml.value("model.species.reader", "reader.bin");
102 Werner 46
    readerFile = GlobalSettings::instance()->path(readerFile, "lip");
47
    mReaderStamp.load(readerFile);
48
 
91 Werner 49
    QSqlQuery query(GlobalSettings::instance()->dbin());
50
    mSetupQuery = &query;
51
    QString sql = QString("select * from %1").arg(tableName);
52
    query.exec(sql);
270 werner 53
    if (query.lastError().isValid()){
54
        throw IException(QString("Error loading species set: %1 \n %2").arg(sql, query.lastError().text()) );
55
    }
56
 
91 Werner 57
    clear();
58
    qDebug() << "attempting to load a species set from" << tableName;
59
    while (query.next()) {
60
        if (var("active").toInt()==0)
61
            continue;
62
 
63
        Species *s = new Species(this); // create
99 Werner 64
        // call setup routine (which calls SpeciesSet::var() to retrieve values
91 Werner 65
        s->setup();
66
 
67
        mSpecies.insert(s->id(), s); // store
179 werner 68
        if (s->active())
69
            mActiveSpecies.append(s);
91 Werner 70
    } // while query.next()
71
    qDebug() << "loaded" << mSpecies.count() << "active species:";
72
    qDebug() << mSpecies.keys();
73
 
74
    mSetupQuery = 0;
209 werner 75
 
76
    // setup nitrogen response
77
    XmlHelper resp(xml.node("model.species.nitrogenResponseClasses"));
78
    if (!resp.isValid())
79
        throw IException("model.species.nitrogenResponseClasses not present!");
80
    mNitrogen_1a = resp.valueDouble("class_1_a");
81
    mNitrogen_1b = resp.valueDouble("class_1_b");
82
    mNitrogen_2a = resp.valueDouble("class_2_a");
83
    mNitrogen_2b = resp.valueDouble("class_2_b");
84
    mNitrogen_3a = resp.valueDouble("class_3_a");
85
    mNitrogen_3b = resp.valueDouble("class_3_b");
86
    if (mNitrogen_1a*mNitrogen_1b*mNitrogen_2a*mNitrogen_2b*mNitrogen_3a*mNitrogen_3b == 0)
87
        throw IException("at least one parameter of model.species.nitrogenResponseClasses is not valid (value=0)!");
88
 
89
    // setup CO2 response
90
    XmlHelper co2(xml.node("model.species.CO2Response"));
91
    mCO2base = co2.valueDouble("baseConcentration");
92
    mCO2comp = co2.valueDouble("compensationPoint");
93
    mCO2beta0 = co2.valueDouble("beta0");
94
    mCO2p0 = co2.valueDouble("p0");
95
    if (mCO2base*mCO2comp*(mCO2base-mCO2comp)*mCO2beta0*mCO2p0==0)
96
        throw IException("at least one parameter of model.species.CO2Response is not valid!");
97
 
274 werner 98
    // setup Light responses
99
    XmlHelper light(xml.node("model.species.lightResponse"));
100
    mLightResponseTolerant.setAndParse(light.value("shadeTolerant"));
101
    mLightResponseIntolerant.setAndParse(light.value("shadeIntolerant"));
102
    if (mLightResponseTolerant.expression().isEmpty() || mLightResponseIntolerant.expression().isEmpty())
103
        throw IException("at least one parameter of model.species.lightResponse is empty!");
104
 
387 werner 105
    // setup of regeneration related stuff like seed dispersal maps
106
    if (xml.valueBool("model.settings.regenerationEnabled", false)) {
107
        foreach(Species *s, mActiveSpecies) {
108
            SeedDispersal *sd = new SeedDispersal(s);
109
            sd->setup(); // setup memory for the seed map (grid)
110
            s->setSeedDispersal(sd); // establish the link between species and the map
111
 
112
        }
113
    }
91 Werner 114
    return mSpecies.count();
115
 
116
}
211 werner 117
 
118
 
91 Werner 119
/** retrieves variables from the datasource available during the setup of species.
120
  */
121
QVariant SpeciesSet::var(const QString& varName)
122
{
94 Werner 123
    Q_ASSERT(mSetupQuery!=0);
91 Werner 124
 
125
    int idx = mSetupQuery->record().indexOf(varName);
126
    if (idx>=0)
127
        return mSetupQuery->value(idx);
125 Werner 128
    throw IException(QString("SpeciesSet: variable not set: %1").arg(varName));
120 Werner 129
    //throw IException(QString("load species parameter: field %1 not found!").arg(varName));
91 Werner 130
    // lookup in defaults
119 Werner 131
    //qDebug() << "variable" << varName << "not found - using default.";
132
    //return GlobalSettings::instance()->settingDefaultValue(varName);
91 Werner 133
}
209 werner 134
 
135
inline double SpeciesSet::nitrogenResponse(const double &availableNitrogen, const double &NA, const double &NB) const
136
{
137
    if (availableNitrogen<=NB)
138
        return 0;
139
    double x = 1. - exp(NA * (availableNitrogen-NB));
140
    return x;
141
}
142
 
143
/// calculate nitrogen response for a given amount of available nitrogen and a respone class
144
/// for fractional values, the response value is interpolated between the fixedly defined classes (1,2,3)
145
double SpeciesSet::nitrogenResponse(const double availableNitrogen, const double &responseClass) const
146
{
147
    double value1, value2, value3;
148
    if (responseClass>2.) {
149
        if (responseClass==3.)
150
            return nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
151
        else {
152
            // interpolate between 2 and 3
153
            value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
154
            value3 = nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
155
            return value2 + (responseClass-2)*(value3-value2);
156
        }
157
    }
158
    if (responseClass==2)
159
        return nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
160
    if (responseClass==1)
161
        return nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
162
    // last ressort: interpolate between 1 and 2
163
    value1 = nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
164
    value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
165
    return value1 + (responseClass-1)*(value2-value1);
166
}
167
 
168
/** calculation for the CO2 response for the ambientCO2 for the water- and nitrogen responses given.
169
    The calculation follows Friedlingsstein 1995 (see also links to equations in code)
170
*/
171
double SpeciesSet::co2Response(const double ambientCO2, const double nitrogenResponse, const double soilWaterResponse) const
172
{
210 werner 173
    if (nitrogenResponse==0)
174
        return 0.;
175
 
209 werner 176
    double co2_water = 2. - soilWaterResponse;
177
    double beta = mCO2beta0 * co2_water * nitrogenResponse;
178
 
179
    double r =1. +  M_LN2 * beta; // NPP increase for a doubling of atmospheric CO2 (Eq. 17)
180
 
181
    // fertilization function (cf. Farquhar, 1980) based on Michaelis-Menten expressions
182
    double deltaC = mCO2base - mCO2comp;
183
    double K2 = ((2*mCO2base - mCO2comp) - r*deltaC ) / ((r-1.)*deltaC*(2*mCO2base - mCO2comp)); // Eq. 16
184
    double K1 = (1. + K2*deltaC) / deltaC;
185
 
186
    double response = mCO2p0 * K1*(ambientCO2 - mCO2comp) / (1 + K2*(ambientCO2-mCO2comp)); // Eq. 16
187
    return response;
188
 
189
}
211 werner 190
 
274 werner 191
/** calculates the lightResponse based on a value for LRI and the species lightResponseClass.
192
    LightResponse is classified from 1 (very shade inolerant) and 5 (very shade tolerant) and interpolated for values between 1 and 5.
298 werner 193
    Returns a value between 0..1
194
    @sa http://iland.boku.ac.at/allocation#reserve_and_allocation_to_stem_growth */
274 werner 195
double SpeciesSet::lightResponse(const double lightResourceIndex, const double lightResponseClass)
196
{
197
    QMutexLocker l(&mMutex); // serialize access to calculations
198
    double low = mLightResponseIntolerant.calculate(lightResourceIndex);
199
    double high = mLightResponseTolerant.calculate(lightResourceIndex);
200
    double result = low + 0.25*(lightResponseClass-1.)*(high-low);
201
    return limit(result, 0., 1.);
214 werner 202
 
274 werner 203
}
204
 
205
 
206