Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1211 | 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 | ********************************************************************************************/ |
||
1111 | werner | 19 | #ifndef SAPLINGS_H |
20 | #define SAPLINGS_H |
||
21 | |||
22 | #include "grid.h" |
||
1113 | werner | 23 | #include "snag.h" |
1162 | werner | 24 | #include <QRectF> |
1174 | werner | 25 | class ResourceUnitSpecies; // forward |
26 | class ResourceUnit; // forward |
||
1111 | werner | 27 | |
28 | struct SaplingTree { |
||
1113 | werner | 29 | SaplingTree() { clear(); } |
1111 | werner | 30 | short unsigned int age; // number of consectuive years the sapling suffers from dire conditions |
1118 | werner | 31 | short signed int species_index; // index of the species within the resource-unit-species container |
1177 | werner | 32 | unsigned char stress_years; // number of consecutive years that a sapling suffers from stress |
1165 | werner | 33 | unsigned char flags; // flags, e.g. whether sapling stems from sprouting |
1111 | werner | 34 | float height; // height of the sapling in meter |
35 | bool is_occupied() const { return height>0.f; } |
||
1118 | werner | 36 | void clear() { age=0; species_index=-1; stress_years=0; flags=0; height=0.f; } |
1177 | werner | 37 | void setSapling(const float h_m, const int age_yrs, const int species_idx) { height=h_m; |
38 | age=static_cast<short unsigned int>(age_yrs); |
||
39 | stress_years=0; |
||
40 | species_index=static_cast<short signed int>(species_idx); } |
||
1165 | werner | 41 | // flags |
42 | bool is_sprout() const { return flags & 1; } |
||
43 | void set_sprout(const bool sprout) {if (sprout) flags |= 1; else flags &= (1 ^ 0xffffff ); } |
||
1174 | werner | 44 | // get resource unit species of the sapling tree |
45 | ResourceUnitSpecies *resourceUnitSpecies(const ResourceUnit *ru); |
||
1111 | werner | 46 | }; |
47 | #define NSAPCELLS 5 |
||
48 | struct SaplingCell { |
||
49 | enum ECellState { CellInvalid=0, CellFree=1, CellFull=2}; |
||
50 | SaplingCell() { |
||
51 | state=CellInvalid; |
||
52 | } |
||
53 | ECellState state; |
||
54 | SaplingTree saplings[NSAPCELLS]; |
||
55 | void checkState() { if (state==CellInvalid) return; |
||
1112 | werner | 56 | bool free = false; |
1111 | werner | 57 | for (int i=0;i<NSAPCELLS;++i) { |
58 | // locked for all species, if a sapling of one species >1.3m |
||
1112 | werner | 59 | if (saplings[i].height>1.3f) {state = CellFull; return; } |
1111 | werner | 60 | // locked, if all slots are occupied. |
61 | if (!saplings[i].is_occupied()) |
||
62 | free=true; |
||
63 | } |
||
64 | state = free? CellFree : CellFull; |
||
65 | } |
||
1117 | werner | 66 | /// get an index to an open slot in the cell, or -1 if all slots are occupied |
67 | int free_index() { |
||
68 | for (int i=0;i<NSAPCELLS;++i) |
||
69 | if (!saplings[i].is_occupied()) |
||
70 | return i; |
||
71 | return -1; |
||
72 | } |
||
1175 | werner | 73 | /// count the number of occupied slots on the pixel |
74 | int n_occupied() { |
||
75 | int n=0; |
||
76 | for (int i=0;i<NSAPCELLS;++i) |
||
77 | n+=saplings[i].is_occupied(); |
||
78 | return n; |
||
79 | } |
||
80 | |||
1117 | werner | 81 | /// add a sapling to this cell, return a pointer to the tree on success, or 0 otherwise |
82 | SaplingTree *addSapling(const float h_m, const int age_yrs, const int species_idx) { |
||
83 | int idx = free_index(); |
||
84 | if (idx==-1) |
||
85 | return 0; |
||
86 | saplings[idx].setSapling(h_m, age_yrs, species_idx); |
||
87 | return &saplings[idx]; |
||
88 | } |
||
89 | /// return the maximum height on the pixel |
||
90 | float max_height() { if (state==CellInvalid) return 0.f; |
||
91 | float h_max = 0.f; |
||
92 | for (int i=0;i<NSAPCELLS;++i) |
||
93 | h_max = std::max(saplings[i].height, h_max); |
||
94 | return h_max; |
||
95 | } |
||
1178 | werner | 96 | bool has_new_saplings() { if (state==CellInvalid) return 0.f; |
97 | for (int i=0;i<NSAPCELLS;++i) |
||
98 | if (saplings[i].is_occupied() && saplings[i].age<2) |
||
99 | return true; |
||
100 | return false; |
||
101 | } |
||
1117 | werner | 102 | /// return the sapling tree of the requested species, or 0 |
103 | SaplingTree *sapling(int species_index) { |
||
104 | if (state==CellInvalid) return 0; |
||
105 | for (int i=0;i<NSAPCELLS;++i) |
||
106 | if (saplings[i].species_index == species_index) |
||
107 | return &saplings[i]; |
||
108 | return 0; |
||
109 | } |
||
1111 | werner | 110 | }; |
111 | class ResourceUnit; |
||
1113 | werner | 112 | class Saplings; |
1111 | werner | 113 | |
1117 | werner | 114 | /** The SaplingStat class stores statistics on the resource unit x species level. |
115 | */ |
||
1113 | werner | 116 | class SaplingStat |
117 | { |
||
118 | public: |
||
1115 | werner | 119 | SaplingStat() { clearStatistics(); } |
1113 | werner | 120 | void clearStatistics(); |
1176 | werner | 121 | /// calculate statistics (and carbon flows) for the saplings of species 'species' on 'ru'. |
1177 | werner | 122 | void calculate(const Species *species, ResourceUnit *ru); |
1113 | werner | 123 | // actions |
1160 | werner | 124 | void addCarbonOfDeadSapling(float dbh) { mDied++; mSumDbhDied+=dbh; } |
1111 | werner | 125 | |
1113 | werner | 126 | // access to statistics |
127 | int newSaplings() const { return mAdded; } |
||
128 | int diedSaplings() const { return mDied; } |
||
1177 | werner | 129 | int livingCohorts() const { return mLiving; } ///< get the number of cohorts |
130 | double livingSaplings() const { return mLivingSaplings; } |
||
131 | double livingSaplingsSmall() const { return mLivingSmallSaplings; } |
||
1113 | werner | 132 | int recruitedSaplings() const { return mRecruited; } |
133 | /// returns the *represented* (Reineke's Law) number of trees (N/ha) and the mean dbh/height (cm/m) |
||
1162 | werner | 134 | double livingStemNumber(const Species *species, double &rAvgDbh, double &rAvgHeight, double &rAvgAge) const; |
1113 | werner | 135 | |
136 | double averageHeight() const { return mAvgHeight; } |
||
137 | double averageAge() const { return mAvgAge; } |
||
138 | double averageDeltaHPot() const { return mAvgDeltaHPot; } |
||
139 | double averageDeltaHRealized() const { return mAvgHRealized; } |
||
140 | // carbon and nitrogen |
||
141 | const CNPair &carbonLiving() const { return mCarbonLiving; } ///< state of the living |
||
142 | const CNPair &carbonGain() const { return mCarbonGain; } ///< state of the living |
||
143 | |||
144 | private: |
||
1177 | werner | 145 | int mAdded; ///< number of tree cohorts added |
146 | int mRecruited; ///< number of cohorts recruited (i.e. grown out of regeneration layer) |
||
147 | int mDied; ///< number of tree cohorts died |
||
1113 | werner | 148 | double mSumDbhDied; ///< running sum of dbh of died trees (used to calculate detritus) |
149 | int mLiving; ///< number of trees (cohorts!!!) currently in the regeneration layer |
||
1177 | werner | 150 | double mLivingSaplings; ///< number of individual trees in the regen layer (using Reinekes R), with h>1.3m |
151 | double mLivingSmallSaplings; ///< number of individual trees of cohorts < 1.3m height |
||
1113 | werner | 152 | double mAvgHeight; ///< average height of saplings (m) |
153 | double mAvgAge; ///< average age of saplings (years) |
||
154 | double mAvgDeltaHPot; ///< average height increment potential (m) |
||
155 | double mAvgHRealized; ///< average realized height increment |
||
1175 | werner | 156 | CNPair mCarbonLiving; ///< kg Carbon (kg/ru) of saplings |
1113 | werner | 157 | CNPair mCarbonGain; ///< net growth (kg / ru) of saplings |
158 | |||
159 | friend class Saplings; |
||
160 | |||
161 | }; |
||
1117 | werner | 162 | /** The Saplings class the container for the establishment and sapling growth in iLand. |
163 | * |
||
164 | */ |
||
1111 | werner | 165 | class Saplings |
166 | { |
||
167 | public: |
||
168 | Saplings(); |
||
169 | void setup(); |
||
1178 | werner | 170 | void calculateInitialStatistics(const ResourceUnit *ru); |
1111 | werner | 171 | // main functions |
172 | void establishment(const ResourceUnit *ru); |
||
1113 | werner | 173 | void saplingGrowth(const ResourceUnit *ru); |
174 | |||
1117 | werner | 175 | // access |
1162 | werner | 176 | /// return the SaplingCell (i.e. container for the ind. saplings) for the given 2x2m coordinates |
177 | /// if 'only_valid' is true, then 0 is returned if no living saplings are on the cell |
||
178 | /// 'rRUPtr' is a pointer to a RU-ptr: if provided, a pointer to the resource unit is stored |
||
179 | SaplingCell *cell(QPoint lif_coords, bool only_valid=true, ResourceUnit **rRUPtr=0); |
||
180 | /// clear/kill all saplings within the rectangle given by 'rectangle'. |
||
1165 | werner | 181 | /// If 'remove_biomass' is true, then the biomass is extracted (e.g. burnt), otherwise they are moved to soil |
1162 | werner | 182 | void clearSaplings(const QRectF &rectangle, const bool remove_biomass); |
1165 | werner | 183 | /// clear all saplings on a given cell 's' (if 'remove_biomass' is true: biomass removed from system (e.g. burnt)) |
184 | void clearSaplings(SaplingCell *s, ResourceUnit *ru, const bool remove_biomass); |
||
1111 | werner | 185 | |
1165 | werner | 186 | /// generate vegetative offspring from 't' (sprouts) |
187 | int addSprout(const Tree *t); |
||
188 | |||
1113 | werner | 189 | static void setRecruitmentVariation(const double variation) { mRecruitmentVariation = variation; } |
190 | static void updateBrowsingPressure(); |
||
191 | |||
1111 | werner | 192 | private: |
1177 | werner | 193 | bool growSapling(const ResourceUnit *ru, SaplingCell &scell, SaplingTree &tree, int isc, float dom_height, float lif_value, int cohorts_on_px); |
1159 | werner | 194 | //Grid<SaplingCell> mGrid; |
1113 | werner | 195 | static double mRecruitmentVariation; |
196 | static double mBrowsingPressure; |
||
1111 | werner | 197 | }; |
198 | |||
1213 | werner | 199 | |
200 | /** SaplingCellRunner is a helper class to access all SaplingCell that |
||
201 | * are located on a given "stand" (in the stand grid) |
||
202 | */ |
||
203 | class MapGrid; // forward |
||
204 | class SaplingCellRunner |
||
205 | { |
||
206 | public: |
||
207 | SaplingCellRunner(const int stand_id, const MapGrid *stand_grid=0); |
||
1214 | werner | 208 | ~SaplingCellRunner(); |
1213 | werner | 209 | SaplingCell *next(); |
210 | ResourceUnit *ru() const { return mRU; } |
||
211 | QPointF currentCoord() const; |
||
212 | private: |
||
213 | GridRunner<float> *mRunner; |
||
214 | ResourceUnit *mRU; |
||
215 | const MapGrid *mStandGrid; |
||
216 | int mStandId; |
||
217 | }; |
||
218 | |||
1111 | werner | 219 | #endif // SAPLINGS_H |