Subversion Repositories public iLand

Rev

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

Rev 639 Rev 671
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/phenology.cpp':
1
Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/phenology.cpp':
-
 
2
/********************************************************************************************
-
 
3
**    iLand - an individual based forest landscape and disturbance model
-
 
4
**    http://iland.boku.ac.at
-
 
5
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
-
 
6
**
-
 
7
**    This program is free software: you can redistribute it and/or modify
-
 
8
**    it under the terms of the GNU General Public License as published by
-
 
9
**    the Free Software Foundation, either version 3 of the License, or
-
 
10
**    (at your option) any later version.
-
 
11
**
-
 
12
**    This program is distributed in the hope that it will be useful,
-
 
13
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
-
 
14
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
 
15
**    GNU General Public License for more details.
-
 
16
**
-
 
17
**    You should have received a copy of the GNU General Public License
-
 
18
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
 
19
********************************************************************************************/
-
 
20
2
#include "global.h"
21
#include "global.h"
3
#include "phenology.h"
22
#include "phenology.h"
4
23
5
#include "climate.h"
24
#include "climate.h"
6
#include "floatingaverage.h"
25
#include "floatingaverage.h"
7
26
8
/// "ramp" function: value < min: 0, value>max: 1: in between linear interpolation
27
/// "ramp" function: value < min: 0, value>max: 1: in between linear interpolation
9
double ramp(const double &value, const double minValue, const double maxValue)
28
double ramp(const double &value, const double minValue, const double maxValue)
10
{
29
{
11
    Q_ASSERT(minValue!=maxValue);
30
    Q_ASSERT(minValue!=maxValue);
12
    if (value<minValue) return 0.;
31
    if (value<minValue) return 0.;
13
    if (value>maxValue) return 1.;
32
    if (value>maxValue) return 1.;
14
    return (value-minValue) / (maxValue - minValue);
33
    return (value-minValue) / (maxValue - minValue);
15
}
34
}
16
35
17
/** calculates the phenology according to Jolly et al. 2005.
36
/** calculates the phenology according to Jolly et al. 2005.
18
  The calculation is performed for a given "group" and a present "climate".
37
  The calculation is performed for a given "group" and a present "climate".
19
*/
38
*/
20
void Phenology::calculate()
39
void Phenology::calculate()
21
{
40
{
22
    if (id()==0) {
41
    if (id()==0) {
23
        // for needles: just calculate the chilling requirement for the establishment
42
        // for needles: just calculate the chilling requirement for the establishment
24
        // i.e.: use the "bottom line" of 10.5 hrs daylength for the end of the vegetation season
43
        // i.e.: use the "bottom line" of 10.5 hrs daylength for the end of the vegetation season
25
        calculateChillDays(mClimate->sun().dayShorter10_5hrs());
44
        calculateChillDays(mClimate->sun().dayShorter10_5hrs());
26
        return;
45
        return;
27
    }
46
    }
28
    const ClimateDay  *end = mClimate->end();
47
    const ClimateDay  *end = mClimate->end();
29
    double vpd,temp,daylength;
48
    double vpd,temp,daylength;
30
    double gsi; // combined factor of effect of vpd, temperature and day length
49
    double gsi; // combined factor of effect of vpd, temperature and day length
31
    int iday = 0;
50
    int iday = 0;
32
    bool inside_period = !mClimate->sun().northernHemishere(); // on northern hemisphere 1.1. is in winter
51
    bool inside_period = !mClimate->sun().northernHemishere(); // on northern hemisphere 1.1. is in winter
33
    int day_start=-1, day_stop=-1;
52
    int day_start=-1, day_stop=-1;
34
    int day_wait_for=-1;
53
    int day_wait_for=-1;
35
54
36
    FloatingAverage floater(21); // a three-week floating average
55
    FloatingAverage floater(21); // a three-week floating average
37
    for (const ClimateDay *day = mClimate->begin(); day!=end; ++day, ++iday) {
56
    for (const ClimateDay *day = mClimate->begin(); day!=end; ++day, ++iday) {
38
57
39
        if (day_wait_for>=0 && iday<day_wait_for)
58
        if (day_wait_for>=0 && iday<day_wait_for)
40
            continue;
59
            continue;
41
        vpd = 1. - ramp(day->vpd, mMinVpd, mMaxVpd); // high value for low vpd
60
        vpd = 1. - ramp(day->vpd, mMinVpd, mMaxVpd); // high value for low vpd
42
        temp = ramp(day->min_temperature, mMinTemp, mMaxTemp);
61
        temp = ramp(day->min_temperature, mMinTemp, mMaxTemp);
43
        daylength = ramp( mClimate->sun().daylength(iday), mMinDayLength, mMaxDayLength);
62
        daylength = ramp( mClimate->sun().daylength(iday), mMinDayLength, mMaxDayLength);
44
        gsi = vpd * temp * daylength;
63
        gsi = vpd * temp * daylength;
45
        gsi = floater.add(gsi);
64
        gsi = floater.add(gsi);
46
        if (!inside_period && gsi>0.5) {
65
        if (!inside_period && gsi>0.5) {
47
            // switch from winter -> summer
66
            // switch from winter -> summer
48
            inside_period = true;
67
            inside_period = true;
49
            day_start = iday;
68
            day_start = iday;
50
            if (day_stop!=-1)
69
            if (day_stop!=-1)
51
                break;
70
                break;
52
            day_wait_for = mClimate->sun().longestDay();
71
            day_wait_for = mClimate->sun().longestDay();
53
        } else if (inside_period && gsi<0.5) {
72
        } else if (inside_period && gsi<0.5) {
54
            // switch from summer to winter
73
            // switch from summer to winter
55
            day_stop = iday;
74
            day_stop = iday;
56
            if (day_start!=-1)
75
            if (day_start!=-1)
57
                break; // finished
76
                break; // finished
58
            day_wait_for = mClimate->sun().longestDay();
77
            day_wait_for = mClimate->sun().longestDay();
59
            inside_period = false;
78
            inside_period = false;
60
        }
79
        }
61
    }
80
    }
62
    day_start -= 10; // three-week-floating average: subtract 10 days
81
    day_start -= 10; // three-week-floating average: subtract 10 days
63
    day_stop -= 10;
82
    day_stop -= 10;
64
    if (day_start < -1 || day_stop<-1)
83
    if (day_start < -1 || day_stop<-1)
65
        throw IException(QString("Phenology::calculation(): was not able to determine the length of the vegetation period for group %1." ).arg(id()));
84
        throw IException(QString("Phenology::calculation(): was not able to determine the length of the vegetation period for group %1." ).arg(id()));
66
    if (logLevelDebug())
85
    if (logLevelDebug())
67
        qDebug() << "Jolly-phenology. start" << mClimate->dayOfYear(day_start)->toString() << "stop" << mClimate->dayOfYear(day_stop)->toString();
86
        qDebug() << "Jolly-phenology. start" << mClimate->dayOfYear(day_start)->toString() << "stop" << mClimate->dayOfYear(day_stop)->toString();
68
    iday = 0;
87
    iday = 0;
69
    mDayStart = day_start;
88
    mDayStart = day_start;
70
    mDayEnd = day_stop;
89
    mDayEnd = day_stop;
71
    int bDay, bMon, eDay, eMon;
90
    int bDay, bMon, eDay, eMon;
72
    // convert yeardays to dates
91
    // convert yeardays to dates
73
    mClimate->toDate(day_start, &bDay, &bMon);
92
    mClimate->toDate(day_start, &bDay, &bMon);
74
    mClimate->toDate(day_stop, &eDay, &eMon);
93
    mClimate->toDate(day_stop, &eDay, &eMon);
75
    for (int i=0;i<12;i++) {
94
    for (int i=0;i<12;i++) {
76
        if (i<bMon || i>eMon) {
95
        if (i<bMon || i>eMon) {
77
            mPhenoFraction[i] = 0; // out of season
96
            mPhenoFraction[i] = 0; // out of season
78
        } else if (i>bMon && i<eMon) {
97
        } else if (i>bMon && i<eMon) {
79
            mPhenoFraction[i] = 1.; // full inside of season
98
            mPhenoFraction[i] = 1.; // full inside of season
80
        } else {
99
        } else {
81
            // fractions of month
100
            // fractions of month
82
            mPhenoFraction[i] = 1.;
101
            mPhenoFraction[i] = 1.;
83
            if (i==bMon)
102
            if (i==bMon)
84
                mPhenoFraction[i] -=  (bDay+1) / double(mClimate->days(bMon));
103
                mPhenoFraction[i] -=  (bDay+1) / double(mClimate->days(bMon));
85
            if (i==eMon)
104
            if (i==eMon)
86
                mPhenoFraction[i] -=  (mClimate->days(eMon) - (bDay+1)) / double(mClimate->days(eMon));
105
                mPhenoFraction[i] -=  (mClimate->days(eMon) - (bDay+1)) / double(mClimate->days(eMon));
87
        }
106
        }
88
    }
107
    }
89
108
90
    calculateChillDays();
109
    calculateChillDays();
91
}
110
}
92
111
93
112
94
// *********** Chill-day calculations ********
113
// *********** Chill-day calculations ********
95
void Phenology::calculateChillDays(const int end_of_season)
114
void Phenology::calculateChillDays(const int end_of_season)
96
{
115
{
97
    int iday = 0;
116
    int iday = 0;
98
    mChillDaysBefore = 0;
117
    mChillDaysBefore = 0;
99
    int days_after = 0;
118
    int days_after = 0;
100
    int last_day = end_of_season>0?end_of_season:mDayEnd;
119
    int last_day = end_of_season>0?end_of_season:mDayEnd;
101
    for (const ClimateDay *day = mClimate->begin(); day!=mClimate->end(); ++day, ++iday) {
120
    for (const ClimateDay *day = mClimate->begin(); day!=mClimate->end(); ++day, ++iday) {
102
        if (day->temperature>=-5 && day->temperature<5) {
121
        if (day->temperature>=-5 && day->temperature<5) {
103
            if (iday<mDayStart)
122
            if (iday<mDayStart)
104
                mChillDaysBefore++;
123
                mChillDaysBefore++;
105
            if (iday>last_day)
124
            if (iday>last_day)
106
                days_after++;
125
                days_after++;
107
        }
126
        }
108
    }
127
    }
109
    if (GlobalSettings::instance()->currentYear()==1) {
128
    if (GlobalSettings::instance()->currentYear()==1) {
110
        // for the first simulation year, use the value of this autumn for the last years autumn
129
        // for the first simulation year, use the value of this autumn for the last years autumn
111
        mChillDaysAfterLastYear = days_after;
130
        mChillDaysAfterLastYear = days_after;
112
    } else {
131
    } else {
113
        mChillDaysAfterLastYear  = mChillDaysAfter;
132
        mChillDaysAfterLastYear  = mChillDaysAfter;
114
    }
133
    }
115
    mChillDaysAfter = days_after;
134
    mChillDaysAfter = days_after;
116
}
135
}
117
 
136