Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
701 | 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 | #ifndef WINDMODULE_H |
||
20 | #define WINDMODULE_H |
||
21 | #include "grid.h" |
||
22 | #include "layeredgrid.h" |
||
722 | werner | 23 | #include "expression.h" |
711 | werner | 24 | #include <QHash> |
25 | |||
26 | class Tree; // forward |
||
27 | class Species; // forward |
||
717 | werner | 28 | class ResourceUnit; // forward |
711 | werner | 29 | |
701 | werner | 30 | /** data structure for a single wind cell (usually 10x10m). |
31 | @ingroup windmodule |
||
32 | |||
33 | */ |
||
34 | class WindCell { |
||
35 | public: |
||
1157 | werner | 36 | WindCell() { topex = 0; n_affected=0; sum_volume_killed=0.; edge_age=0; clear(); } |
37 | void clear() {height = edge = 0.f; n_trees=0.f; tree=0; n_killed = 0; basal_area_killed = 0.f; cws_uproot = 0.; cws_break= crown_windspeed= 0.; n_iteration = 0;} |
||
701 | werner | 38 | bool isValid() const { return height<9999.f; } ///< returns true if the pixel is on the valid project area |
742 | werner | 39 | float topex; ///< topographic modifier for wind speed (-) |
701 | werner | 40 | float height; ///< top height (m). |
1157 | werner | 41 | float n_trees; ///< number of trees on pixel |
714 | werner | 42 | const Tree *tree; ///< pointer to the tallest tree on the pixel (if already populated) |
701 | werner | 43 | float edge; ///< maximum difference to neighboring cells (m) |
712 | werner | 44 | // statistics |
45 | int n_iteration; ///< number of iteration this pixel is processed (and trees are killed) |
||
46 | int n_killed; ///< number of trees killed on the pixel |
||
1157 | werner | 47 | int edge_age; ///< age of an edge (consecutive number of years of being an edge) |
48 | double basal_area_killed; ///< basal area of trees that died (m2) (during an event) |
||
712 | werner | 49 | double cws_uproot; ///< critital wind speed for uprooting (m/s) |
50 | double cws_break; ///< critical wind speed for tree breakage (m/s) |
||
51 | double crown_windspeed; ///< wind speed (m/s) on the cecll |
||
1054 | werner | 52 | int n_affected; ///< number of storm that killed trees on that pixel. |
1157 | werner | 53 | double sum_volume_killed; ///< running sum of killed tree volume on that pixel (m3) |
701 | werner | 54 | }; |
714 | werner | 55 | // data structure for a resource unit |
56 | class WindRUCell { |
||
57 | public: |
||
742 | werner | 58 | WindRUCell(): flag(0), soilIsFrozen(false) {} |
59 | int flag; // flag to indicate that the trees of the current resource are already processed |
||
721 | werner | 60 | bool soilIsFrozen; |
714 | werner | 61 | }; |
701 | werner | 62 | |
63 | /** Helper class manage and visualize data layers related to fire. |
||
1036 | werner | 64 | @ingroup windmodule |
701 | werner | 65 | */ |
66 | class WindLayers: public LayeredGrid<WindCell> { |
||
67 | public: |
||
68 | void setGrid(const Grid<WindCell> &grid) { mGrid = &grid; } |
||
69 | double value(const WindCell& data, const int index) const; |
||
1014 | werner | 70 | const QVector<LayerElement> &names(); |
717 | werner | 71 | // specifics for wind layers |
72 | void setRUGrid(const Grid<WindRUCell> *grid) { mRUGrid = grid; } |
||
73 | private: |
||
1014 | werner | 74 | QVector<LayerElement> mNames; |
721 | werner | 75 | double ruValueAt(const WindCell *cell, const int what) const; // get resource-unit level factor at cell "cell" |
717 | werner | 76 | const Grid<WindRUCell> *mRUGrid; |
701 | werner | 77 | }; |
78 | |||
711 | werner | 79 | /** Species parameters that are specific to the wind module |
80 | */ |
||
81 | struct WindSpeciesParameters |
||
82 | { |
||
83 | WindSpeciesParameters(): crown_area_factor(0.5), crown_length(0.5), Creg(111), MOR(30.6), wet_biomass_factor(1.86) {} |
||
84 | double crown_area_factor; // empirical factor related to the crown shape (fraction of crown shape compared to rectangle) |
||
85 | double crown_length; // crown length of the tree (fraction of tree height) |
||
86 | double Creg; // Nm/kg, critical turning coefficient from tree pulling |
||
87 | double MOR; // MPa, modulus of rupture |
||
88 | double wet_biomass_factor; // conversion factor between dry and wet biomass (wet = dry*factor) |
||
89 | }; |
||
701 | werner | 90 | |
91 | /** @class WindModule |
||
92 | @ingroup windmodule |
||
93 | The WindModule is the disturbance module for simulation wind and windthrow in iLand. */ |
||
94 | class WindModule |
||
95 | { |
||
96 | public: |
||
97 | WindModule(); |
||
705 | werner | 98 | static double cellsize() { return 10.; } |
701 | werner | 99 | /// the general setup routine after starting iland |
100 | void setup(); |
||
717 | werner | 101 | void setupResourceUnit(const ResourceUnit* ru); |
1080 | werner | 102 | WindLayers &layers() { return mWindLayers; } |
701 | werner | 103 | |
104 | /// main function of the disturbance module |
||
719 | werner | 105 | void run(const int iteration=-1, const bool execute_from_script=false); |
702 | werner | 106 | |
107 | // test functions |
||
712 | werner | 108 | void setWindProperties(const double direction_rad, const double speed_ms) { mWindDirection = direction_rad; mWindSpeed = speed_ms; } |
109 | void setSimulationMode(const bool mode) { mSimulationMode = mode; } |
||
1157 | werner | 110 | bool simulationMode() const { return mSimulationMode; } |
716 | werner | 111 | void setMaximumIterations(const double maxit) { mMaxIteration = maxit; } |
712 | werner | 112 | |
702 | werner | 113 | void testFetch(double degree_direction); |
711 | werner | 114 | void testEffect(); |
701 | werner | 115 | private: |
712 | werner | 116 | // main functions |
719 | werner | 117 | bool eventTriggered(); ///< determine details of this years' wind event (and return false if no event happens) |
701 | werner | 118 | void initWindGrid(); ///< load state from iland main module |
1157 | werner | 119 | void detectEdges(bool at_startup=false); ///< detect all pixels that are higher than the surrounding and therefore are likely candidates for damage |
712 | werner | 120 | void calculateFetch(); ///< calculate maximum gap sizes in upwind direction |
121 | int calculateWindImpact(); ///< do one round of wind effect calculations |
||
122 | |||
123 | // details |
||
702 | werner | 124 | /// find distance to the next pixels that give shelter |
125 | bool checkFetch(const int startx, const int starty, const double direction, const double max_distance, const double threshold) ; |
||
711 | werner | 126 | /// perform the wind effect calculations for a given grid cell |
716 | werner | 127 | bool windImpactOnPixel(const QPoint position, WindCell *cell); |
711 | werner | 128 | /// |
1157 | werner | 129 | double calculateCrownWindSpeed(const Tree *tree, const WindSpeciesParameters ¶ms, const double n_trees, const double wind_speed_10); |
712 | werner | 130 | double calculateCrititalWindSpeed(const Tree *tree, const WindSpeciesParameters ¶ms, const double gap_length, double &rCWS_uproot, double &rCWS_break); |
721 | werner | 131 | /// check if the soil on current resource unit is frozen or not |
132 | bool isSoilFrozen(const ResourceUnit *ru, const int day_of_year) const; |
||
1157 | werner | 133 | |
711 | werner | 134 | // helping functions |
714 | werner | 135 | void scanResourceUnitTrees(const QPoint &position); |
711 | werner | 136 | void loadSpeciesParameter(const QString &table_name); |
137 | const WindSpeciesParameters &speciesParameter(const Species *s); |
||
1157 | werner | 138 | void initializeEdgeAge(const int years); |
139 | void incrementEdgeAge(); |
||
712 | werner | 140 | |
141 | // variables |
||
742 | werner | 142 | bool mTopexFromGrid; ///< indicates if topex grid is a real grid or by ressource unit |
712 | werner | 143 | double mWindDirection; ///< direction of the current wind event (rad) |
716 | werner | 144 | double mWindDirectionVariation; ///< random variation in wind direction |
712 | werner | 145 | double mWindSpeed; ///< wind speed (TODO: per resource unit!) |
746 | werner | 146 | double mEdgeDetectionThreshold; ///< minimum height difference of height-grid pixels to be detected as edges (default is 10m) |
782 | werner | 147 | double mFactorEdge; ///< constant ratio between the maximujm turning moments at the stand edge and conditions well inside the forest (default: 5) |
721 | werner | 148 | int mWindDayOfYear; ///< day of year of the wind event (0..365) |
712 | werner | 149 | bool mSimulationMode; ///< if true, no trees are removed (test mode) |
716 | werner | 150 | int mCurrentIteration; ///< current iteration (1..n) |
151 | int mMaxIteration; ///< maximum number of iterations |
||
717 | werner | 152 | double mGustModifier; ///< Modification range accounting for differences in wind speed between iterations (0..1) |
153 | double mCurrentGustFactor; ///< gustfactor of the current year (multiplier) |
||
746 | werner | 154 | enum ETopexFactorModificationType {gfMultiply, gfAdd} mTopexFactorModificationType; ///< determines if topo-modifier is added multiplicatively or additively. |
717 | werner | 155 | double mIterationsPerMinute; ///< number of iterations per minute of the events' duration |
1157 | werner | 156 | int mEdgeAgeBaseValue; ///< initial value for the age of edges in the initial state of the forest |
157 | Expression mEdgeProbability; ///< function that determines the probability that an edge is calculated (old edges are less likely to being tested) |
||
158 | double mEdgeBackgroundProbability; ///< probability that a 10x10m pixel is marked as edge during a wind event (randomly) |
||
716 | werner | 159 | // some statistics |
160 | int mPixelAffected; ///< total number of pixels that are impacted |
||
161 | int mTreesKilled; ///< total number of killed trees |
||
162 | double mTotalKilledBasalArea; ///< total basal area of killed trees |
||
1060 | werner | 163 | double mTotalKilledVolume; ///< total tree volume (m3) killed |
724 | werner | 164 | enum ESoilFreezeMode {esfFrozen, esfNotFrozen, esfAuto, esfInvalid} mSoilFreezeMode; ///< if "esfAuto", soil-freeze-state is derived from climate |
701 | werner | 165 | Grid<WindCell> mGrid; ///< wind grid (10x10m) |
714 | werner | 166 | Grid<WindRUCell> mRUGrid; ///< grid for resource unit data |
701 | werner | 167 | WindLayers mWindLayers; ///< helping structure |
711 | werner | 168 | // species parameters for the wind module |
169 | QHash<const Species*, WindSpeciesParameters> mSpeciesParameters; |
||
722 | werner | 170 | /// formula for the transfer function LRI |
171 | Expression mLRITransferFunction; |
||
717 | werner | 172 | |
1157 | werner | 173 | QString mAfterExecEvent; |
174 | |||
717 | werner | 175 | friend class WindScript; |
1054 | werner | 176 | friend class WindOut; |
1157 | werner | 177 | friend void nc_calculateFetch(WindCell *begin, WindCell *end); |
178 | friend void nc_calculateWindImpact(ResourceUnit *unit); |
||
717 | werner | 179 | |
701 | werner | 180 | }; |
181 | |||
182 | |||
183 | |||
184 | #endif // WINDMODULE_H |