Subversion Repositories public iLand

Rev

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

Rev 210 Rev 211
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/speciesset.cpp':
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/speciesset.cpp':
2
#include <QtCore>
2
#include <QtCore>
3
#include <QtSql>
3
#include <QtSql>
4
#include "global.h"
4
#include "global.h"
5
#include "xmlhelper.h"
5
#include "xmlhelper.h"
6
#include "speciesset.h"
6
#include "speciesset.h"
7
#include "species.h"
7
#include "species.h"
8
8
9
SpeciesSet::SpeciesSet()
9
SpeciesSet::SpeciesSet()
10
{
10
{
11
    mSetupQuery = 0;
11
    mSetupQuery = 0;
12
}
12
}
13
13
14
SpeciesSet::~SpeciesSet()
14
SpeciesSet::~SpeciesSet()
15
{
15
{
16
   clear();
16
   clear();
17
}
17
}
18
18
19
void SpeciesSet::clear()
19
void SpeciesSet::clear()
20
{
20
{
21
    qDeleteAll(mSpecies.values());
21
    qDeleteAll(mSpecies.values());
22
    mSpecies.clear();
22
    mSpecies.clear();
23
    mActiveSpecies.clear();
23
    mActiveSpecies.clear();
24
}
24
}
25
25
26
const Species *SpeciesSet::species(const int &index)
26
const Species *SpeciesSet::species(const int &index)
27
{
27
{
28
    foreach(Species *s, mSpecies)
28
    foreach(Species *s, mSpecies)
29
        if (s->index() == index)
29
        if (s->index() == index)
30
            return s;
30
            return s;
31
    return NULL;
31
    return NULL;
32
}
32
}
33
33
34
/** loads active species from a database table and creates/setups the species.
34
/** loads active species from a database table and creates/setups the species.
35
    The function uses the global database-connection.
35
    The function uses the global database-connection.
36
  */
36
  */
