Rev 493 | Rev 511 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | |||
90 | Werner | 2 | #ifndef SPECIES_H |
3 | #define SPECIES_H |
||
38 | Werner | 4 | |
103 | Werner | 5 | |
91 | Werner | 6 | #include "expression.h" |
7 | |||
103 | Werner | 8 | #include "speciesset.h" |
102 | Werner | 9 | |
91 | Werner | 10 | class StampContainer; // forwards |
38 | Werner | 11 | class Stamp; |
91 | Werner | 12 | |
103 | Werner | 13 | |
446 | werner | 14 | /// parameters for establishment |
15 | struct EstablishmentParameters |
||
16 | { |
||
17 | double min_temp; //degC |
||
18 | int chill_requirement; // days of chilling requirement |
||
19 | int GDD_min, GDD_max; // GDD thresholds |
||
20 | double GDD_baseTemperature; // for GDD-calc: GDD=sum(T - baseTemp) |
||
21 | int bud_birst; // GDDs needed until bud burst |
||
22 | int frost_free; // minimum number of annual frost-free days required |
||
23 | double frost_tolerance; //factor in growing season frost tolerance calculation |
||
24 | EstablishmentParameters(): min_temp(-37), chill_requirement(56), GDD_min(177), GDD_max(3261), GDD_baseTemperature(3.4), |
||
25 | bud_birst(255), frost_free(65), frost_tolerance(0.5) {} |
||
26 | }; |
||
27 | |||
450 | werner | 28 | /// parameters for sapling growth |
29 | struct SaplingGrowthParameters |
||
30 | { |
||
31 | Expression heightGrowthPotential; ///< formula that expresses height growth potential |
||
32 | int maxStressYears; ///< trees die, if they are "stressed" for this number of consectuive years |
||
33 | double stressThreshold; ///< tree is considered as "stressed" if f_env_yr is below that threhold |
||
453 | werner | 34 | float hdSapling; ///< fixed height-diameter ratio used for saplings |
483 | werner | 35 | double ReinekesR; ///< Reinekes R, i.e. maximum stem number for a dg of 25cm |
467 | werner | 36 | double referenceRatio; ///< f_ref (eq. 3) -> ratio reference site / optimum site |
483 | werner | 37 | SaplingGrowthParameters(): maxStressYears(3), stressThreshold(0.1), hdSapling(80.f), ReinekesR(1450.), referenceRatio(1.) {} |
508 | werner | 38 | /// stem number that is represented by one cohort (N) (using Reinekes Law): Important: this is not scaled to N/ha! |
39 | double representedStemNumber(const double dbh) const { return ReinekesR*pow(dbh/25., -1.605); } |
||
450 | werner | 40 | }; |
446 | werner | 41 | |
450 | werner | 42 | |
90 | Werner | 43 | class Species |
38 | Werner | 44 | { |
45 | public: |
||
475 | werner | 46 | Species(SpeciesSet *set) { mSet = set; mIndex=set->count(); mSeedDispersal=0; mRandomGenerator=0; } |
391 | werner | 47 | ~Species(); |
48 | // maintenance |
||
49 | void setup(); |
||
415 | werner | 50 | void newYear(); |
475 | werner | 51 | // getter for a thread-local random number generator object. if setRandomGenerator() is used, this saves some overhead |
52 | MTRand &randomGenerator() const { if (mRandomGenerator) return *mRandomGenerator; else return GlobalSettings::instance()->randomGenerator(); } |
||
53 | void setRandomGenerator() { mRandomGenerator = &GlobalSettings::instance()->randomGenerator(); } // fetch random generator of the current thread |
||
391 | werner | 54 | |
475 | werner | 55 | |
226 | werner | 56 | const SpeciesSet *speciesSet() const { return mSet; } |
91 | Werner | 57 | // properties |
391 | werner | 58 | SeedDispersal *seedDispersal() const { return mSeedDispersal; } |
91 | Werner | 59 | /// @property id 4-character unique identification of the tree species |
111 | Werner | 60 | const QString &id() const { return mId; } |
91 | Werner | 61 | /// the full name (e.g. Picea Abies) of the species |
111 | Werner | 62 | const QString &name() const { return mName; } |
493 | werner | 63 | const QColor displayColor() const { return mDisplayColor; } |
145 | Werner | 64 | int index() const { return mIndex; } ///< unique index of species within current set |
179 | werner | 65 | bool active() const { return true; } ///< active??? todo! |
236 | werner | 66 | int phenologyClass() const { return mPhenologyClass; } ///< phenology class defined in project file. class 0 = evergreen |
67 | bool isConiferous() const { return mConiferous; } |
||
68 | bool isEvergreen() const { return mEvergreen; } |
||
415 | werner | 69 | bool isSeedYear() const { return mIsSeedYear; } |
136 | Werner | 70 | |
391 | werner | 71 | |
91 | Werner | 72 | // calculations: allometries |
145 | Werner | 73 | double biomassFoliage(const double dbh) const; |
74 | double biomassWoody(const double dbh) const; |
||
75 | double biomassRoot(const double dbh) const; |
||
449 | werner | 76 | double biomassBranch(const double dbh) const; |
145 | Werner | 77 | double allometricRatio_wf() const { return mWoody_b / mFoliage_b; } |
78 | double allometricFractionStem(const double dbh) const; |
||
276 | werner | 79 | double finerootFoliageRatio() const { return mFinerootFoliageRatio; } ///< ratio of fineroot mass (kg) to foliage mass (kg) |
136 | Werner | 80 | |
116 | Werner | 81 | // turnover rates |
145 | Werner | 82 | double turnoverLeaf() const { return mTurnoverLeaf; } |
83 | double turnoverRoot() const { return mTurnoverRoot; } |
||
119 | Werner | 84 | // hd-values |
425 | werner | 85 | void hdRange(const double dbh, double &rMinHD, double &rMaxHD) const; |
125 | Werner | 86 | // growth |
145 | Werner | 87 | double volumeFactor() const { return mVolumeFactor; } ///< factor for volume calculation: V = factor * D^2*H (incorporates density and the form of the bole) |
88 | double density() const { return mWoodDensity; } ///< density of stem wood [kg/m3] |
||
89 | double specificLeafArea() const { return mSpecificLeafArea; } |
||
159 | werner | 90 | // mortality |
91 | double deathProb_intrinsic() const { return mDeathProb_intrinsic; } |
||
308 | werner | 92 | inline double deathProb_stress(const double &stress_index) const; |
169 | werner | 93 | // aging |
425 | werner | 94 | double aging(const float height, const int age) const; |
388 | werner | 95 | int estimateAge(const float height) const;///< estimate age for a tree with the current age |
387 | werner | 96 | // regeneration |
460 | werner | 97 | void seedProduction(const int age, const float height, const QPoint &position_index); |
387 | werner | 98 | void setSeedDispersal(SeedDispersal *seed_dispersal) {mSeedDispersal=seed_dispersal; } |
209 | werner | 99 | // environmental responses |
100 | double vpdResponse(const double &vpd) const; |
||
266 | werner | 101 | inline double temperatureResponse(const double &delayed_temp) const; |
209 | werner | 102 | double nitrogenResponse(const double &availableNitrogen) const { return mSet->nitrogenResponse(availableNitrogen, mRespNitrogenClass); } |
236 | werner | 103 | double canopyConductance() const { return mMaxCanopyConductance; } ///< maximum canopy conductance in m/s |
266 | werner | 104 | inline double soilwaterResponse(const double &psi_kPa) const; ///< input: matrix potential (kPa) (e.g. -15) |
470 | werner | 105 | double lightResponse(const double lightResourceIndex) const {return mSet->lightResponse(lightResourceIndex, mLightResponseClass); } |
304 | werner | 106 | double psiMin() const { return mPsiMin; } |
445 | werner | 107 | // parameters for seed dispersal |
108 | void treeMigKernel(double &ras1, double &ras2, double &ks) const { ras1=mTM_as1; ras2=mTM_as2; ks=mTM_ks; } |
||
109 | double fecundity_m2() const { return mFecundity_m2; } |
||
110 | double nonSeedYearFraction() const { return mNonSeedYearFraction; } |
||
446 | werner | 111 | const EstablishmentParameters &establishmentParameters() const { return mEstablishmentParams; } |
450 | werner | 112 | const SaplingGrowthParameters &saplingGrowthParameters() const { return mSaplingGrowthParams; } |
110 | Werner | 113 | |
136 | Werner | 114 | const Stamp* stamp(const float dbh, const float height) const { return mLIPs.stamp(dbh, height);} |
38 | Werner | 115 | private: |
90 | Werner | 116 | Q_DISABLE_COPY(Species); |
136 | Werner | 117 | // helpers during setup |
236 | werner | 118 | bool boolVar(const QString s) { return mSet->var(s).toBool(); } ///< during setup: get value of variable @p s as a boolean variable. |
136 | Werner | 119 | double doubleVar(const QString s) { return mSet->var(s).toDouble(); }///< during setup: get value of variable @p s as a double. |
236 | werner | 120 | int intVar(const QString s) { return mSet->var(s).toInt(); } ///< during setup: get value of variable @p s as an integer. |
136 | Werner | 121 | QString stringVar(const QString s) { return mSet->var(s).toString(); } ///< during setup: get value of variable @p s as a string. |
475 | werner | 122 | MTRand *mRandomGenerator; |
136 | Werner | 123 | |
91 | Werner | 124 | SpeciesSet *mSet; ///< ptr. to the "parent" set |
136 | Werner | 125 | StampContainer mLIPs; ///< ptr to the container of the LIP-pattern |
91 | Werner | 126 | QString mId; |
127 | QString mName; |
||
493 | werner | 128 | QColor mDisplayColor; |
111 | Werner | 129 | int mIndex; ///< internal index within the SpeciesSet |
236 | werner | 130 | bool mConiferous; ///< true if confierous species (vs. broadleaved) |
131 | bool mEvergreen; ///< true if evergreen species |
||
136 | Werner | 132 | // biomass allometries: |
133 | double mFoliage_a, mFoliage_b; ///< allometry (biomass = a * dbh^b) for foliage |
||
134 | double mWoody_a, mWoody_b; ///< allometry (biomass = a * dbh^b) for woody compartments aboveground |
||
135 | double mRoot_a, mRoot_b; ///< allometry (biomass = a * dbh^b) for roots (compound, fine and coarse roots as one pool) |
||
136 | double mBranch_a, mBranch_b; ///< allometry (biomass = a * dbh^b) for branches |
||
137 | |||
110 | Werner | 138 | double mSpecificLeafArea; ///< conversion factor from kg OTS to m2 LeafArea |
116 | Werner | 139 | // turnover rates |
140 | double mTurnoverLeaf; ///< yearly turnover rate leafs |
||
141 | double mTurnoverRoot; ///< yearly turnover rate root |
||
276 | werner | 142 | double mFinerootFoliageRatio; ///< ratio of fineroot mass (kg) to foliage mass (kg) |
119 | Werner | 143 | // height-diameter-relationships |
144 | Expression mHDlow; ///< minimum HD-relation as f(d) (open grown tree) |
||
145 | Expression mHDhigh; ///< maximum HD-relation as f(d) |
||
125 | Werner | 146 | // stem density and taper |
147 | double mWoodDensity; ///< density of the wood [kg/m3] |
||
148 | double mFormFactor; ///< taper form factor of the stem [-] used for volume / stem-mass calculation calculation |
||
149 | double mVolumeFactor; ///< factor for volume calculation |
||
159 | werner | 150 | // mortality |
151 | double mDeathProb_intrinsic; ///< prob. of intrinsic death per year [0..1] |
||
152 | double mDeathProb_stress; ///< max. prob. of death per year when tree suffering maximum stress |
||
169 | werner | 153 | // Aging |
154 | double mMaximumAge; ///< maximum age of species (years) |
||
155 | double mMaximumHeight; ///< maximum height of species (m) for aging |
||
214 | werner | 156 | Expression mAging; |
209 | werner | 157 | // environmental responses |
158 | double mRespVpdExponent; ///< exponent in vpd response calculation (Mäkela 2008) |
||
159 | double mRespTempMin; ///< temperature response calculation offset |
||
160 | double mRespTempMax; ///< temperature response calculation: saturation point for temp. response |
||
161 | double mRespNitrogenClass; ///< nitrogen response class (1..3). fractional values (e.g. 1.2) are interpolated. |
||
304 | werner | 162 | double mPsiMin; ///< minimum water potential (MPa), i.e. wilting point (is below zero!) |
236 | werner | 163 | // water |
164 | double mMaxCanopyConductance; ///< maximum canopy conductance for transpiration (m/s) |
||
226 | werner | 165 | int mPhenologyClass; |
274 | werner | 166 | double mLightResponseClass; ///< light response class (1..5) (1=shade intolerant) |
387 | werner | 167 | // regeneration |
168 | SeedDispersal *mSeedDispersal; ///< link to the seed dispersal map of the species |
||
445 | werner | 169 | int mMaturityYears; ///< a tree produces seeds if it is older than this parameter |
415 | werner | 170 | double mSeedYearProbability; ///< probability that a year is a seed year (=1/avg.timespan between seedyears) |
171 | bool mIsSeedYear; ///< true, if current year is a seed year. see also: |
||
445 | werner | 172 | double mNonSeedYearFraction; ///< fraction of the seed production in non-seed-years |
173 | // regeneration - seed dispersal |
||
174 | double mFecundity_m2; ///< "surviving seeds" (cf. Moles et al) per m2, see also http://iland.boku.ac.at/fecundity |
||
175 | double mTM_as1; ///< seed dispersal paramaters (treemig) |
||
176 | double mTM_as2; ///< seed dispersal paramaters (treemig) |
||
177 | double mTM_ks; ///< seed dispersal paramaters (treemig) |
||
449 | werner | 178 | EstablishmentParameters mEstablishmentParams; ///< collection of parameters used for establishment |
450 | werner | 179 | SaplingGrowthParameters mSaplingGrowthParams; ///< collection of parameters for sapling growth |
445 | werner | 180 | |
38 | Werner | 181 | }; |
182 | |||
40 | Werner | 183 | |
119 | Werner | 184 | // inlined functions... |
425 | werner | 185 | inline void Species::hdRange(const double dbh, double &rLowHD, double &rHighHD) const |
119 | Werner | 186 | { |
187 | rLowHD = mHDlow.calculate(dbh); |
||
188 | rHighHD = mHDhigh.calculate(dbh); |
||
189 | } |
||
209 | werner | 190 | /** vpdResponse calculates response on vpd. |
191 | Input: vpd [kPa]*/ |
||
192 | inline double Species::vpdResponse(const double &vpd) const |
||
193 | { |
||
194 | return exp(mRespVpdExponent * vpd); |
||
195 | } |
||
119 | Werner | 196 | |
209 | werner | 197 | /** temperatureResponse calculates response on delayed daily temperature. |
198 | Input: average temperature [°C] |
||
199 | Note: slightly different from Mäkela 2008: the maximum parameter (Sk) in iLand is interpreted as the absolute |
||
200 | temperature yielding a response of 1; in Mäkela 2008, Sk is the width of the range (relative to the lower threhold) |
||
201 | */ |
||
202 | inline double Species::temperatureResponse(const double &delayed_temp) const |
||
203 | { |
||
204 | double x = qMax(delayed_temp-mRespTempMin, 0.); |
||
205 | x = qMin(x/(mRespTempMax-mRespTempMin), 1.); |
||
206 | return x; |
||
207 | } |
||
266 | werner | 208 | /** soilwaterResponse is a function of the current matrix potential of the soil. |
209 | werner | 209 | |
266 | werner | 210 | */ |
211 | inline double Species::soilwaterResponse(const double &psi_kPa) const |
||
212 | { |
||
213 | const double psi_mpa = psi_kPa / 1000.; // convert to MPa |
||
304 | werner | 214 | double result = limit( 1. - psi_mpa / mPsiMin, 0., 1.); |
266 | werner | 215 | return result; |
216 | } |
||
217 | |||
308 | werner | 218 | /** calculate probabilty of death based on the current stress index. */ |
219 | inline double Species::deathProb_stress(const double &stress_index) const |
||
220 | { |
||
221 | if (stress_index==0) |
||
222 | return 0.; |
||
223 | double result = 1. - exp(-mDeathProb_stress*stress_index); |
||
224 | return result; |
||
225 | } |
||
226 | |||
90 | Werner | 227 | #endif // SPECIES_H |