protected override void LogYear(Model model, SqliteCommand insertRow) { foreach (ResourceUnit ru in model.Landscape.ResourceUnits) { if (ru.EnvironmentID == -1) { continue; // do not include if out of project area } foreach (ResourceUnitTreeSpecies ruSpecies in ru.Trees.SpeciesAvailableOnResourceUnit) { ResourceUnitTreeStatistics stat = ruSpecies.StatisticsDead; if (stat.TreeCount == 0.0) { continue; } insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = ru.ResourceUnitGridIndex; insertRow.Parameters[2].Value = ru.EnvironmentID; insertRow.Parameters[3].Value = ruSpecies.Species.ID; insertRow.Parameters[4].Value = stat.TreeCount; insertRow.Parameters[5].Value = stat.AverageDbh; insertRow.Parameters[6].Value = stat.AverageHeight; insertRow.Parameters[7].Value = stat.StemVolume; insertRow.Parameters[8].Value = stat.BasalArea; insertRow.Parameters[9].Value = stat.TreeNpp; insertRow.Parameters[10].Value = stat.TreeNppAboveground; insertRow.ExecuteNonQuery(); } } }
protected override void LogYear(Model model, SqliteCommand insertRow) { if (this.filter.IsEmpty == false) { if (this.filter.Evaluate(model.CurrentYear) == 0.0) { return; } } // clear landscape stats foreach (KeyValuePair <string, LandscapeTreeSpeciesStatistics> speciesStatistics in this.treeSpeciesStatistics) { speciesStatistics.Value.Zero(); } foreach (ResourceUnit ru in model.Landscape.ResourceUnits) { if (ru.EnvironmentID == -1) { continue; // do not include if out of project area } foreach (ResourceUnitTreeSpecies ruSpecies in ru.Trees.SpeciesAvailableOnResourceUnit) { ResourceUnitTreeStatistics ruSpeciesStats = ruSpecies.Statistics; if (ruSpeciesStats.TreeCount == 0 && ruSpeciesStats.CohortCount == 0 && ruSpeciesStats.LiveAndSnagStemVolume == 0.0F) { continue; } if (this.treeSpeciesStatistics.TryGetValue(ruSpecies.Species.ID, out LandscapeTreeSpeciesStatistics? speciesStatistics) == false) { speciesStatistics = new LandscapeTreeSpeciesStatistics(); this.treeSpeciesStatistics.Add(ruSpecies.Species.ID, speciesStatistics); } speciesStatistics.AddResourceUnit(ru, ruSpeciesStats); } } // write species to output stream foreach (KeyValuePair <string, LandscapeTreeSpeciesStatistics> species in this.treeSpeciesStatistics) { LandscapeTreeSpeciesStatistics speciesStats = species.Value; speciesStats.ConvertSumsToAreaWeightedAverages(); insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = species.Key; // keys: year, species insertRow.Parameters[2].Value = speciesStats.TreeCount; insertRow.Parameters[3].Value = speciesStats.AverageDbh; insertRow.Parameters[4].Value = speciesStats.AverageHeight; insertRow.Parameters[5].Value = speciesStats.LiveStemVolume; insertRow.Parameters[6].Value = speciesStats.TotalCarbon; insertRow.Parameters[7].Value = speciesStats.LiveAndSnagStemVolume; insertRow.Parameters[8].Value = speciesStats.BasalArea; insertRow.Parameters[9].Value = speciesStats.TreeNpp; insertRow.Parameters[10].Value = speciesStats.TreeNppAboveground; insertRow.Parameters[11].Value = speciesStats.LeafAreaIndex; insertRow.Parameters[12].Value = speciesStats.CohortCount; insertRow.ExecuteNonQuery(); } }
protected override void LogYear(Model model, SqliteCommand insertRow) { if (this.mYearFilter.IsEmpty == false) { if (this.mYearFilter.Evaluate(model.CurrentYear) == 0.0) { return; } } foreach (ResourceUnit ru in model.Landscape.ResourceUnits) { if (ru.EnvironmentID == -1) { continue; // do not include if out of project area } foreach (ResourceUnitTreeSpecies ruSpecies in ru.Trees.SpeciesAvailableOnResourceUnit) { ResourceUnitTreeStatistics speciesStats = ruSpecies.Statistics; if (speciesStats.TreeCount == 0 && speciesStats.CohortCount == 0) { continue; } insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = ru.ResourceUnitGridIndex; insertRow.Parameters[2].Value = ru.EnvironmentID; insertRow.Parameters[3].Value = ruSpecies.Species.ID; insertRow.Parameters[4].Value = ru.AreaInLandscape / Constant.RUArea; // keys // insertRow.Parameters[4].Value = ru.boundingBox().center().x() << ru.boundingBox().center().y(); // temp insertRow.Parameters[5].Value = speciesStats.TreeCount; insertRow.Parameters[6].Value = speciesStats.AverageDbh; insertRow.Parameters[7].Value = speciesStats.AverageHeight; insertRow.Parameters[8].Value = speciesStats.StemVolume; insertRow.Parameters[9].Value = speciesStats.GetTotalCarbon(); insertRow.Parameters[10].Value = speciesStats.LiveAndSnagStemVolume; insertRow.Parameters[11].Value = speciesStats.BasalArea; insertRow.Parameters[12].Value = speciesStats.TreeNpp; insertRow.Parameters[13].Value = speciesStats.TreeNppAboveground; insertRow.Parameters[14].Value = speciesStats.LeafAreaIndex; insertRow.Parameters[15].Value = speciesStats.CohortCount; insertRow.ExecuteNonQuery(); } } }
protected override void LogYear(Model model, SqliteCommand insertRow) { foreach (ResourceUnit ru in model.Landscape.ResourceUnits) { if (ru.EnvironmentID == -1) { continue; // do not include if out of project area } if (this.mResouceUnitFilter.IsEmpty == false) { Debug.Assert(this.mResouceUnitFilter.Wrapper != null); ((ResourceUnitWrapper)this.mResouceUnitFilter.Wrapper).ResourceUnit = ru; if (this.mResouceUnitFilter.Execute() == 0.0) { continue; } } foreach (ResourceUnitTreeSpecies ruSpecies in ru.Trees.SpeciesAvailableOnResourceUnit) { ResourceUnitTreeStatistics stat = ruSpecies.Statistics; SaplingProperties sap = ruSpecies.SaplingStats; if (stat.SaplingCount == 0) { continue; } insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = ru.ResourceUnitGridIndex; insertRow.Parameters[2].Value = ru.EnvironmentID; insertRow.Parameters[3].Value = ruSpecies.Species.ID; // keys // calculate statistics based on the number of represented trees per cohort // float n = sap.livingStemNumber(rus.species(), out float avg_dbh, out float avg_height, out float avg_age; insertRow.Parameters[4].Value = sap.LivingSaplings; insertRow.Parameters[5].Value = sap.LivingSaplingsSmall; insertRow.Parameters[6].Value = sap.LivingCohorts; insertRow.Parameters[7].Value = sap.AverageHeight; insertRow.Parameters[8].Value = sap.AverageAge; insertRow.ExecuteNonQuery(); } } }
public void AddResourceUnit(ResourceUnit ru, ResourceUnitTreeStatistics ruSpeciesStats) { if (ruSpeciesStats.IsPerHectare == false) { throw new ArgumentOutOfRangeException(nameof(ruSpeciesStats), "Attempt to aggregate species statistics which are not per hectare."); } this.totalAreaInLandscape += ru.AreaInLandscape; this.totalAreaWithTrees += ru.AreaWithTrees; this.AverageDbh += ruSpeciesStats.AverageDbh * ru.AreaInLandscape; this.AverageHeight += ruSpeciesStats.AverageHeight * ru.AreaInLandscape; this.BasalArea += ruSpeciesStats.BasalArea * ru.AreaInLandscape; this.CohortCount += ruSpeciesStats.CohortCount * ru.AreaInLandscape; this.LeafAreaIndex += ruSpeciesStats.LeafArea; this.LiveAndSnagStemVolume += ruSpeciesStats.LiveAndSnagStemVolume * ru.AreaInLandscape; this.LiveStemVolume += ruSpeciesStats.StemVolume * ru.AreaInLandscape; this.TreeCount += ruSpeciesStats.TreeCount * ru.AreaInLandscape; this.TotalCarbon += ruSpeciesStats.GetTotalCarbon() * ru.AreaInLandscape; this.TreeNpp += ruSpeciesStats.TreeNpp * ru.AreaInLandscape; this.TreeNppAboveground += ruSpeciesStats.TreeNppAboveground * ru.AreaInLandscape; }
protected override void LogYear(Model model, SqliteCommand insertRow) { // global condition if ((this.mYearFilter.IsEmpty == false) && (this.mYearFilter.Evaluate(model.CurrentYear) == 0.0)) { return; } bool isRUlevel = true; // switch off details if this is indicated in the conditionRU option if ((this.mResourceUnitFilter.IsEmpty == false) && (this.mResourceUnitFilter.Evaluate(model.CurrentYear) == 0.0)) { isRUlevel = false; } float[] accumulatedValues = new float[23]; // 8 data values foreach (ResourceUnit ru in model.Landscape.ResourceUnits) { if (ru.EnvironmentID == -1 || ru.Snags == null) { continue; // do not include if out of project area } Debug.Assert(ru.Snags != null, "Resource unit has null soil when its snags are non-null."); ResourceUnitTreeStatistics ruStatistics = ru.Trees.StatisticsForAllSpeciesAndStands; if (ruStatistics.IsPerHectare == false) { throw new NotSupportedException("Attempt to log statistics which are not per hectare."); } float areaFactor = ru.AreaInLandscape / Constant.RUArea; // conversion factor from real area to per ha values if (isRUlevel) { insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = ru.ResourceUnitGridIndex; insertRow.Parameters[2].Value = ru.EnvironmentID; insertRow.Parameters[3].Value = areaFactor; // biomass from trees (scaled to 1ha already) insertRow.Parameters[4].Value = ruStatistics.StemCarbon; insertRow.Parameters[5].Value = ruStatistics.StemNitrogen; insertRow.Parameters[6].Value = ruStatistics.BranchCarbon; insertRow.Parameters[7].Value = ruStatistics.BranchNitrogen; insertRow.Parameters[8].Value = ruStatistics.FoliageCarbon; insertRow.Parameters[9].Value = ruStatistics.FoliageNitrogen; insertRow.Parameters[10].Value = ruStatistics.CoarseRootCarbon; insertRow.Parameters[11].Value = ruStatistics.CoarseRootNitrogen; insertRow.Parameters[12].Value = ruStatistics.FineRootCarbon; insertRow.Parameters[13].Value = ruStatistics.FineRootNitrogen; // biomass from regeneration insertRow.Parameters[14].Value = ruStatistics.RegenerationCarbon; insertRow.Parameters[15].Value = ruStatistics.RegenerationNitrogen; // biomass from standing dead woods if (ru.Snags.TotalStanding == null) // expected in year 0 { insertRow.Parameters[16].Value = 0.0; insertRow.Parameters[17].Value = 0.0; } else { insertRow.Parameters[16].Value = ru.Snags.TotalStanding.C / areaFactor; insertRow.Parameters[17].Value = ru.Snags.TotalStanding.N / areaFactor; // snags } if (ru.Snags.TotalBranchesAndRoots == null) { insertRow.Parameters[18].Value = 0.0; insertRow.Parameters[19].Value = 0.0; } else { insertRow.Parameters[18].Value = ru.Snags.TotalBranchesAndRoots.C / areaFactor; insertRow.Parameters[19].Value = ru.Snags.TotalBranchesAndRoots.N / areaFactor; // snags, other (branch + coarse root) } // biomass from soil (convert from t/ha . kg/ha) insertRow.Parameters[20].Value = ru.Soil !.YoungRefractory.C * 1000.0; // wood, 16.8.0 nullable analysis misses RU consistency check above insertRow.Parameters[21].Value = ru.Soil.YoungRefractory.N * 1000.0; insertRow.Parameters[22].Value = ru.Soil.YoungLabile.C * 1000.0; // litter insertRow.Parameters[23].Value = ru.Soil.YoungLabile.N * 1000.0; insertRow.Parameters[24].Value = ru.Soil.OrganicMatter.C * 1000.0; // soil insertRow.Parameters[25].Value = ru.Soil.OrganicMatter.N * 1000.0; insertRow.ExecuteNonQuery(); } // landscape level statistics accumulatedValues[0] += areaFactor; // carbon pools aboveground are in kg/resource unit, e.g., the sum of stem-carbon of all trees, so no scaling required accumulatedValues[1] += ruStatistics.StemCarbon * areaFactor; accumulatedValues[2] += ruStatistics.StemNitrogen * areaFactor; accumulatedValues[3] += ruStatistics.BranchCarbon * areaFactor; accumulatedValues[4] += ruStatistics.BranchNitrogen * areaFactor; accumulatedValues[5] += ruStatistics.FoliageCarbon * areaFactor; accumulatedValues[6] += ruStatistics.FoliageNitrogen * areaFactor; accumulatedValues[7] += ruStatistics.CoarseRootCarbon * areaFactor; accumulatedValues[8] += ruStatistics.CoarseRootNitrogen * areaFactor; accumulatedValues[9] += ruStatistics.FineRootCarbon * areaFactor; accumulatedValues[10] += ruStatistics.FineRootNitrogen * areaFactor; // regen accumulatedValues[11] += ruStatistics.RegenerationCarbon; accumulatedValues[12] += ruStatistics.RegenerationNitrogen; // standing dead wood if (ru.Snags.TotalStanding != null) { accumulatedValues[13] += ru.Snags.TotalStanding.C; accumulatedValues[14] += ru.Snags.TotalStanding.N; } if (ru.Snags.TotalBranchesAndRoots != null) { accumulatedValues[15] += ru.Snags.TotalBranchesAndRoots.C; accumulatedValues[16] += ru.Snags.TotalBranchesAndRoots.N; } // biomass from soil (converstion to kg/ha), and scale with fraction of stockable area accumulatedValues[17] += 1000.0F * ru.Soil !.YoungRefractory.C * areaFactor; // 16.8.0 nullable analysis misses RU consistency check above accumulatedValues[18] += 1000.0F * ru.Soil.YoungRefractory.N * areaFactor; accumulatedValues[19] += 1000.0F * ru.Soil.YoungLabile.C * areaFactor; accumulatedValues[20] += 1000.0F * ru.Soil.YoungLabile.N * areaFactor; accumulatedValues[21] += 1000.0F * ru.Soil.OrganicMatter.C * areaFactor; accumulatedValues[22] += 1000.0F * ru.Soil.OrganicMatter.N * areaFactor; } // write landscape sums float totalStockableArea = accumulatedValues[0]; // convert to ha of stockable area insertRow.Parameters[0].Value = model.CurrentYear; insertRow.Parameters[1].Value = -1; insertRow.Parameters[2].Value = -1; // keys insertRow.Parameters[3].Value = accumulatedValues[0]; // stockable area [m2] for (int valueIndex = 1; valueIndex < accumulatedValues.Length; ++valueIndex) { insertRow.Parameters[3 + valueIndex].Value = accumulatedValues[valueIndex] / totalStockableArea; } insertRow.ExecuteNonQuery(); }