37
int SpeciesSet::setup()
37
int SpeciesSet::setup()
38
{
38
{
-
 
39
    // setup phenology
-
 
40
    setupPhenology();
-
 
41
39
    const XmlHelper &xml = GlobalSettings::instance()->settings();
42
    const XmlHelper &xml = GlobalSettings::instance()->settings();
40
    QString tableName = xml.value("model.species.source", "species");
43
    QString tableName = xml.value("model.species.source", "species");
41
    QString readerFile = xml.value("model.species.reader", "reader.bin");
44
    QString readerFile = xml.value("model.species.reader", "reader.bin");
42
    readerFile = GlobalSettings::instance()->path(readerFile, "lip");
45
    readerFile = GlobalSettings::instance()->path(readerFile, "lip");
43
    mReaderStamp.load(readerFile);
46
    mReaderStamp.load(readerFile);
44
47
45
    QSqlQuery query(GlobalSettings::instance()->dbin());
48
    QSqlQuery query(GlobalSettings::instance()->dbin());
46
    mSetupQuery = &query;
49
    mSetupQuery = &query;
47
    QString sql = QString("select * from %1").arg(tableName);
50
    QString sql = QString("select * from %1").arg(tableName);
48
    query.exec(sql);
51
    query.exec(sql);
49
    clear();
52
    clear();
50
    qDebug() << "attempting to load a species set from" << tableName;
53
    qDebug() << "attempting to load a species set from" << tableName;
51
    while (query.next()) {
54
    while (query.next()) {
52
        if (var("active").toInt()==0)
55
        if (var("active").toInt()==0)
53
            continue;
56
            continue;
54
57
55
        Species *s = new Species(this); // create
58
        Species *s = new Species(this); // create
56
        // call setup routine (which calls SpeciesSet::var() to retrieve values
59
        // call setup routine (which calls SpeciesSet::var() to retrieve values
57
        s->setup();
60
        s->setup();
58
61
59
        mSpecies.insert(s->id(), s); // store
62
        mSpecies.insert(s->id(), s); // store
60
        if (s->active())
63
        if (s->active())
61
            mActiveSpecies.append(s);
64
            mActiveSpecies.append(s);
62
    } // while query.next()
65
    } // while query.next()
63
    qDebug() << "loaded" << mSpecies.count() << "active species:";
66
    qDebug() << "loaded" << mSpecies.count() << "active species:";
64
    qDebug() << mSpecies.keys();
67
    qDebug() << mSpecies.keys();
65
68
66
    mSetupQuery = 0;
69
    mSetupQuery = 0;
67
70
68
    // setup nitrogen response
71
    // setup nitrogen response
69
    XmlHelper resp(xml.node("model.species.nitrogenResponseClasses"));
72
    XmlHelper resp(xml.node("model.species.nitrogenResponseClasses"));
70
    if (!resp.isValid())
73
    if (!resp.isValid())
71
        throw IException("model.species.nitrogenResponseClasses not present!");
74
        throw IException("model.species.nitrogenResponseClasses not present!");
72
    mNitrogen_1a = resp.valueDouble("class_1_a");
75
    mNitrogen_1a = resp.valueDouble("class_1_a");
73
    mNitrogen_1b = resp.valueDouble("class_1_b");
76
    mNitrogen_1b = resp.valueDouble("class_1_b");
74
    mNitrogen_2a = resp.valueDouble("class_2_a");
77
    mNitrogen_2a = resp.valueDouble("class_2_a");
75
    mNitrogen_2b = resp.valueDouble("class_2_b");
78
    mNitrogen_2b = resp.valueDouble("class_2_b");
76
    mNitrogen_3a = resp.valueDouble("class_3_a");
79
    mNitrogen_3a = resp.valueDouble("class_3_a");
77
    mNitrogen_3b = resp.valueDouble("class_3_b");
80
    mNitrogen_3b = resp.valueDouble("class_3_b");
78
    if (mNitrogen_1a*mNitrogen_1b*mNitrogen_2a*mNitrogen_2b*mNitrogen_3a*mNitrogen_3b == 0)
81
    if (mNitrogen_1a*mNitrogen_1b*mNitrogen_2a*mNitrogen_2b*mNitrogen_3a*mNitrogen_3b == 0)
79
        throw IException("at least one parameter of model.species.nitrogenResponseClasses is not valid (value=0)!");
82
        throw IException("at least one parameter of model.species.nitrogenResponseClasses is not valid (value=0)!");
80
83
81
    // setup CO2 response
84
    // setup CO2 response
82
    XmlHelper co2(xml.node("model.species.CO2Response"));
85
    XmlHelper co2(xml.node("model.species.CO2Response"));
83
    mCO2base = co2.valueDouble("baseConcentration");
86
    mCO2base = co2.valueDouble("baseConcentration");
84
    mCO2comp = co2.valueDouble("compensationPoint");
87
    mCO2comp = co2.valueDouble("compensationPoint");
85
    mCO2beta0 = co2.valueDouble("beta0");
88
    mCO2beta0 = co2.valueDouble("beta0");
86
    mCO2p0 = co2.valueDouble("p0");
89
    mCO2p0 = co2.valueDouble("p0");
87
    if (mCO2base*mCO2comp*(mCO2base-mCO2comp)*mCO2beta0*mCO2p0==0)
90
    if (mCO2base*mCO2comp*(mCO2base-mCO2comp)*mCO2beta0*mCO2p0==0)
88
        throw IException("at least one parameter of model.species.CO2Response is not valid!");
91
        throw IException("at least one parameter of model.species.CO2Response is not valid!");
89
92
90
    return mSpecies.count();
93
    return mSpecies.count();
91
94
92
}
95
}
-
 
96
-
 
97
void SpeciesSet::setupPhenology()
-
 
