https://github.com/StefanKruse/LAVESI
Raw File
Tip revision: c32cbbc296be5acf3223ae0b8b259a333ce9b5ff authored by Stefan Kruse on 10 March 2022, 13:09:09 UTC
Update README.md
Tip revision: c32cbbc
plotupdate.cpp
#include "LAVESI.h"
#include "RandomNumber.h"
#include "VectorList.h"

using namespace std;

void AddTreeDensity(VectorList<Tree>& tree_list, vector<Envirgrid>& plot_list) {
#pragma omp parallel for default(shared) schedule(guided)
    for (unsigned int tree_i = 0; tree_i < tree_list.size(); ++tree_i) {
        auto& tree = tree_list[tree_i];

		if (tree.growing == true) {
			int i = tree.ycoo * parameter[0].sizemagnif / 1000;
			int j = tree.xcoo * parameter[0].sizemagnif / 1000;

			// assess the size of the area the current tree influences
			double impactareasize = 0.0;
			if (parameter[0].calcinfarea == 1)  // linearly increasing
				impactareasize = tree.dbasal * parameter[0].incfac / 100.0;
			else if (parameter[0].calcinfarea == 2)  // linearly increasing
				impactareasize = tree.dbasal * (2 / 3) * parameter[0].incfac / 100.0;
			else if (parameter[0].calcinfarea == 3)  // linearly increasing
				impactareasize = tree.dbasal * (4 / 3) * parameter[0].incfac / 100.0;
			else if (parameter[0].calcinfarea == 4)  // logistic growth function with maximum at 8 m
				impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.1 * tree.dbasal)))) - 1;
			else if (parameter[0].calcinfarea == 5)  // logistic growth function with maximum at 8 m
				impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.2 * tree.dbasal)))) - 1;
			else if (parameter[0].calcinfarea == 6)  // logistic growth function with maximum at 8 m
				impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.5 * tree.dbasal)))) - 1;

			if (impactareasize < (1.0 / parameter[0].sizemagnif)) {  // if the trees influences only one density grid cell
				const std::size_t curposi = static_cast<std::size_t>(i) * static_cast<std::size_t>(treecols) * static_cast<std::size_t>(parameter[0].sizemagnif)
											+ static_cast<std::size_t>(j);
				auto& cur_plot = plot_list[curposi];

				cur_plot.Treedensityvalue += 10000
											 * pow(pow(impactareasize / (1.0 / parameter[0].sizemagnif), parameter[0].densitysmallweighing)
													   // weighing with diameter
													   * pow(tree.dbasal, parameter[0].densitytreetile),
												   parameter[0].densityvaluemanipulatorexp);
				++cur_plot.Treenumber;
				tree.densitywert =
					pow(pow(tree.dbasal, parameter[0].densitytreetile) * pow(impactareasize / (1.0 / parameter[0].sizemagnif), parameter[0].densitysmallweighing),
						parameter[0].densityvaluemanipulatorexp);
			} else {  // if the trees influences more than one density grid cell
				// determine dimensions of the grid around the tree
				int xyquerrastpos = impactareasize * parameter[0].sizemagnif;
				// determine shifted coordinates and adding up the density value
				double sumdensitywert = 0;
				for (int rastposi = (i + xyquerrastpos); rastposi > (i - (xyquerrastpos + 1)); rastposi--) {
					for (int rastposj = (j - xyquerrastpos); rastposj < (j + xyquerrastpos + 1); rastposj++) {
						if ((rastposi <= (int)((treerows - 1) * parameter[0].sizemagnif) && rastposi >= 0)
							&& (rastposj <= (int)((treecols - 1) * parameter[0].sizemagnif) && rastposj >= 0)) {  // TODO directly use in for loop boundaries
							// distance calculation to determine the influence of the density value in spatial units ...
							// ... and inserting the value at every position
							double entfrastpos = sqrt(pow(double(i - rastposi), 2) + pow(double(j - rastposj), 2));
							// only if the current grid cell is part of the influence area, a value is assigned
							if (entfrastpos <= (double)xyquerrastpos) {
								std::size_t curposii =
									static_cast<std::size_t>(rastposi) * static_cast<std::size_t>(treecols) * static_cast<std::size_t>(parameter[0].sizemagnif)
									+ static_cast<std::size_t>(rastposj);
								auto& cur_plot = plot_list[curposii];
								const auto density =
									std::pow(std::pow(tree.dbasal, parameter[0].densitytreetile) / (entfrastpos + 1.0), parameter[0].densityvaluemanipulatorexp);
								cur_plot.Treedensityvalue += 10000 * density;
								++cur_plot.Treenumber;
								sumdensitywert += density;
							}
						}
					}
				}
				tree.densitywert = sumdensitywert;
			}
		}
    }  // each tree
}

