Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
671 | 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 | |||
434 | werner | 20 | #include "establishment.h" |
21 | |||
22 | #include "climate.h" |
||
23 | #include "species.h" |
||
438 | werner | 24 | #include "resourceunit.h" |
434 | werner | 25 | #include "resourceunitspecies.h" |
438 | werner | 26 | #include "seeddispersal.h" |
439 | werner | 27 | #include "model.h" |
1062 | werner | 28 | #include "grasscover.h" |
626 | werner | 29 | #include "helper.h" |
1001 | werner | 30 | #include "debugtimer.h" |
1160 | werner | 31 | #include "watercycle.h" |
434 | werner | 32 | |
33 | /** @class Establishment |
||
34 | Establishment deals with the establishment process of saplings. |
||
35 | http://iland.boku.ac.at/establishment |
||
36 | Prerequisites for establishment are: |
||
37 | the availability of seeds: derived from the seed-maps per Species (@sa SeedDispersal) |
||
38 | the quality of the abiotic environment (TACA-model): calculations are performend here, based on climate and species responses |
||
39 | the quality of the biotic environment, mainly light: based on the LIF-values |
||
40 | |||
41 | */ |
||
440 | werner | 42 | Establishment::Establishment() |
43 | { |
||
44 | mPAbiotic = 0.; |
||
45 | } |
||
46 | |||
434 | werner | 47 | Establishment::Establishment(const Climate *climate, const ResourceUnitSpecies *rus) |
48 | { |
||
440 | werner | 49 | setup(climate, rus); |
50 | } |
||
51 | |||
52 | void Establishment::setup(const Climate *climate, const ResourceUnitSpecies *rus) |
||
53 | { |
||
434 | werner | 54 | mClimate = climate; |
55 | mRUS = rus; |
||
56 | mPAbiotic = 0.; |
||
440 | werner | 57 | mPxDensity = 0.; |
58 | mNumberEstablished = 0; |
||
1210 | werner | 59 | if (climate==0) |
60 | throw IException("Establishment::setup: no valid climate for a resource unit."); |
||
61 | if (rus==0 || rus->species()==0 || rus->ru()==0) |
||
62 | throw IException("Establishment::setup: important variable is null (are the species properly set up?)."); |
||
434 | werner | 63 | } |
64 | |||
439 | werner | 65 | |
451 | werner | 66 | |
1168 | werner | 67 | void Establishment::clear() |
68 | { |
||
69 | mPAbiotic = 0.; |
||
70 | mNumberEstablished = 0; |
||
71 | mPxDensity = 0.; |
||
72 | mTACA_min_temp=mTACA_chill=mTACA_gdd=mTACA_frostfree=false; |
||
73 | mTACA_frostAfterBuds=0; |
||
74 | mSumLIFvalue = 0.; |
||
75 | mLIFcount = 0; |
||
76 | mWaterLimitation = 0.; |
||
77 | |||
78 | } |
||
79 | |||
434 | werner | 80 | |
1160 | werner | 81 | double Establishment::calculateWaterLimitation(const int veg_period_start, const int veg_period_end) |
82 | { |
||
83 | // return 1 if effect is disabled |
||
84 | if (mRUS->species()->establishmentParameters().psi_min >= 0.) |
||
85 | return 1.; |
||
439 | werner | 86 | |
1160 | werner | 87 | double psi_min = mRUS->species()->establishmentParameters().psi_min; |
88 | const WaterCycle *water = mRUS->ru()->waterCycle(); |
||
89 | int days = mRUS->ru()->climate()->daysOfYear(); |
||
1068 | werner | 90 | |
1160 | werner | 91 | // two week (14 days) running average of actual psi-values on the resource unit |
92 | static const int nwindow = 14; |
||
93 | double psi_buffer[nwindow]; |
||
94 | for (int i=0;i<nwindow;++i) |
||
95 | psi_buffer[i] = 0.; |
||
96 | double current_sum = 0.; |
||
97 | |||
98 | int i_buffer = 0; |
||
99 | double min_average = 9999999.; |
||
100 | double current_avg = 0.; |
||
101 | for (int day=0;day<days;++day) { |
||
1161 | werner | 102 | // running average: remove oldest item, add new item in a ringbuffer |
1160 | werner | 103 | current_sum -= psi_buffer[i_buffer]; |
104 | psi_buffer[i_buffer] = water->psi_kPa(day); |
||
105 | current_sum += psi_buffer[i_buffer]; |
||
106 | |||
107 | if (day>=veg_period_start && day<=veg_period_end) { |
||
108 | current_avg = day>0? current_sum / std::min(day, nwindow) : current_sum; |
||
109 | min_average = std::min(min_average, current_avg); |
||
110 | } |
||
111 | |||
112 | // move to next value in the buffer |
||
113 | i_buffer = ++i_buffer % nwindow; |
||
114 | } |
||
115 | |||
116 | if (min_average > 1000.) |
||
117 | return 1.; // invalid vegetation period? |
||
118 | |||
119 | // calculate the response of the species to this value of psi (see also Species::soilwaterResponse()) |
||
120 | const double psi_mpa = min_average / 1000.; // convert to MPa |
||
121 | double result = limit( (psi_mpa - psi_min) / (-0.015 - psi_min) , 0., 1.); |
||
122 | |||
123 | return result; |
||
124 | |||
125 | } |
||
126 | |||
127 | |||
128 | |||
434 | werner | 129 | /** Calculate the abiotic environemnt for seedling for a given species and a given resource unit. |
130 | The model is closely based on the TACA approach of Nitschke and Innes (2008), Ecol. Model 210, 263-277 |
||
131 | more details: http://iland.boku.ac.at/establishment#abiotic_environment |
||
132 | a model mockup in R: script_establishment.r |
||
133 | |||
134 | */ |
||
135 | void Establishment::calculateAbioticEnvironment() |
||
136 | { |
||
1001 | werner | 137 | //DebugTimer t("est_abiotic"); t.setSilent(); |
1161 | werner | 138 | // make sure that required calculations (e.g. watercycle are already performed) |
139 | const_cast<ResourceUnitSpecies*>(mRUS)->calculate(true); // calculate the 3pg module and run the water cycle (this is done only if that did not happen up to now); true: call comes from regeneration |
||
1001 | werner | 140 | |
446 | werner | 141 | const EstablishmentParameters &p = mRUS->species()->establishmentParameters(); |
434 | werner | 142 | const Phenology &pheno = mClimate->phenology(mRUS->species()->phenologyClass()); |
143 | |||
442 | werner | 144 | mTACA_min_temp = true; // minimum temperature threshold |
145 | mTACA_chill = false; // (total) chilling requirement |
||
146 | mTACA_gdd = false; // gdd-thresholds |
||
147 | mTACA_frostfree = false; // frost free days in vegetation period |
||
148 | mTACA_frostAfterBuds = 0; // frost days after bud birst |
||
434 | werner | 149 | |
150 | |||
151 | const ClimateDay *day = mClimate->begin(); |
||
152 | int doy = 0; |
||
153 | double GDD=0.; |
||
154 | double GDD_BudBirst = 0.; |
||
155 | int chill_days = pheno.chillingDaysLastYear(); // chilling days of the last autumn |
||
156 | int frost_free = 0; |
||
442 | werner | 157 | mTACA_frostAfterBuds = 0; |
434 | werner | 158 | bool chill_ok = false; |
159 | bool buds_are_birst = false; |
||
440 | werner | 160 | int veg_period_end = pheno.vegetationPeriodEnd(); |
161 | if (veg_period_end >= 365) |
||
162 | veg_period_end = mClimate->sun().dayShorter10_5hrs(); |
||
163 | |||
434 | werner | 164 | for (; day!=mClimate->end(); ++day, ++doy) { |
165 | // minimum temperature: if temp too low -> set prob. to zero |
||
166 | if (day->min_temperature < p.min_temp) |
||
442 | werner | 167 | mTACA_min_temp = false; |
434 | werner | 168 | |
435 | werner | 169 | // count frost free days |
170 | if (day->min_temperature > 0.) |
||
171 | frost_free++; |
||
172 | |||
434 | werner | 173 | // chilling requirement, GDD, bud birst |
174 | if (day->temperature>=-5. && day->temperature<5.) |
||
175 | chill_days++; |
||
176 | if (chill_days>p.chill_requirement) |
||
177 | chill_ok=true; |
||
178 | // GDDs above the base temperature are counted if beginning from the day where the chilling requirements are met |
||
179 | // up to a fixed day ending the veg period |
||
440 | werner | 180 | if (doy<=veg_period_end) { |
434 | werner | 181 | // accumulate growing degree days |
182 | if (chill_ok && day->temperature > p.GDD_baseTemperature) { |
||
183 | GDD += day->temperature - p.GDD_baseTemperature; |
||
184 | GDD_BudBirst += day->temperature - p.GDD_baseTemperature; |
||
185 | } |
||
186 | // if day-frost occurs, the GDD counter for bud birst is reset |
||
187 | if (day->temperature <= 0.) |
||
188 | GDD_BudBirst = 0.; |
||
189 | |||
190 | if (GDD_BudBirst > p.bud_birst) |
||
191 | buds_are_birst = true; |
||
192 | |||
440 | werner | 193 | if (doy<veg_period_end && buds_are_birst && day->min_temperature <= 0.) |
442 | werner | 194 | mTACA_frostAfterBuds++; |
434 | werner | 195 | } |
196 | } |
||
197 | // chilling requirement |
||
436 | werner | 198 | if (chill_ok) |
442 | werner | 199 | mTACA_chill = true; |
434 | werner | 200 | |
201 | // GDD requirements |
||
202 | if (GDD>p.GDD_min && GDD<p.GDD_max) |
||
442 | werner | 203 | mTACA_gdd = true; |
434 | werner | 204 | |
205 | // frost free days in the vegetation period |
||
206 | if (frost_free > p.frost_free) |
||
442 | werner | 207 | mTACA_frostfree = true; |
434 | werner | 208 | |
209 | // if all requirements are met: |
||
681 | werner | 210 | if (mTACA_chill && mTACA_min_temp && mTACA_gdd && mTACA_frostfree) { |
434 | werner | 211 | // negative effect of frost events after bud birst |
440 | werner | 212 | double frost_effect = 1.; |
442 | werner | 213 | if (mTACA_frostAfterBuds>0) |
214 | frost_effect = pow(p.frost_tolerance, sqrt(double(mTACA_frostAfterBuds))); |
||
1160 | werner | 215 | // negative effect due to water limitation on establishment [1: no effect] |
1168 | werner | 216 | mWaterLimitation = calculateWaterLimitation(pheno.vegetationPeriodStart(), pheno.vegetationPeriodLength()); |
1160 | werner | 217 | // combine drought and frost effect multiplicatively |
1168 | werner | 218 | mPAbiotic = frost_effect * mWaterLimitation; |
434 | werner | 219 | } else { |
220 | mPAbiotic = 0.; // if any of the requirements is not met |
||
221 | } |
||
222 | |||
223 | } |
||
1002 | werner | 224 | |
1168 | werner | 225 | void Establishment::writeDebugOutputs() |
226 | { |
||
227 | if (GlobalSettings::instance()->isDebugEnabled(GlobalSettings::dEstablishment)) { |
||
228 | DebugList &out = GlobalSettings::instance()->debugList(mRUS->ru()->index(), GlobalSettings::dEstablishment); |
||
229 | // establishment details |
||
230 | out << mRUS->species()->id() << mRUS->ru()->index() << mRUS->ru()->id(); |
||
231 | out << avgSeedDensity(); |
||
232 | out << TACAminTemp() << TACAchill() << TACAfrostFree() << TACgdd(); |
||
233 | out << TACAfrostDaysAfterBudBirst() << waterLimitation() << abioticEnvironment(); |
||
1174 | werner | 234 | out << mRUS->prod3PG().fEnvYear() << mRUS->constSaplingStat().newSaplings(); |
235 | |||
1168 | werner | 236 | //out << mSaplingStat.livingSaplings() << mSaplingStat.averageHeight() << mSaplingStat.averageAge() << mSaplingStat.averageDeltaHPot() << mSaplingStat.averageDeltaHRealized(); |
237 | //out << mSaplingStat.newSaplings() << mSaplingStat.diedSaplings() << mSaplingStat.recruitedSaplings() << mSpecies->saplingGrowthParameters().referenceRatio; |
||
238 | } |
||
239 | //); // DBGMODE() |
||
240 | |||
241 | |||
242 | if ( logLevelDebug() ) |
||
243 | qDebug() << "establishment of RU" << mRUS->ru()->index() << "species" << mRUS->species()->id() |
||
244 | << "seeds density:" << avgSeedDensity() |
||
245 | << "abiotic environment:" << abioticEnvironment() |
||
246 | << "f_env,yr:" << mRUS->prod3PG().fEnvYear() |
||
247 | << "N(established):" << numberEstablished(); |
||
248 | |||
249 | } |
||
250 |