98
{
-
 
99
    mPhenology.clear();
-
 
100
    mPhenology.push_back(Phenology()); // id=0
-
 
101
    XmlHelper xml(GlobalSettings::instance()->settings().node("model.species.phenology"));
-
 
102
    int i=0;
-
 
103
    do {
-
 
104
        QDomElement n = xml.node(QString("type[%1]").arg(i));
-
 
105
        if (n.isNull())
-
 
106
            break;
-
 
107
        i++;
-
 
108
        int id;
-
 
109
        id = n.attribute("id", "-1").toInt();
-
 
110
        if (id<0) throw IException(QString("Error setting up phenology: id invalid\ndump: %1").arg(xml.dump("")));
-
 
111
        xml.setCurrentNode(QString("type[%1]").arg(i));
-
 
112
        Phenology item( id,
-
 
113
                        xml.valueDouble(".vpdMin",0.5), // use relative access to node (".x")
-
 
114
                        xml.valueDouble(".vpdMax", 5),
-
 
115
                        xml.valueDouble(".minDayLength",10),
-
 
116
                        xml.valueDouble(".maxDayLength",11),
-
 
117
                        xml.valueDouble(".tempMin", 2),
-
 
118
                        xml.valueDouble(".tempMax", 9) );
-
 
119
-
 
120
        mPhenology.push_back(item);
-
 
121
    } while(true);
-
 
122
-
 
123
}
-
 
124
93
/** retrieves variables from the datasource available during the setup of species.
125
/** retrieves variables from the datasource available during the setup of species.
94
  */
126
  */
