Subversion Repositories public iLand

Rev

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

Rev Author Line No. Line
1
 
671 werner 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
 
211 werner 21
#include "global.h"
22
#include "phenology.h"
23
 
24
#include "climate.h"
214 werner 25
#include "floatingaverage.h"
26
 
27
/// "ramp" function: value < min: 0, value>max: 1: in between linear interpolation
28
double ramp(const double &value, const double minValue, const double maxValue)
29
{
30
    Q_ASSERT(minValue!=maxValue);
31
    if (value<minValue) return 0.;
32
    if (value>maxValue) return 1.;
33
    return (value-minValue) / (maxValue - minValue);
34
}
35
 
36
/** calculates the phenology according to Jolly et al. 2005.
226 werner 37
  The calculation is performed for a given "group" and a present "climate".
214 werner 38
*/
39
void Phenology::calculate()
40
{
436 werner 41
    if (id()==0) {
42
        // for needles: just calculate the chilling requirement for the establishment
440 werner 43
        // i.e.: use the "bottom line" of 10.5 hrs daylength for the end of the vegetation season
44
        calculateChillDays(mClimate->sun().dayShorter10_5hrs());
214 werner 45
        return;
436 werner 46
    }
214 werner 47
    const ClimateDay  *end = mClimate->end();
48
    double vpd,temp,daylength;
49
    double gsi; // combined factor of effect of vpd, temperature and day length
50
    int iday = 0;
51
    bool inside_period = !mClimate->sun().northernHemishere(); // on northern hemisphere 1.1. is in winter
52
    int day_start=-1, day_stop=-1;
53
    int day_wait_for=-1;
54
 
55
    FloatingAverage floater(21); // a three-week floating average
56
    for (const ClimateDay *day = mClimate->begin(); day!=end; ++day, ++iday) {
57
 
58
        if (day_wait_for>=0 && iday<day_wait_for)
59
            continue;
60
        vpd = 1. - ramp(day->vpd, mMinVpd, mMaxVpd); // high value for low vpd
441 werner 61
        temp = ramp(day->min_temperature, mMinTemp, mMaxTemp);
214 werner 62
        daylength = ramp( mClimate->sun().daylength(iday), mMinDayLength, mMaxDayLength);
63
        gsi = vpd * temp * daylength;
64
        gsi = floater.add(gsi);
65
        if (!inside_period && gsi>0.5) {
66
            // switch from winter -> summer
67
            inside_period = true;
68
            day_start = iday;
69
            if (day_stop!=-1)
70
                break;
71
            day_wait_for = mClimate->sun().longestDay();
72
        } else if (inside_period && gsi<0.5) {
73
            // switch from summer to winter
74
            day_stop = iday;
75
            if (day_start!=-1)
76
                break; // finished
77
            day_wait_for = mClimate->sun().longestDay();
78
            inside_period = false;
79
        }
80
    }
81
    day_start -= 10; // three-week-floating average: subtract 10 days
82
    day_stop -= 10;
83
    if (day_start < -1 || day_stop<-1)
84
        throw IException(QString("Phenology::calculation(): was not able to determine the length of the vegetation period for group %1." ).arg(id()));
611 werner 85
    if (logLevelDebug())
86
        qDebug() << "Jolly-phenology. start" << mClimate->dayOfYear(day_start)->toString() << "stop" << mClimate->dayOfYear(day_stop)->toString();
214 werner 87
    iday = 0;
226 werner 88
    mDayStart = day_start;
89
    mDayEnd = day_stop;
214 werner 90
    int bDay, bMon, eDay, eMon;
91
    // convert yeardays to dates
92
    mClimate->toDate(day_start, &bDay, &bMon);
93
    mClimate->toDate(day_stop, &eDay, &eMon);
94
    for (int i=0;i<12;i++) {
95
        if (i<bMon || i>eMon) {
96
            mPhenoFraction[i] = 0; // out of season
97
        } else if (i>bMon && i<eMon) {
98
            mPhenoFraction[i] = 1.; // full inside of season
99
        } else {
100
            // fractions of month
101
            mPhenoFraction[i] = 1.;
102
            if (i==bMon)
103
                mPhenoFraction[i] -=  (bDay+1) / double(mClimate->days(bMon));
104
            if (i==eMon)
105
                mPhenoFraction[i] -=  (mClimate->days(eMon) - (bDay+1)) / double(mClimate->days(eMon));
106
        }
107
    }
434 werner 108
 
109
    calculateChillDays();
214 werner 110
}
434 werner 111
 
112
 
113
// *********** Chill-day calculations ********
436 werner 114
void Phenology::calculateChillDays(const int end_of_season)
434 werner 115
{
116
    int iday = 0;
117
    mChillDaysBefore = 0;
118
    int days_after = 0;
436 werner 119
    int last_day = end_of_season>0?end_of_season:mDayEnd;
434 werner 120
    for (const ClimateDay *day = mClimate->begin(); day!=mClimate->end(); ++day, ++iday) {
121
        if (day->temperature>=-5 && day->temperature<5) {
122
            if (iday<mDayStart)
123
                mChillDaysBefore++;
436 werner 124
            if (iday>last_day)
434 werner 125
                days_after++;
126
        }
127
    }
128
    if (GlobalSettings::instance()->currentYear()==1) {
129
        // for the first simulation year, use the value of this autumn for the last years autumn
130
        mChillDaysAfterLastYear = days_after;
131
    } else {
132
        mChillDaysAfterLastYear  = mChillDaysAfter;
133
    }
134
    mChillDaysAfter = days_after;
135
}