Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1033 werner 1
/********************************************************************************************
2
**    iLand - an individual based forest landscape and disturbance model
3
**    http://iland.boku.ac.at
4
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**
6
**    This program is free software: you can redistribute it and/or modify
7
**    it under the terms of the GNU General Public License as published by
8
**    the Free Software Foundation, either version 3 of the License, or
9
**    (at your option) any later version.
10
**
11
**    This program is distributed in the hope that it will be useful,
12
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    GNU General Public License for more details.
15
**
16
**    You should have received a copy of the GNU General Public License
17
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
********************************************************************************************/
19
 
964 werner 20
#include "bbgenerations.h"
21
 
1007 werner 22
#include "resourceunit.h"
23
#include "climate.h"
1095 werner 24
/** @class BBGenerations
25
    @ingroup beetlemodule
26
    BBGenerations calculates potential bark beetle generations based on climate data (including bark temperature).
27
  */
964 werner 28
BBGenerations::BBGenerations()
29
{
30
}
1007 werner 31
 
1008 werner 32
/**
33
 * @brief BBGenerations::calculateGenerations
34
 * @param ru
1085 werner 35
 * @return the number of filial generation (i.e, main generations) + 0.5 if a sister brood develops also for the last generation
1008 werner 36
 */
37
double BBGenerations::calculateGenerations(const ResourceUnit *ru)
38
{
39
    calculateBarkTemperature(ru);
1007 werner 40
 
1008 werner 41
    // start at the 1. of April, and wait for 140.3 degree days (with a threhsold of 8.3 degrees)
42
    const ClimateDay *clim = ru->climate()->day(4-1,1-1); // 0-based indices
43
    const ClimateDay *last_day = ru->climate()->day(10-1,31-1); // 0-based indices -> Oct 31
44
    const ClimateDay * day_too_short = ru->climate()->dayOfYear(ru->climate()->sun().dayShorter14_5hrs()); // the first doy where the day is shorter than 14.5 hours
45
 
46
    double dd=0.;
47
    while (dd<140.3 && clim<last_day) {
48
        dd+=std::max(clim->max_temperature-8.3, 0.);
49
        ++clim;
50
    }
51
    // now wait for a decent warm day with tmax > 16.5 degrees
52
    while (clim->max_temperature<=16.5 && clim<last_day)
53
        ++clim;
54
 
55
    mGenerations.clear();
56
    // start with the first generation....
57
    BBGeneration bbgen;
58
    bbgen.start_day = ru->climate()->whichDayOfYear(clim);
1010 werner 59
    bbgen.is_sister_brood = false;
1008 werner 60
    bbgen.gen = 1; // the first generation
61
    mGenerations.append(bbgen);
62
 
63
    // process the generations
64
    int i=0;
65
    while (i<mGenerations.count()) {
66
        BBGeneration bb = mGenerations[i]; // deliberately make a copy and not a ref
67
        const ClimateDay *c = ru->climate()->dayOfYear(bb.start_day);
68
        int doy = bb.start_day;
69
        double base_temp = mEffectiveBarkTemp[doy];
70
 
1032 werner 71
        double t_sum=0.;
1010 werner 72
        bool added_sister_brood = false;
1008 werner 73
        while (c < last_day) {
74
            t_sum = (mEffectiveBarkTemp[doy]-base_temp) / 557.;
75
            if (t_sum>=1.) {
76
                if (c<day_too_short) {
1082 werner 77
                    // start a new parental generation (a full cycle), only if the current
78
                    // generation is also a filial generation.
79
                    if (bb.is_sister_brood)
80
                        mGenerations.append(BBGeneration(doy, true, bb.gen)); // sisterbrood: (true), keep counter of filial generation
81
                    else
82
                        mGenerations.append(BBGeneration(doy, false, bb.gen+1)); // new filial brood (false), start a new gen
83
 
1008 werner 84
                }
85
                break;
1010 werner 86
            } else if (t_sum>0.5 && !added_sister_brood) {
87
                // start a sister brood, *if* the maximum air temperature is high enough, and if the
1008 werner 88
                // length of the day > 14.5 hours
89
                if (c->max_temperature>16.5 && c<day_too_short) {
1082 werner 90
                    mGenerations.append(BBGeneration(doy, true, bb.gen)); // add a sister brood generation (true), keep gen. of originating brood
1010 werner 91
                    added_sister_brood = true;
1008 werner 92
                }
93
            }
94
            ++c; ++doy;
95
        }
96
        mGenerations[i].value = std::min(t_sum, 1.);
97
        ++i; // now process the next generation
98
    }
99
 
1082 werner 100
 
101
    mNSisterBroods = 0; mNFilialBroods = 0;
102
 
1008 werner 103
    for (i=0;i<mGenerations.count();++i) {
1082 werner 104
        if (mGenerations[i].value>0.6 && mGenerations[i].is_sister_brood==true)
105
            mNSisterBroods = std::max( mGenerations[i].gen, mNSisterBroods );
1008 werner 106
 
1082 werner 107
        if (mGenerations[i].value>0.6 && mGenerations[i].is_sister_brood==false)
108
            mNFilialBroods = mGenerations[i].gen;
1008 werner 109
    }
1010 werner 110
 
1082 werner 111
    // return the number of filial broods, and increase by 0.5 if a sister brood of the last filial generation has successfully developed.
112
    return mNFilialBroods + ( hasSisterBrood() ? 0.5 : 0.);
113
 
114
//    // now accumulate the generations
115
//    double filial_generations = 0.;
116
//    double sister_generations = 0.;
117
//    // accumulate possible number of offspring
118
//    const double offspring_factor = 25.; // assuming sex-ratio of 1:1 and 50 offspring per female (see p. 59)
119
//    int n=0;
120
//    int total_offspring = 0;
121
//    for (i=0;i<mGenerations.count();++i) {
122
//        if (mGenerations[i].value>0.6)  {
123
//            ++n;
124
//            total_offspring+= pow(offspring_factor, mGenerations[i].gen-1)*2.*offspring_factor;
125
//        }
126
//        if (mGenerations[i].value>0.6 && mGenerations[i].is_sister_brood==true)
127
//            sister_generations+=mGenerations[i].value;
128
//        if (mGenerations[i].value>0.6 && mGenerations[i].is_sister_brood==false)
129
//            filial_generations+=mGenerations[i].value;
130
 
131
//    }
132
//    if (logLevelDebug())
133
//        qDebug() << "rid" <<ru->id() << "filial/sister:" << filial_generations << sister_generations << "offspring:" << total_offspring << "started generations:" << n;
134
//    mNSisterBroods = sister_generations;
135
//    mNFilialBroods = filial_generations;
136
 
137
//    return filial_generations + (sister_generations>0?0.5:0);
1008 werner 138
}
139
 
