Subversion Repositories public iLand

Rev

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

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