Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
705 | 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 | |||
20 | #ifndef SPECIES_H |
||
21 | #define SPECIES_H |
||
989 | werner | 22 | #ifdef ILAND_GUI |
780 | werner | 23 | #include <QColor> |
989 | werner | 24 | #endif |
705 | werner | 25 | |
26 | #include "expression.h" |
||
27 | #include "globalsettings.h" |
||
28 | #include "speciesset.h" |
||
29 | |||
30 | class StampContainer; // forwards |
||
31 | class Stamp; |
||
1180 | werner | 32 | class Tree; |
705 | werner | 33 | |
34 | |||
35 | /// parameters for establishment |
||
36 | struct EstablishmentParameters |
||
37 | { |
||
38 | double min_temp; //degC |
||
39 | int chill_requirement; // days of chilling requirement |
||
40 | int GDD_min, GDD_max; // GDD thresholds |
||
41 | double GDD_baseTemperature; // for GDD-calc: GDD=sum(T - baseTemp) |
||
42 | int bud_birst; // GDDs needed until bud burst |
||
43 | int frost_free; // minimum number of annual frost-free days required |
||
44 | double frost_tolerance; //factor in growing season frost tolerance calculation |
||
1160 | werner | 45 | double psi_min; // minimum soil water potential for establishment |
705 | werner | 46 | EstablishmentParameters(): min_temp(-37), chill_requirement(56), GDD_min(177), GDD_max(3261), GDD_baseTemperature(3.4), |
1160 | werner | 47 | bud_birst(255), frost_free(65), frost_tolerance(0.5), psi_min(0.) {} |
705 | werner | 48 | }; |
49 | |||
50 | /// parameters for sapling growth |
||
51 | struct SaplingGrowthParameters |
||
52 | { |
||
53 | Expression heightGrowthPotential; ///< formula that expresses height growth potential |
||
54 | int maxStressYears; ///< trees die, if they are "stressed" for this number of consectuive years |
||
55 | double stressThreshold; ///< tree is considered as "stressed" if f_env_yr is below that threhold |
||
56 | float hdSapling; ///< fixed height-diameter ratio used for saplings |
||
57 | double ReinekesR; ///< Reinekes R, i.e. maximum stem number for a dg of 25cm |
||
58 | double referenceRatio; ///< f_ref (eq. 3) -> ratio reference site / optimum site |
||
1165 | werner | 59 | SaplingGrowthParameters(): maxStressYears(3), stressThreshold(0.1), hdSapling(80.f), ReinekesR(1450.), referenceRatio(1.), browsingProbability(0.), sproutGrowth(0.) {} |
1182 | werner | 60 | /// represented stem number by height of one cohort (using Reinekes Law): this uses a lookup table to improve performance |
1177 | werner | 61 | double representedStemNumberH(const double height) const { return mRepresentedClasses[limit(qRound(height*10.),0,mRepresentedClasses.size())]; } |
705 | werner | 62 | /// represented stem number by one cohort (using Reinekes Law): |
63 | double representedStemNumber(const double dbh) const { return ReinekesR*pow(dbh/25., -1.605) / double(cPxPerHectare); } |
||
1063 | werner | 64 | /// browsing probability |
65 | double browsingProbability; |
||
1165 | werner | 66 | double sproutGrowth; ///< multiplier of growth for saplings regenerated by sprouts (0: no sprouts) |
1177 | werner | 67 | QVector<double> mRepresentedClasses; ///< lookup table for represented trees |
68 | void setupReinekeLookup(); |
||
705 | werner | 69 | }; |
70 | |||
71 | |||
72 | class Species |
||
73 | { |
||
74 | public: |
||
707 | werner | 75 | Species(SpeciesSet *set) { mSet = set; mIndex=set->count(); mSeedDispersal=0; } |
705 | werner | 76 | ~Species(); |
77 | // maintenance |
||
78 | void setup(); |
||
79 | void newYear(); |
||
80 | |||
81 | const SpeciesSet *speciesSet() const { return mSet; } |
||
82 | // properties |
||
83 | SeedDispersal *seedDispersal() const { return mSeedDispersal; } |
||
84 | /// @property id 4-character unique identification of the tree species |
||
85 | const QString &id() const { return mId; } |
||
86 | /// the full name (e.g. Picea Abies) of the species |
||
87 | const QString &name() const { return mName; } |
||
989 | werner | 88 | #ifdef ILAND_GUI |
705 | werner | 89 | const QColor displayColor() const { return mDisplayColor; } |
989 | werner | 90 | #endif |
705 | werner | 91 | int index() const { return mIndex; } ///< unique index of species within current set |
92 | bool active() const { return true; } ///< active??? todo! |
||
93 | int phenologyClass() const { return mPhenologyClass; } ///< phenology class defined in project file. class 0 = evergreen |
||
94 | bool isConiferous() const { return mConiferous; } |
||
95 | bool isEvergreen() const { return mEvergreen; } |
||
96 | bool isSeedYear() const { return mIsSeedYear; } |
||
97 | |||
98 | |||
99 | // calculations: allometries |
||
100 | inline double biomassFoliage(const double dbh) const { return mFoliage_a * pow(dbh, mFoliage_b); } |
||
101 | inline double biomassWoody(const double dbh) const { return mWoody_a * pow(dbh, mWoody_b); } |
||
102 | inline double biomassRoot(const double dbh) const { return mRoot_a * pow(dbh, mRoot_b); } |
||
103 | inline double biomassBranch(const double dbh) const { return mBranch_a * pow(dbh, mBranch_b); } |
||
104 | inline double allometricRatio_wf() const { return mWoody_b / mFoliage_b; } |
||
105 | double allometricFractionStem(const double dbh) const; |
||
106 | double finerootFoliageRatio() const { return mFinerootFoliageRatio; } ///< ratio of fineroot mass (kg) to foliage mass (kg) |
||
107 | double barkThickness(const double dbh) const { return dbh * mBarkThicknessFactor; } |
||
108 | // cn ratios |
||
109 | double cnFoliage() const { return mCNFoliage; } |
||
110 | double cnFineroot() const { return mCNFineroot; } |
||
111 | double cnWood() const { return mCNWood; } |
||
112 | // turnover rates |
||
113 | double turnoverLeaf() const { return mTurnoverLeaf; } |
||
114 | double turnoverRoot() const { return mTurnoverRoot; } |
||
115 | // snags |
||
116 | double snagKsw() const { return mSnagKSW; } |
||
117 | double snagHalflife() const { return mSnagHalflife; } |
||
118 | double snagKyl() const { return mSnagKYL; } ///< decomposition rate for labile matter (litter) used in soil model |
||
119 | double snagKyr() const { return mSnagKYR; } ///< decomposition rate for refractory matter (woody) used in soil model |
||
120 | |||
121 | // hd-values |
||
122 | void hdRange(const double dbh, double &rMinHD, double &rMaxHD) const; |
||
123 | // growth |
||
124 | double volumeFactor() const { return mVolumeFactor; } ///< factor for volume calculation: V = factor * D^2*H (incorporates density and the form of the bole) |
||
125 | double density() const { return mWoodDensity; } ///< density of stem wood [kg/m3] |
||
126 | double specificLeafArea() const { return mSpecificLeafArea; } |
||
127 | // mortality |
||
128 | double deathProb_intrinsic() const { return mDeathProb_intrinsic; } |
||
129 | inline double deathProb_stress(const double &stress_index) const; |
||
130 | // aging |
||
131 | double aging(const float height, const int age) const; |
||
132 | int estimateAge(const float height) const;///< estimate age for a tree with the current age |
||
133 | // regeneration |
||
1167 | werner | 134 | /// check the maturity of the tree and flag the position as seed source appropriately |
1180 | werner | 135 | void seedProduction(const Tree *tree); |
705 | werner | 136 | void setSeedDispersal(SeedDispersal *seed_dispersal) {mSeedDispersal=seed_dispersal; } |
137 | // environmental responses |
||
138 | double vpdResponse(const double &vpd) const; |
||
139 | inline double temperatureResponse(const double &delayed_temp) const; |
||
140 | double nitrogenResponse(const double &availableNitrogen) const { return mSet->nitrogenResponse(availableNitrogen, mRespNitrogenClass); } |
||
141 | double canopyConductance() const { return mMaxCanopyConductance; } ///< maximum canopy conductance in m/s |
||
142 | inline double soilwaterResponse(const double &psi_kPa) const; ///< input: matrix potential (kPa) (e.g. -15) |
||
143 | double lightResponse(const double lightResourceIndex) const {return mSet->lightResponse(lightResourceIndex, mLightResponseClass); } |
||
144 | double psiMin() const { return mPsiMin; } |
||
145 | // parameters for seed dispersal |
||
146 | void treeMigKernel(double &ras1, double &ras2, double &ks) const { ras1=mTM_as1; ras2=mTM_as2; ks=mTM_ks; } |
||
147 | double fecundity_m2() const { return mFecundity_m2; } |
||
148 | double nonSeedYearFraction() const { return mNonSeedYearFraction; } |
||
1167 | werner | 149 | double fecunditySerotiny() const { return mSerotinyFecundity; } |
150 | /// returns true of a tree with given age/height is serotinous (i.e. seed release after fire) |
||
151 | bool isTreeSerotinous(const int age) const; |
||
152 | |||
705 | werner | 153 | const EstablishmentParameters &establishmentParameters() const { return mEstablishmentParams; } |
154 | const SaplingGrowthParameters &saplingGrowthParameters() const { return mSaplingGrowthParams; } |
||
155 | |||
156 | const Stamp* stamp(const float dbh, const float height) const { return mLIPs.stamp(dbh, height);} |
||
157 | private: |
||
837 | werner | 158 | Q_DISABLE_COPY(Species) |
705 | werner | 159 | // helpers during setup |
160 | bool boolVar(const QString s) { return mSet->var(s).toBool(); } ///< during setup: get value of variable @p s as a boolean variable. |
||
161 | double doubleVar(const QString s) { return mSet->var(s).toDouble(); }///< during setup: get value of variable @p s as a double. |
||
162 | int intVar(const QString s) { return mSet->var(s).toInt(); } ///< during setup: get value of variable @p s as an integer. |
||
163 | QString stringVar(const QString s) { return mSet->var(s).toString(); } ///< during setup: get value of variable @p s as a string. |
||
164 | SpeciesSet *mSet; ///< ptr. to the "parent" set |
||
165 | StampContainer mLIPs; ///< ptr to the container of the LIP-pattern |
||
166 | QString mId; |
||
167 | QString mName; |
||
1172 | werner | 168 | |
705 | werner | 169 | int mIndex; ///< internal index within the SpeciesSet |
170 | bool mConiferous; ///< true if confierous species (vs. broadleaved) |
||
171 | bool mEvergreen; ///< true if evergreen species |
||
172 | // biomass allometries: |
||
173 | double mFoliage_a, mFoliage_b; ///< allometry (biomass = a * dbh^b) for foliage |
||
174 | double mWoody_a, mWoody_b; ///< allometry (biomass = a * dbh^b) for woody compartments aboveground |
||
175 | double mRoot_a, mRoot_b; ///< allometry (biomass = a * dbh^b) for roots (compound, fine and coarse roots as one pool) |
||
176 | double mBranch_a, mBranch_b; ///< allometry (biomass = a * dbh^b) for branches |
||
177 | // cn-ratios |
||
178 | double mCNFoliage, mCNFineroot, mCNWood; ///< CN-ratios for various tissue types; stem, branches and coarse roots are pooled as 'wood' |
||
179 | double mBarkThicknessFactor; ///< multiplier to estimate bark thickness (cm) from dbh |
||
180 | |||
181 | double mSpecificLeafArea; ///< conversion factor from kg OTS to m2 LeafArea |
||
182 | // turnover rates |
||
183 | double mTurnoverLeaf; ///< yearly turnover rate leafs |
||
184 | double mTurnoverRoot; ///< yearly turnover rate root |
||
185 | double mFinerootFoliageRatio; ///< ratio of fineroot mass (kg) to foliage mass (kg) |
||
186 | // height-diameter-relationships |
||
187 | Expression mHDlow; ///< minimum HD-relation as f(d) (open grown tree) |
||
188 | Expression mHDhigh; ///< maximum HD-relation as f(d) |
||
189 | // stem density and taper |
||
190 | double mWoodDensity; ///< density of the wood [kg/m3] |
||
191 | double mFormFactor; ///< taper form factor of the stem [-] used for volume / stem-mass calculation calculation |
||
192 | double mVolumeFactor; ///< factor for volume calculation |
||
193 | // snag dynamics |
||
194 | double mSnagKSW; ///< standing woody debris (swd) decomposition rate |
||
195 | double mSnagKYL; ///< decomposition rate for labile matter (litter) used in soil model |
||
196 | double mSnagKYR; ///< decomposition rate for refractory matter (woody) used in soil model |
||
197 | double mSnagHalflife; ///< half-life-period of standing snags (years) |
||
198 | // mortality |
||
199 | double mDeathProb_intrinsic; ///< prob. of intrinsic death per year [0..1] |
||
200 | double mDeathProb_stress; ///< max. prob. of death per year when tree suffering maximum stress |
||
201 | // Aging |
||
202 | double mMaximumAge; ///< maximum age of species (years) |
||
203 | double mMaximumHeight; ///< maximum height of species (m) for aging |
||
204 | Expression mAging; |
||
205 | // environmental responses |
||
206 | double mRespVpdExponent; ///< exponent in vpd response calculation (Mkela 2008) |
||
207 | double mRespTempMin; ///< temperature response calculation offset |
||
208 | double mRespTempMax; ///< temperature response calculation: saturation point for temp. response |
||
209 | double mRespNitrogenClass; ///< nitrogen response class (1..3). fractional values (e.g. 1.2) are interpolated. |
||
210 | double mPsiMin; ///< minimum water potential (MPa), i.e. wilting point (is below zero!) |
||
211 | // water |
||
212 | double mMaxCanopyConductance; ///< maximum canopy conductance for transpiration (m/s) |
||
213 | int mPhenologyClass; |
||
214 | double mLightResponseClass; ///< light response class (1..5) (1=shade intolerant) |
||
215 | // regeneration |
||
216 | SeedDispersal *mSeedDispersal; ///< link to the seed dispersal map of the species |
||
217 | int mMaturityYears; ///< a tree produces seeds if it is older than this parameter |
||
218 | double mSeedYearProbability; ///< probability that a year is a seed year (=1/avg.timespan between seedyears) |
||
219 | bool mIsSeedYear; ///< true, if current year is a seed year. see also: |
||
220 | double mNonSeedYearFraction; ///< fraction of the seed production in non-seed-years |
||
221 | // regeneration - seed dispersal |
||
222 | double mFecundity_m2; ///< "surviving seeds" (cf. Moles et al) per m2, see also http://iland.boku.ac.at/fecundity |
||
223 | double mTM_as1; ///< seed dispersal paramaters (treemig) |
||
224 | double mTM_as2; ///< seed dispersal paramaters (treemig) |
||
225 | double mTM_ks; ///< seed dispersal paramaters (treemig) |
||
226 | EstablishmentParameters mEstablishmentParams; ///< collection of parameters used for establishment |
||
227 | SaplingGrowthParameters mSaplingGrowthParams; ///< collection of parameters for sapling growth |
||
1167 | werner | 228 | Expression mSerotiny; ///< function that decides (probabilistic) if a tree is serotinous; empty: serotiny not active |
229 | double mSerotinyFecundity; ///< multiplier that increases fecundity for post-fire seed rain of serotinous species |
||
705 | werner | 230 | |
1172 | werner | 231 | #ifdef ILAND_GUI |
232 | QColor mDisplayColor; |
||
233 | #else |
||
234 | int mDisplayColor; |
||
235 | #endif |
||
705 | werner | 236 | }; |
237 | |||
238 | |||
239 | // inlined functions... |
||
240 | inline void Species::hdRange(const double dbh, double &rLowHD, double &rHighHD) const |
||
241 | { |
||
242 | rLowHD = mHDlow.calculate(dbh); |
||
243 | rHighHD = mHDhigh.calculate(dbh); |
||
244 | } |
||
245 | /** vpdResponse calculates response on vpd. |
||
246 | Input: vpd [kPa]*/ |
||
247 | inline double Species::vpdResponse(const double &vpd) const |
||
248 | { |
||
249 | return exp(mRespVpdExponent * vpd); |
||
250 | } |
||
251 | |||
252 | /** temperatureResponse calculates response on delayed daily temperature. |
||
253 | Input: average temperature [C] |
||
254 | Note: slightly different from Mkela 2008: the maximum parameter (Sk) in iLand is interpreted as the absolute |
||
255 | temperature yielding a response of 1; in Mkela 2008, Sk is the width of the range (relative to the lower threhold) |
||
256 | */ |
||
257 | inline double Species::temperatureResponse(const double &delayed_temp) const |
||
258 | { |
||
259 | double x = qMax(delayed_temp-mRespTempMin, 0.); |
||
260 | x = qMin(x/(mRespTempMax-mRespTempMin), 1.); |
||
261 | return x; |
||
262 | } |
||
263 | /** soilwaterResponse is a function of the current matrix potential of the soil. |
||
264 | |||
265 | */ |
||
266 | inline double Species::soilwaterResponse(const double &psi_kPa) const |
||
267 | { |
||
268 | const double psi_mpa = psi_kPa / 1000.; // convert to MPa |
||
269 | double result = limit( (psi_mpa - mPsiMin) / (-0.015 - mPsiMin) , 0., 1.); |
||
270 | return result; |
||
271 | } |
||
272 | |||
273 | /** calculate probabilty of death based on the current stress index. */ |
||
274 | inline double Species::deathProb_stress(const double &stress_index) const |
||
275 | { |
||
1160 | werner | 276 | if (stress_index==0.) |
705 | werner | 277 | return 0.; |
278 | double result = 1. - exp(-mDeathProb_stress*stress_index); |
||
279 | return result; |
||
280 | } |
||
281 | |||
282 | #endif // SPECIES_H |