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