95
QVariant SpeciesSet::var(const QString& varName)
127
QVariant SpeciesSet::var(const QString& varName)
96
{
128
{
97
    Q_ASSERT(mSetupQuery!=0);
129
    Q_ASSERT(mSetupQuery!=0);
98
130
99
    int idx = mSetupQuery->record().indexOf(varName);
131
    int idx = mSetupQuery->record().indexOf(varName);
100
    if (idx>=0)
132
    if (idx>=0)
101
        return mSetupQuery->value(idx);
133
        return mSetupQuery->value(idx);
102
    throw IException(QString("SpeciesSet: variable not set: %1").arg(varName));
134
    throw IException(QString("SpeciesSet: variable not set: %1").arg(varName));
103
    //throw IException(QString("load species parameter: field %1 not found!").arg(varName));
135
    //throw IException(QString("load species parameter: field %1 not found!").arg(varName));
104
    // lookup in defaults
136
    // lookup in defaults
105
    //qDebug() << "variable" << varName << "not found - using default.";
137
    //qDebug() << "variable" << varName << "not found - using default.";
106
    //return GlobalSettings::instance()->settingDefaultValue(varName);
138
    //return GlobalSettings::instance()->settingDefaultValue(varName);
107
}
139
}
108
140
109
inline double SpeciesSet::nitrogenResponse(const double &availableNitrogen, const double &NA, const double &NB) const
141
inline double SpeciesSet::nitrogenResponse(const double &availableNitrogen, const double &NA, const double &NB) const
110
{
142
{
111
    if (availableNitrogen<=NB)
143
    if (availableNitrogen<=NB)
112
        return 0;
144
        return 0;
113
    double x = 1. - exp(NA * (availableNitrogen-NB));
145
    double x = 1. - exp(NA * (availableNitrogen-NB));
114
    return x;
146
    return x;
115
}
147
}
116
148
117
/// calculate nitrogen response for a given amount of available nitrogen and a respone class
149
/// calculate nitrogen response for a given amount of available nitrogen and a respone class
118
/// for fractional values, the response value is interpolated between the fixedly defined classes (1,2,3)
150
/// for fractional values, the response value is interpolated between the fixedly defined classes (1,2,3)
119
double SpeciesSet::nitrogenResponse(const double availableNitrogen, const double &responseClass) const
151
double SpeciesSet::nitrogenResponse(const double availableNitrogen, const double &responseClass) const
120
{
152
{
121
    double value1, value2, value3;
153
    double value1, value2, value3;
122
    if (responseClass>2.) {
154
    if (responseClass>2.) {
123
        if (responseClass==3.)
155
        if (responseClass==3.)
124
            return nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
156
            return nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
125
        else {
157
        else {
126
            // interpolate between 2 and 3
158
            // interpolate between 2 and 3
127
            value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
159
            value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
128
            value3 = nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
160
            value3 = nitrogenResponse(availableNitrogen, mNitrogen_3a, mNitrogen_3b);
129
            return value2 + (responseClass-2)*(value3-value2);
161
            return value2 + (responseClass-2)*(value3-value2);
130
        }
162
        }
131
    }
163
    }
132
    if (responseClass==2)
164
    if (responseClass==2)
133
        return nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
165
        return nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
134
    if (responseClass==1)
166
    if (responseClass==1)
135
        return nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
167
        return nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
136
    // last ressort: interpolate between 1 and 2
168
    // last ressort: interpolate between 1 and 2
137
    value1 = nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
169
    value1 = nitrogenResponse(availableNitrogen, mNitrogen_1a, mNitrogen_1b);
138
    value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
170
    value2 = nitrogenResponse(availableNitrogen, mNitrogen_2a, mNitrogen_2b);
139
    return value1 + (responseClass-1)*(value2-value1);
171
    return value1 + (responseClass-1)*(value2-value1);
140
}
172
}
141
173
142
/** calculation for the CO2 response for the ambientCO2 for the water- and nitrogen responses given.
174
/** calculation for the CO2 response for the ambientCO2 for the water- and nitrogen responses given.
143
    The calculation follows Friedlingsstein 1995 (see also links to equations in code)
175
    The calculation follows Friedlingsstein 1995 (see also links to equations in code)
144
*/
176
*/
145
double SpeciesSet::co2Response(const double ambientCO2, const double nitrogenResponse, const double soilWaterResponse) const
177
double SpeciesSet::co2Response(const double ambientCO2, const double nitrogenResponse, const double soilWaterResponse) const
146
{
178
{
147
    if (nitrogenResponse==0)
179
    if (nitrogenResponse==0)
148
        return 0.;
180
        return 0.;
149
181
150
    double co2_water = 2. - soilWaterResponse;
182
    double co2_water = 2. - soilWaterResponse;
151
    double beta = mCO2beta0 * co2_water * nitrogenResponse;
183
    double beta = mCO2beta0 * co2_water * nitrogenResponse;
152
184
153
    double r =1. +  M_LN2 * beta; // NPP increase for a doubling of atmospheric CO2 (Eq. 17)
185
    double r =1. +  M_LN2 * beta; // NPP increase for a doubling of atmospheric CO2 (Eq. 17)
154
186
155
    // fertilization function (cf. Farquhar, 1980) based on Michaelis-Menten expressions
187
    // fertilization function (cf. Farquhar, 1980) based on Michaelis-Menten expressions
156
    double deltaC = mCO2base - mCO2comp;
188
    double deltaC = mCO2base - mCO2comp;
157
    double K2 = ((2*mCO2base - mCO2comp) - r*deltaC ) / ((r-1.)*deltaC*(2*mCO2base - mCO2comp)); // Eq. 16
189
    double K2 = ((2*mCO2base - mCO2comp) - r*deltaC ) / ((r-1.)*deltaC*(2*mCO2base - mCO2comp)); // Eq. 16
158
    double K1 = (1. + K2*deltaC) / deltaC;
190
    double K1 = (1. + K2*deltaC) / deltaC;
159
191
160
    double response = mCO2p0 * K1*(ambientCO2 - mCO2comp) / (1 + K2*(ambientCO2-mCO2comp)); // Eq. 16
192
    double response = mCO2p0 * K1*(ambientCO2 - mCO2comp) / (1 + K2*(ambientCO2-mCO2comp)); // Eq. 16
161
    return response;
193
    return response;
162
194
-
 
195
}
-
 
196
-
 
197
/** return the phenology of the group... */
-
 
198
const Phenology &SpeciesSet::phenology(const int phenologyGroup)
-
 
199
{
-
 
200
    const Phenology &p = mPhenology.at(phenologyGroup);
-
 
201
    if (p.id() == phenologyGroup)
-
 
202
        return p;
-
 
203
    // search...
-
 
204
    for (int i=0;i<mPhenology.count();i++)
-
 
205
        if (mPhenology[i].id()==phenologyGroup)
-
 
206
            return mPhenology[i];
-
 
207
    throw IException(QString("Error at SpeciesSEt::phenology(): invalid group: %1").arg(phenologyGroup));
163
}
208
}
164
 
209