void IndividualTreeDensity(VectorList<Tree>& tree_list, vector<Envirgrid>& plot_list) {
    RandomNumber<double> uniform(0, 1);
#pragma omp parallel for default(shared) private(uniform) schedule(guided)
    for (unsigned int tree_i = 0; tree_i < tree_list.size(); ++tree_i) {
        auto& tree = tree_list[tree_i];

		if (tree.growing == true) {
			int i = tree.ycoo * parameter[0].sizemagnif / 1000;
			int j = tree.xcoo * parameter[0].sizemagnif / 1000;

			if (parameter[0].densitymode == 1) {
				tree.densitywert = 0.0;
			} else {
				double impactareasize = 0.0;
				if (parameter[0].calcinfarea == 1)  // linearly increasing
					impactareasize = tree.dbasal * parameter[0].incfac / 100.0;
				else if (parameter[0].calcinfarea == 2)  // linearly increasing
					impactareasize = tree.dbasal * (2 / 3) * parameter[0].incfac / 100.0;
				else if (parameter[0].calcinfarea == 3)  // linearly increasing
					impactareasize = tree.dbasal * (4 / 3) * parameter[0].incfac / 100.0;
				else if (parameter[0].calcinfarea == 4)  // logistic growth function with maximum at 8 m
					impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.1 * tree.dbasal)))) - 1;
				else if (parameter[0].calcinfarea == 5)  // logistic growth function with maximum at 8 m
					impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.2 * tree.dbasal)))) - 1;
				else if (parameter[0].calcinfarea == 6)  // logistic growth function with maximum at 8 m
					impactareasize = (9 / (1 + (((1 / 0.1) - 1) * exp(-0.5 * tree.dbasal)))) - 1;

				// if the tree only influences one grid cell
				if (impactareasize < (1.0 / parameter[0].sizemagnif)) {
					const std::size_t curposi = static_cast<std::size_t>(i) * static_cast<std::size_t>(treecols) * static_cast<std::size_t>(parameter[0].sizemagnif)
												+ static_cast<std::size_t>(j);
					auto& cur_plot = plot_list[curposi];

					if (parameter[0].densitymode == 2) {
						if (cur_plot.Treedensityvalue > 0) {
							if (parameter[0].densitytiletree == 1)  // sum of values
							{
								tree.densitywert = (1.0 - (tree.densitywert / ((double)cur_plot.Treedensityvalue / 10000)));
								//                           density_desired(at position) / density_currently(at position)
							} else if (parameter[0].densitytiletree == 2)  // multiplication of values
							{
								tree.densitywert = (1.0 - (tree.densitywert / (((double)cur_plot.Treedensityvalue / 10000) * tree.densitywert)));
								//                         density_desired(at position) / density_currently(at position)
							}
						} else {
							tree.densitywert = 0.0;  // no competition effect
						}

						// dem sensing
						if (parameter[0].demlandscape) {
							tree.elevation = cur_plot.elevation;
							tree.envirimpact = cur_plot.envirgrowthimpact;
						}
					} else if (parameter[0].densitymode == 3) {
						// determine the grid position randomly
						int izuf = (treerows - 1) * parameter[0].sizemagnif * uniform.draw();
						int jzuf = (treecols - 1) * parameter[0].sizemagnif * uniform.draw();

						std::size_t curposii =
							static_cast<std::size_t>(izuf) * static_cast<std::size_t>(treecols) * static_cast<std::size_t>(parameter[0].sizemagnif)
							+ static_cast<std::size_t>(jzuf);
						auto& cur_plot = plot_list[curposii];

						if (cur_plot.Treedensityvalue > 0) {
							if (parameter[0].densitytiletree == 1)  // sum of values
							{
								tree.densitywert = (1.0 - (tree.densitywert / ((double)cur_plot.Treedensityvalue / 10000)));
								//                           density_desired(at position) / density_currently(at position)
							} else if (parameter[0].densitytiletree == 2)  // multiplication of values
							{
								tree.densitywert = (1.0 - (tree.densitywert / (((double)cur_plot.Treedensityvalue / 10000) * tree.densitywert)));
							}
						} else {
							tree.densitywert = 0.0;
						}
					}

					// calculate the influence of the thawing depth on the tree growth
					if ((cur_plot.maxthawing_depth < 2000) && (parameter[0].thawing_depth == true && parameter[0].spinupphase == false)) {
						tree.thawing_depthinfluence = (unsigned short)((200.0 / 2000.0) * (double)cur_plot.maxthawing_depth);
					} else {
						tree.thawing_depthinfluence = 100;
					}
				} else {  // ... if the tree influences more than one section
					// determine dimensions of the considered grid around a tree
					int xyquerrastpos = impactareasize * parameter[0].sizemagnif;
					double maxdist = sqrt(pow(double(xyquerrastpos), 2) + pow(double(xyquerrastpos), 2));

					// determine rescaled coordinates and summation of the density value
					double sumdensitywert = 0;
					double sumthawing_depth = 0;
					unsigned int anzahlflaechen = 0;

					double sumelevation = 0;
					double sumenvirgrowthimpact = 0;
					unsigned int countelevation = 0;

					for (int rastposi = (i + xyquerrastpos); rastposi > (i - (xyquerrastpos + 1)); rastposi--) {
						for (int rastposj = (j - xyquerrastpos); rastposj < (j + xyquerrastpos + 1); rastposj++) {
							if ((rastposi <= ((int)(treerows - 1) * parameter[0].sizemagnif) && rastposi >= 0)
								&& (rastposj <= ((int)(treecols - 1) * parameter[0].sizemagnif) && rastposj >= 0)) {
								double entfrastpos = sqrt(pow(double(i - rastposi), 2) + pow(double(j - rastposj), 2));

								if (entfrastpos <= (double)xyquerrastpos) {
									int icurr = rastposi;
									int jcurr = rastposj;

									if (parameter[0].densitymode == 3) {  // determine the position of density values randomly
										icurr = (treerows - 1) * parameter[0].sizemagnif * uniform.draw();
										jcurr = (treecols - 1) * parameter[0].sizemagnif * uniform.draw();
									}

									std::size_t curposii =
										static_cast<std::size_t>(icurr) * static_cast<std::size_t>(treecols) * static_cast<std::size_t>(parameter[0].sizemagnif)
										+ static_cast<std::size_t>(jcurr);
									auto& cur_plot = plot_list[curposii];

									if (parameter[0].densitytiletree == 1) {
										sumdensitywert += ((double)cur_plot.Treedensityvalue / 10000) * (1 - entfrastpos / maxdist);
										// added the values influence as becoming weaker in the periphery, otherwise the density value influence would be
										// overestimated
									} else if (parameter[0].densitytiletree == 2) {
										// after weighting the additional values by the individual influence values the offset is added
										sumdensitywert +=
											(((double)cur_plot.Treedensityvalue / 10000) - pow(tree.dbasal, parameter[0].densitytreetile) / (entfrastpos + 1.0))
												* pow(tree.dbasal, parameter[0].densitytreetile) / (entfrastpos + 1.0)
											+ pow(tree.dbasal, parameter[0].densitytreetile) / (entfrastpos + 1.0);
									}

									sumthawing_depth += (double)cur_plot.maxthawing_depth;
									anzahlflaechen++;

									if (parameter[0].demlandscape && (cur_plot.elevation < 32767)) {  // dem sensing
										sumelevation += (double)cur_plot.elevation / 10;
										sumenvirgrowthimpact += (double)cur_plot.envirgrowthimpact / 10000;
										countelevation++;
									}
								}
							}
						}
					}

					if (sumdensitywert > 0.0)
						tree.densitywert = 1.0 - (tree.densitywert / sumdensitywert);
					else
						tree.densitywert = 0.0;

					sumthawing_depth /= anzahlflaechen;

					if (sumthawing_depth < 2000)
						tree.thawing_depthinfluence = (unsigned short)((200.0 / 2000.0) * sumthawing_depth);
					else
						tree.thawing_depthinfluence = 100;

					if (parameter[0].demlandscape) {  // dem sensing by mean value of gridcells in range
						tree.elevation = 10 * sumelevation / (double)countelevation;
						tree.envirimpact = 10000 * sumenvirgrowthimpact / (double)countelevation;
					}
				}

				tree.densitywert = tree.densitywert
								   * pow((1.0 - (0.01 / tree.dbasal)),
										 parameter[0].densityvaluedbasalinfluence);  // increasing influence by increasing tree height

				if (parameter[0].dichtheightrel == 1) {
					tree.densitywert = tree.densitywert * (-1.0 / 130.0 * (double)tree.height / 10 + 1.0);
				} else if (parameter[0].dichtheightrel == 2) {
					tree.densitywert = tree.densitywert * (-1.0 / 200.0 * (double)tree.height / 10 + 1.0);
				} else if (parameter[0].dichtheightrel == 3) {
					double hrelbuf = (-1.0 / 200.0 * (double)tree.height / 10 + 1.0);
					if (hrelbuf < 0.1)
						hrelbuf = 0.1;
					tree.densitywert = tree.densitywert * hrelbuf;
				} else if (parameter[0].dichtheightrel == 4) {
					if ((double)tree.height / 10 < 40)
						tree.densitywert = 1.0;
					else if (((double)tree.height / 10 >= 40) && ((double)tree.height / 10 < 200))
						tree.densitywert = 0.5;
					else if ((double)tree.height / 10 >= 200)
						tree.densitywert = 0.0;
				} else if (parameter[0].dichtheightrel == 5) {
					if ((double)tree.height / 10 < 40)
						tree.densitywert = 1.0;
					else if (((double)tree.height / 10 >= 40) && ((double)tree.height / 10 < 200))
						tree.densitywert = 0.55;
					else if ((double)tree.height / 10 >= 200)
						tree.densitywert = 0.1;
				} else if (parameter[0].dichtheightrel == 6) {
					if ((double)tree.height / 10 < 40)
						tree.densitywert = 1.0;
					else if (((double)tree.height / 10 >= 40) && ((double)tree.height / 10 < 200))
						tree.densitywert = 0.9;
					else if ((double)tree.height / 10 >= 200)
						tree.densitywert = 0.8;
				} else if (parameter[0].dichtheightrel == 10) {  // added to fit the height classes distribution properly
					// density value decreases by increasing tree height linearly
					double densitywertminimum = 0.1;
					double ageseinfluss = (-1 * (1 - densitywertminimum) / 100.0 * (double)tree.age + 1.0);
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;
				} else if (parameter[0].dichtheightrel == 11) {
					double densitywertminimum = 0.5;
					double ageseinfluss = (-1 * (1 - densitywertminimum) / 100.0 * (double)tree.age + 1.0);
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;
				} else if (parameter[0].dichtheightrel == 12) {
					double densitywertminimum = 0.1;
					double ageseinfluss = (-1 * (1 - densitywertminimum) / 50.0 * (double)tree.age + 1.0);
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;
				} else if (parameter[0].dichtheightrel == 13) {
					double densitywertminimum = 0.5;
					double ageseinfluss = (-1 * (1 - densitywertminimum) / 50.0 * (double)tree.age + 1.0);
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;
				} else if (parameter[0].dichtheightrel == 20) {
					double densitywertminimum = 0.1;
					double ageseinfluss = (1.0 / pow(((double)tree.age + 1.0), 0.5));
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;

				} else if (parameter[0].dichtheightrel == 21) {
					double densitywertminimum = 0.5;
					double ageseinfluss = (1.0 / pow(((double)tree.age + 1.0), 0.15));
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;

				} else if (parameter[0].dichtheightrel == 22) {
					double densitywertminimum = 0.1;
					double ageseinfluss = (1.0 / pow(((double)tree.age + 1.0), 0.6));
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;

				} else if (parameter[0].dichtheightrel == 23) {
					double densitywertminimum = 0.5;
					double ageseinfluss = (1.0 / pow(((double)tree.age + 1.0), 0.175));
					if (ageseinfluss < densitywertminimum) {
						ageseinfluss = densitywertminimum;
					}
					tree.densitywert = tree.densitywert * ageseinfluss;
				}

				if (tree.densitywert < 0)
					tree.densitywert = 0.0;

				// set to maximal value if density value is greater than it (rescaling)
				if (tree.densitywert > parameter[0].desitymaxreduction)
					tree.densitywert = parameter[0].desitymaxreduction;
			}
		}
    }
}