140
 
1007 werner 141
/**
142
 * Calculate the bark temperatures for this year and a given resource unit.
1024 werner 143
 * Input: climate data (tmax (C), tmean (C), radiation (MJ/m2))
1007 werner 144
 * the LAI to estimate the radiation on the ground (Wh/m2)
1008 werner 145
 * Output: calculates for each day of the year the "effective" bark-temperature and saves a cumulative sum
1007 werner 146
 * Source: Schopf et al 2004: Risikoabschaetzung von Borkenkaefermassenkalamitaeten im Nationalpark Kalkalpen
147
 */
148
void BBGenerations::calculateBarkTemperature(const ResourceUnit *ru)
149
{
150
    // estimate the fraction of light on the ground (multiplier from 0..1)
151
    const double k = 0.5; // constant for the beer lambert function
152
    double ground_light_fraction = exp(-k * ru->leafAreaIndex() );
153
 
1010 werner 154
    mFrostDaysEarly=0;
155
    mFrostDaysLate=0;
1007 werner 156
 
157
    for (int i=0;i<ru->climate()->daysOfYear();++i) {
158
        const ClimateDay *clim = ru->climate()->dayOfYear(i);
159
        // radiation: MJ/m2/day -> the regression uses Wh/m2/day -> conversion-factor: 1/0.0036
1008 werner 160
        double rad_wh = clim->radiation*ground_light_fraction/0.0036;
161
        // calc. maximum bark temperature
162
        double bt_max=1.656 + 0.002955*rad_wh + 0.534*clim->max_temperature + 0.01884 * clim->max_temperature*clim->max_temperature;
163
        double diff_bt=0.;
1007 werner 164
 
1008 werner 165
 
166
        if (bt_max>=30.4)
167
            diff_bt=std::max(-310.667 + 9.603 * bt_max, 0.); // degree * hours
168
 
169
        // mean bark temperature
170
        double bt_mean=-0.173+0.0008518*rad_wh+1.054*clim->mean_temp();
171
 
172
        // effective:
173
        double bt_sum = std::max(bt_mean - 8.3, 0.)*24.; // degree * hours
174
 
175
        // corrected for days with very high bark temperature (>30.4 degrees)
176
        double bt_sum_eff = (bt_sum - diff_bt) / 24.; // degree * days
177
 
178
        mEffectiveBarkTemp[i] = (i>0? mEffectiveBarkTemp[i-1] : 0.) + bt_sum_eff;
179
 
1010 werner 180
        // frost days:
181
        if (clim->min_temperature < -15.) {
182
            if (i < ru->climate()->sun().longestDay())
183
                mFrostDaysEarly++;
184
            else
185
                mFrostDaysLate++;
186
        }
187
 
1007 werner 188
    }
189
 
190
}