Rev 1044 | Rev 1064 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | |||
671 | 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 | |||
3 | Werner | 21 | #ifndef TREE_H |
22 | #define TREE_H |
||
23 | #include <QPointF> |
||
24 | |||
83 | Werner | 25 | #include "grid.h" |
158 | werner | 26 | // forwards |
90 | Werner | 27 | class Species; |
38 | Werner | 28 | class Stamp; |
187 | iland | 29 | class ResourceUnit; |
151 | iland | 30 | struct HeightGridValue; |
159 | werner | 31 | struct TreeGrowthData; |
264 | werner | 32 | class TreeOut; |
3 | Werner | 33 | |
34 | class Tree |
||
35 | { |
||
36 | public: |
||
141 | Werner | 37 | // lifecycle |
3 | Werner | 38 | Tree(); |
885 | werner | 39 | void setup(); ///< calculates initial values for biomass pools etc. after dimensions are set. |
141 | Werner | 40 | |
41 | // access to properties |
||
885 | werner | 42 | int id() const { return mId; } ///< numerical unique ID of the tree |
43 | int age() const { return mAge; } ///< the tree age (years) |
||
156 | werner | 44 | /// @property position The tree does not store the floating point coordinates but only the index of pixel on the LIF grid |
45 | const QPointF position() const { Q_ASSERT(mGrid!=0); return mGrid->cellCenterPoint(mPositionIndex); } |
||
544 | werner | 46 | const QPoint positionIndex() const { return mPositionIndex; } |
158 | werner | 47 | const Species* species() const { Q_ASSERT(mRU!=0); return mSpecies; } ///< pointer to the tree species of the tree. |
187 | iland | 48 | const ResourceUnit *ru() const { Q_ASSERT(mRU!=0); return mRU; } ///< pointer to the ressource unit the tree belongs to. |
158 | werner | 49 | |
234 | werner | 50 | // properties |
51 | float dbh() const { return mDbh; } ///< dimater at breast height in cm |
||
52 | float height() const { return mHeight; } ///< tree height in m |
||
53 | float lightResourceIndex() const { return mLRI; } ///< LRI of the tree (updated during readStamp()) |
||
54 | float leafArea() const { return mLeafArea; } ///< leaf area (m2) of the tree |
||
158 | werner | 55 | double volume() const; ///< volume (m3) of stem volume based on geometry and density calculated on the fly. |
180 | werner | 56 | double basalArea() const; ///< basal area of the tree at breast height in m2 |
158 | werner | 57 | bool isDead() const { return flag(Tree::TreeDead); } ///< returns true if the tree is already dead. |
407 | werner | 58 | float crownRadius() const; ///< fetch crown radius (m) from the attached stamp |
449 | werner | 59 | // biomass properties |
60 | float biomassFoliage() const { return mFoliageMass; } ///< mass (kg) of foliage |
||
476 | werner | 61 | float biomassBranch() const; ///< mass (kg) of branches |
449 | werner | 62 | float biomassFineRoot() const { return mFineRootMass; } ///< mass (kg) of fine roots |
63 | float biomassCoarseRoot() const { return mCoarseRootMass; } ///< mass (kg) of coarse roots |
||
64 | float biomassStem() const { return mWoodyMass; } ///< mass (kg) of stem |
||
667 | werner | 65 | double barkThickness() const; ///< thickness of the bark (cm) |
1010 | werner | 66 | float stressIndex() const { return mStressIndex; } ///< the scalar stress rating (0..1) |
449 | werner | 67 | |
158 | werner | 68 | // actions |
1044 | werner | 69 | enum TreeRemovalType { TreeDeath=0, TreeHarvest=1, TreeDisturbance=2}; |
713 | werner | 70 | /// the tree dies (is killed) |
71 | void die(TreeGrowthData *d=0); |
||
564 | werner | 72 | /// remove the tree (management). removalFractions for tree compartments: if 0: all biomass stays in the system, 1: all is "removed" |
73 | /// default values: all biomass remains in the forest (i.e.: kill()). |
||
74 | void remove(double removeFoliage=0., double removeBranch=0., double removeStem=0. ); |
||
713 | werner | 75 | /// remove the tree due to an special event (disturbance) |
76 | /// the part of the biomass that goes not to soil/snags is removed (e.g. fire) |
||
77 | /// @param stem_to_soil_fraction (0..1) of stem biomass that is routed to the soil |
||
78 | /// @param stem_to_snag_fraction (0..1) of the stem biomass continues as standing dead |
||
79 | /// @param branch_to_soil_fraction (0..1) of branch biomass that is routed to the soil |
||
80 | /// @param branch_to_snag_fraction (0..1) of the branch biomass continues as standing dead |
||
81 | /// @param foliage_to_soil_fraciton (0..1) fraction of biomass that goes directly to the soil. The rest (1.-fraction) is removed. |
||
82 | void removeDisturbance(const double stem_to_soil_fraction, const double stem_to_snag_fraction, |
||
83 | const double branch_to_soil_fraction, const double branch_to_snag_fraction, |
||
84 | const double foliage_to_soil_fraction); |
||
85 | |||
158 | werner | 86 | void enableDebugging(const bool enable=true) {setFlag(Tree::TreeDebugging, enable); } |
668 | werner | 87 | /// removes fractions (0..1) for foliage, branches, stem from a tree, e.g. due to a fire. |
88 | /// values of "0" remove nothing, "1" removes the full compartent. |
||
903 | werner | 89 | void removeBiomassOfTree(const double removeFoliageFraction, const double removeBranchFraction, const double removeStemFraction); |
158 | werner | 90 | |
91 | // setters for initialization |
||
92 | void setNewId() { mId = m_nextId++; } ///< force a new id for this object (after copying trees) |
||
247 | werner | 93 | void setId(const int id) { mId = id; } ///< set a spcific ID (if provided in stand init file). |
156 | werner | 94 | void setPosition(const QPointF pos) { Q_ASSERT(mGrid!=0); mPositionIndex = mGrid->indexAt(pos); } |
287 | werner | 95 | void setPosition(const QPoint posIndex) { mPositionIndex = posIndex; } |
106 | Werner | 96 | void setDbh(const float dbh) { mDbh=dbh; } |
975 | werner | 97 | void setHeight(const float height); |
106 | Werner | 98 | void setSpecies(Species *ts) { mSpecies=ts; } |
187 | iland | 99 | void setRU(ResourceUnit *ru) { mRU = ru; } |
388 | werner | 100 | void setAge(const int age, const float treeheight); |
158 | werner | 101 | |
885 | werner | 102 | // management flags (used by ABE management system) |
103 | void markForHarvest(bool do_mark) { setFlag(Tree::MarkForHarvest, do_mark);} |
||
104 | bool isMarkedForHarvest() const { return flag(Tree::MarkForHarvest);} |
||
105 | void markForCut(bool do_mark) { setFlag(Tree::MarkForCut, do_mark);} |
||
106 | bool isMarkedForCut() const { return flag(Tree::MarkForCut);} |
||
107 | void markCropTree(bool do_mark) { setFlag(Tree::MarkCropTree, do_mark);} |
||
108 | bool isMarkedAsCropTree() const { return flag(Tree::MarkCropTree);} |
||
951 | werner | 109 | void markCropCompetitor(bool do_mark) { setFlag(Tree::MarkCropCompetitor, do_mark);} |
110 | bool isMarkedAsCropCompetitor() const { return flag(Tree::MarkCropCompetitor);} |
||
1044 | werner | 111 | // death reasons |
112 | void setDeathReasonWind() { setFlag(Tree::TreeDeadWind, true); } |
||
113 | void setDeathReasonBarkBeetle() { setFlag(Tree::TreeDeadBarkBeetle, true); } |
||
114 | void setDeathReasonFire() { setFlag(Tree::TreeDeadFire, true); } |
||
115 | void setDeathCutdown() { setFlag(Tree::TreeDeadKillAndDrop, true); } |
||
1050 | werner | 116 | void setIsHarvested() { setFlag(Tree::TreeHarvested, true); } |
117 | |||
1044 | werner | 118 | bool isDeadWind() const { return flag(Tree::TreeDeadWind);} |
119 | bool isDeadBarkBeetle() const { return flag(Tree::TreeDeadBarkBeetle);} |
||
120 | bool isDeadFire() const { return flag(Tree::TreeDeadFire);} |
||
121 | bool isCutdown() const { return flag(Tree::TreeDeadKillAndDrop);} |
||
1050 | werner | 122 | bool isHarvested() const { return flag(Tree::TreeHarvested);} |
885 | werner | 123 | |
107 | Werner | 124 | // grid based light-concurrency functions |
158 | werner | 125 | void applyLIP(); ///< apply LightInfluencePattern onto the global grid |
187 | iland | 126 | void readLIF(); ///< calculate the lightResourceIndex with multiplicative approach |
107 | Werner | 127 | void heightGrid(); ///< calculate the height grid |
39 | Werner | 128 | |
158 | werner | 129 | void applyLIP_torus(); ///< apply LightInfluencePattern on a closed 1ha area |
130 | void readLIF_torus(); ///< calculate LRI from a closed 1ha area |
||
131 | void heightGrid_torus(); ///< calculate the height grid |
||
155 | werner | 132 | |
251 | werner | 133 | void calcLightResponse(); ///< calculate light response |
107 | Werner | 134 | // growth, etc. |
158 | werner | 135 | void grow(); ///< main growth function to update the tree state. |
107 | Werner | 136 | |
137 | // static functions |
||
151 | iland | 138 | static void setGrid(FloatGrid* gridToStamp, Grid<HeightGridValue> *dominanceGrid); |
40 | Werner | 139 | // statistics |
140 | static void resetStatistics(); |
||
145 | Werner | 141 | static int statPrints() { return m_statPrint; } |
142 | static int statCreated() { return m_statCreated; } |
||
40 | Werner | 143 | |
135 | Werner | 144 | QString dump(); |
145 | Werner | 145 | void dumpList(QList<QVariant> &rTargetList); |
733 | werner | 146 | const Stamp *stamp() const { return mStamp; } ///< TODO: only for debugging purposes |
135 | Werner | 147 | |
3 | Werner | 148 | private: |
110 | Werner | 149 | // helping functions |
159 | werner | 150 | void partitioning(TreeGrowthData &d); ///< split NPP into various plant pools. |
158 | werner | 151 | double relative_height_growth(); ///< estimate height growth based on light status. |
159 | werner | 152 | void grow_diameter(TreeGrowthData &d); ///< actual growth of the tree's stem. |
153 | void mortality(TreeGrowthData &d); ///< main function that checks whether trees is to die |
||
904 | werner | 154 | void recordRemovedVolume(TreeRemovalType reason); ///< record the removed volume in the height grid |
159 | werner | 155 | |
107 | Werner | 156 | // state variables |
169 | werner | 157 | int mId; ///< unique ID of tree |
158 | int mAge; ///< age of tree in years |
||
125 | Werner | 159 | float mDbh; ///< diameter at breast height [cm] |
160 | float mHeight; ///< tree height [m] |
||
156 | werner | 161 | QPoint mPositionIndex; ///< index of the trees position on the basic LIF grid |
107 | Werner | 162 | // biomass compartements |
149 | werner | 163 | float mLeafArea; ///< m2 leaf area |
164 | float mOpacity; ///< multiplier on LIP weights, depending on leaf area status (opacity of the crown) |
||
885 | werner | 165 | float mFoliageMass; ///< kg of foliage (dry) |
166 | float mWoodyMass; ///< kg biomass of aboveground stem biomass |
||
167 | float mFineRootMass; ///< kg biomass of fine roots (linked to foliage mass) |
||
168 | float mCoarseRootMass; ///< kg biomass of coarse roots (allometric equation) |
||
116 | Werner | 169 | // production relevant |
885 | werner | 170 | float mNPPReserve; ///< NPP reserve pool [kg] - stores a part of assimilates for use in less favorable years |
187 | iland | 171 | float mLRI; ///< resulting lightResourceIndex |
212 | werner | 172 | float mLightResponse; ///< light response used for distribution of biomass on RU level |
159 | werner | 173 | // auxiliary |
125 | Werner | 174 | float mDbhDelta; ///< diameter growth [cm] |
159 | werner | 175 | float mStressIndex; ///< stress index (used for mortality) |
176 | |||
187 | iland | 177 | // Stamp, Species, Resource Unit |
106 | Werner | 178 | const Stamp *mStamp; |
179 | Species *mSpecies; |
||
187 | iland | 180 | ResourceUnit *mRU; |
107 | Werner | 181 | |
157 | werner | 182 | // various flags |
183 | int mFlags; |
||
885 | werner | 184 | /// (binary coded) tree flags |
185 | enum Flags { TreeDead=1, TreeDebugging=2, |
||
1050 | werner | 186 | TreeDeadBarkBeetle=16, TreeDeadWind=32, TreeDeadFire=64, TreeDeadKillAndDrop=128, TreeHarvested=256, |
187 | MarkForCut=512, // mark tree for being cut down |
||
188 | MarkForHarvest=1024, // mark tree for being harvested |
||
189 | MarkCropTree=2048, // mark as crop tree |
||
190 | MarkCropCompetitor=4096 // mark as competitor for a crop tree |
||
885 | werner | 191 | }; |
192 | /// set a Flag 'flag' to the value 'value'. |
||
157 | werner | 193 | void setFlag(const Tree::Flags flag, const bool value) { if (value) mFlags |= flag; else mFlags &= (flag ^ 0xffffff );} |
885 | werner | 194 | /// set a number of flags (need to be constructed by or'ing flags together) at the same time to the Boolean value 'value'. |
195 | void setFlag(const int flag, const bool value) { if (value) mFlags |= flag; else mFlags &= (flag ^ 0xffffff );} |
||
196 | /// retrieve the value of the flag 'flag'. |
||
157 | werner | 197 | bool flag(const Tree::Flags flag) const { return mFlags & flag; } |
139 | Werner | 198 | |
117 | Werner | 199 | // special functions |
157 | werner | 200 | bool isDebugging() { return flag(Tree::TreeDebugging); } |
135 | Werner | 201 | |
107 | Werner | 202 | // static data |
106 | Werner | 203 | static FloatGrid *mGrid; |
151 | iland | 204 | static Grid<HeightGridValue> *mHeightGrid; |
53 | Werner | 205 | |
40 | Werner | 206 | // statistics |
207 | static int m_statPrint; |
||
48 | Werner | 208 | static int m_statAboveZ; |
105 | Werner | 209 | static int m_statCreated; |
40 | Werner | 210 | static int m_nextId; |
148 | iland | 211 | |
212 | // friends |
||
213 | friend class TreeWrapper; |
||
180 | werner | 214 | friend class StandStatistics; |
264 | werner | 215 | friend class TreeOut; |
675 | werner | 216 | friend class Snapshot; |
3 | Werner | 217 | }; |
218 | |||
257 | werner | 219 | /// internal data structure which is passed between function and to statistics |
220 | struct TreeGrowthData |
||
221 | { |
||
261 | werner | 222 | double NPP; ///< total NPP (kg) |
223 | double NPP_above; ///< NPP aboveground (kg) (NPP - fraction roots), no consideration of tree senescence |
||
257 | werner | 224 | double NPP_stem; ///< NPP used for growth of stem (dbh,h) |
225 | double stress_index; ///< stress index used for mortality calculation |
||
262 | werner | 226 | TreeGrowthData(): NPP(0.), NPP_above(0.), NPP_stem(0.) {} |
257 | werner | 227 | }; |
3 | Werner | 228 | #endif // TREE_H |