/****************************************************************************************/
/**
 * \brief reset Maps "Envirgrid"
 *
 * reset Treedensity und Treenumber \n
 * calculate vegetation density (auflagenstaerke) if vegetation==true
 *\n calculate max active layer depth
 *
 *
 *******************************************************************************************/

void ResetMaps(int yearposition, vector<Envirgrid>& plot_list, vector<Weather>& weather_list) {
    const auto loop_size = static_cast<std::size_t>(treerows) * static_cast<std::size_t>(parameter[0].sizemagnif) * static_cast<std::size_t>(treecols)
                           * static_cast<std::size_t>(parameter[0].sizemagnif);
    if (parameter[0].thawing_depth == true && parameter[0].spinupphase == false) {
        double daempfung = (1.0 / 4000.0) * 200;  // 1/4000 =slope to reach the maximum value at appr. 4000
        // double daempfung = (1.0 / 4000.0) * (double)pEnvirgrid.litterheightmean;  // 1/4000 =slope to reach the maximum value at appr. 4000

        if (daempfung >= 0.9) {
            daempfung = 0.9;
        }

        const unsigned short maxthawing_depth =
            1000.0 * (1.0 - daempfung) * 0.050 * weather_list[yearposition].degreday_sqrt[0];  // 1000 (scaling from m to mm)*edaphicfactor=0.050 (SD=0.019)

#pragma omp parallel for default(shared) schedule(guided)
        for (std::size_t kartenpos = 0; kartenpos < loop_size; ++kartenpos) {
            auto& pEnvirgrid = plot_list[kartenpos];
            pEnvirgrid.Treedensityvalue = 0;
            pEnvirgrid.Treenumber = 0;
            pEnvirgrid.maxthawing_depth = maxthawing_depth;
        }

    } else {
#pragma omp parallel for default(shared) schedule(guided)
        for (std::size_t kartenpos = 0; kartenpos < loop_size; ++kartenpos) {
            auto& pEnvirgrid = plot_list[kartenpos];
            pEnvirgrid.Treedensityvalue = 0;
            pEnvirgrid.Treenumber = 0;
        }
    }
}

/****************************************************************************************/
/**
 * \brief update density maps and active layer depth
 *
 *
 *
 *
 *******************************************************************************************/

void Environmentupdate(//Parameter* parameter,
                       int yearposition,
                       vector<vector<Envirgrid>>& world_plot_list,
                       vector<VectorList<Tree>>& world_tree_list,
                       vector<vector<Weather>>& world_weather_list) {
    int aktort = 0;

    for (vector<vector<Envirgrid>>::iterator posw = world_plot_list.begin(); posw != world_plot_list.end(); ++posw) {
        vector<Envirgrid>& plot_list = *posw;

        vector<VectorList<Tree>>::iterator world_positon_b = (world_tree_list.begin() + aktort);
        VectorList<Tree>& tree_list = *world_positon_b;

        vector<vector<Weather>>::iterator posiwelt = (world_weather_list.begin() + aktort);
        vector<Weather>& weather_list = *posiwelt;

        aktort++;

        ResetMaps(yearposition, plot_list, weather_list);

        AddTreeDensity(tree_list, plot_list);

        IndividualTreeDensity(tree_list, plot_list);
    }
}
back to top