public TreeQuantiles(TestStand stand, PspStand pspStand, int measurementYear) : this() { float perTreeExpansionFactor = pspStand.GetTreesPerHectareExpansionFactor(); foreach (KeyValuePair <FiaCode, int[]> initialDbhQuantile in stand.InitialDbhQuantileBySpecies) { // accumulate stand state into quantiles int[] speciesQuantileCounts = new int[TestConstant.DbhQuantiles]; float[] speciesQuantileLiveExpansionFactor = new float[TestConstant.DbhQuantiles]; float[] speciesQuantileMaxDbh = new float[TestConstant.DbhQuantiles]; float[] speciesQuantileMeanDbh = new float[TestConstant.DbhQuantiles]; float[] speciesQuantileMinDbh = Enumerable.Repeat(Constant.CentimetersPerInch * TestConstant.Maximum.DiameterInInches, TestConstant.DbhQuantiles).ToArray(); Trees treesOfSpecies = stand.TreesBySpecies[initialDbhQuantile.Key]; for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { int quantile = initialDbhQuantile.Value[treeIndex]; int tag = treesOfSpecies.Tag[treeIndex]; PspTreeMeasurementSeries measurementSeries = pspStand.MeasurementsByTag[tag]; if (measurementSeries.DbhInCentimetersByYear.TryGetValue(measurementYear, out float dbh)) { speciesQuantileCounts[quantile] += 1; speciesQuantileLiveExpansionFactor[quantile] += perTreeExpansionFactor; speciesQuantileMaxDbh[quantile] = MathF.Max(speciesQuantileMaxDbh[quantile], dbh); speciesQuantileMeanDbh[quantile] += dbh; speciesQuantileMinDbh[quantile] = MathF.Min(speciesQuantileMinDbh[quantile], dbh); } } for (int quantile = 0; quantile < TestConstant.DbhQuantiles; ++quantile) { int quantileCount = speciesQuantileCounts[quantile]; if (quantileCount > 0) { speciesQuantileMeanDbh[quantile] = speciesQuantileMeanDbh[quantile] / (float)quantileCount; Debug.Assert(speciesQuantileMinDbh[quantile] / speciesQuantileMaxDbh[quantile] < 1.0001); Debug.Assert(speciesQuantileMinDbh[quantile] / speciesQuantileMeanDbh[quantile] < 1.0001); Debug.Assert(speciesQuantileMeanDbh[quantile] / speciesQuantileMaxDbh[quantile] < 1.0001); } } FiaCode species = initialDbhQuantile.Key; this.DeadExpansionFactorBySpecies.Add(species, new float[TestConstant.DbhQuantiles]); this.LiveExpansionFactorBySpecies.Add(species, speciesQuantileLiveExpansionFactor); this.MaxDbhInCmBySpecies.Add(species, speciesQuantileMaxDbh); this.MeanCrownRatioBySpecies.Add(species, new float[TestConstant.DbhQuantiles]); this.MeanDbhInCmBySpecies.Add(species, speciesQuantileMeanDbh); this.MeanHeightInMetersBySpecies.Add(species, new float[TestConstant.DbhQuantiles]); this.MinDbhInCmBySpecies.Add(species, speciesQuantileMinDbh); } }
public void SubmaxApi() { this.TestContext !.WriteLine("version, A1, A2"); foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); this.TestContext.WriteLine("{0},{1},{2}", variant, stand.A1, stand.A2); Assert.IsTrue(stand.A1 < 7.0F); Assert.IsTrue(stand.A1 > 5.0F); Assert.IsTrue(stand.A2 > 0.60F); Assert.IsTrue(stand.A2 < 0.65F); OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); } }
public void OrganonStandGrowthApi() { TestStand.WriteTreeHeader(this.TestContext !); foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); // check crown competition API TestStand stand = OrganonTest.CreateDefaultStand(configuration); float crownCompetitionFactor = OrganonStandDensity.GetCrownCompetitionByHeight(variant, stand)[0]; Assert.IsTrue(crownCompetitionFactor >= 0.0F); Assert.IsTrue(crownCompetitionFactor <= TestConstant.Maximum.CrownCompetitionFactor); OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth | ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); // recalculate heights and crown ratios for all trees Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { OrganonGrowth.SetIngrowthHeightAndCrownRatio(variant, stand, treesOfSpecies, treesOfSpecies.Count, calibrationBySpecies); } OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth | ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); // run Organon growth simulation stand = OrganonTest.CreateDefaultStand(configuration); if (configuration.IsEvenAge) { // stand error if less than one year to grow to breast height stand.AgeInYears = stand.BreastHeightAgeInYears + 2; } stand.SetQuantiles(); stand.WriteTreesAsCsv(this.TestContext !, variant, 0, false); TestStand initialStand = new TestStand(stand); TreeLifeAndDeath treeGrowth = new TreeLifeAndDeath(); for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { OrganonGrowth.Grow(simulationStep, configuration, stand, calibrationBySpecies); treeGrowth.AccumulateGrowthAndMortality(stand); OrganonTest.Verify(ExpectedTreeChanges.DiameterGrowth | ExpectedTreeChanges.HeightGrowth, OrganonWarnings.LessThan50TreeRecords, stand, variant); stand.WriteTreesAsCsv(this.TestContext !, variant, variant.GetEndYear(simulationStep), false); } OrganonTest.Verify(ExpectedTreeChanges.DiameterGrowth | ExpectedTreeChanges.HeightGrowth, treeGrowth, initialStand, stand); OrganonTest.Verify(calibrationBySpecies); } }
public void DiameterGrowthApi() { foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); Dictionary <FiaCode, float[]> previousTreeDiametersBySpecies = new Dictionary <FiaCode, float[]>(); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { previousTreeDiametersBySpecies.Add(treesOfSpecies.Species, new float[treesOfSpecies.Capacity]); } for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { OrganonStandDensity treeCompetition = new OrganonStandDensity(stand, variant); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { float[] previousTreeDiameters = previousTreeDiametersBySpecies[treesOfSpecies.Species]; OrganonGrowth.GrowDiameter(configuration, simulationStep, stand, treesOfSpecies, treeCompetition, calibrationBySpecies[treesOfSpecies.Species].Diameter); stand.SetSdiMax(configuration); for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { float dbhInInches = treesOfSpecies.Dbh[treeIndex]; float previousDbhInInches = previousTreeDiameters[treeIndex]; Assert.IsTrue(dbhInInches >= previousDbhInInches); Assert.IsTrue(dbhInInches <= TestConstant.Maximum.DiameterInInches); } } OrganonTest.Verify(ExpectedTreeChanges.DiameterGrowth, stand, variant); OrganonTest.Verify(calibrationBySpecies); } OrganonStandDensity densityForLookup = new OrganonStandDensity(stand, variant); for (float dbhInInches = 0.5F; dbhInInches <= 101.0F; ++dbhInInches) { float basalAreaLarger = densityForLookup.GetBasalAreaLarger(dbhInInches); Assert.IsTrue(basalAreaLarger >= 0.0F); Assert.IsTrue(basalAreaLarger <= densityForLookup.BasalAreaPerAcre); float crownCompetitionLarger = densityForLookup.GetCrownCompetitionFactorLarger(dbhInInches); Assert.IsTrue(crownCompetitionLarger >= 0.0F); Assert.IsTrue(crownCompetitionLarger <= densityForLookup.CrownCompetitionFactor); } } }
public void MortalityApi() { foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); OrganonStandDensity density = new OrganonStandDensity(stand, variant); for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { OrganonMortality.ReduceExpansionFactors(configuration, simulationStep, stand, density); stand.SetSdiMax(configuration); OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); float oldGrowthIndicator = OrganonMortality.GetOldGrowthIndicator(variant, stand); Assert.IsTrue(oldGrowthIndicator >= 0.0F); Assert.IsTrue(oldGrowthIndicator <= 2.0F); } } }
public void StatsApi() { // no test coverage: one line function // Stats.CON_RASI(); // no test coverage: one line function // Stats.RASITE(); foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); OrganonStandDensity standDensity = new OrganonStandDensity(stand, variant); this.TestContext !.WriteLine("{0},{1} ft²/ac,{2} trees per acre,{3} crown competition factor", variant, standDensity.BasalAreaPerAcre, standDensity.TreesPerAcre, standDensity.CrownCompetitionFactor); this.TestContext.WriteLine("index,large tree BA larger,large tree CCF larger"); for (int largeTreeCompetitionIndex = 0; largeTreeCompetitionIndex < standDensity.LargeTreeBasalAreaLarger.Length; ++largeTreeCompetitionIndex) { float largeTreeBasalAreaLarger = standDensity.LargeTreeBasalAreaLarger[largeTreeCompetitionIndex]; float largeTreeCrownCompetitionFactor = standDensity.LargeTreeCrownCompetition[largeTreeCompetitionIndex]; Assert.IsTrue(largeTreeBasalAreaLarger >= 0.0F); Assert.IsTrue(largeTreeBasalAreaLarger < TestConstant.Maximum.TreeBasalAreaLarger); Assert.IsTrue(largeTreeCrownCompetitionFactor >= 0.0F); Assert.IsTrue(largeTreeCrownCompetitionFactor < TestConstant.Maximum.StandCrownCompetitionFactor); this.TestContext.WriteLine("{0},{1}", largeTreeBasalAreaLarger, largeTreeCrownCompetitionFactor); } this.TestContext.WriteLine("index,small tree BA larger,large tree CCF larger"); for (int smallTreeCompetitionIndex = 0; smallTreeCompetitionIndex < standDensity.SmallTreeBasalAreaLarger.Length; ++smallTreeCompetitionIndex) { float smallTreeBasalAreaLarger = standDensity.SmallTreeBasalAreaLarger[smallTreeCompetitionIndex]; float smallTreeCrownCompetitionFactor = standDensity.SmallTreeCrownCompetition[smallTreeCompetitionIndex]; Assert.IsTrue(smallTreeBasalAreaLarger >= 0.0F); Assert.IsTrue(smallTreeBasalAreaLarger < TestConstant.Maximum.TreeBasalAreaLarger); Assert.IsTrue(smallTreeCrownCompetitionFactor >= 0.0F); Assert.IsTrue(smallTreeCrownCompetitionFactor < TestConstant.Maximum.StandCrownCompetitionFactor); this.TestContext.WriteLine("{0},{1}", smallTreeBasalAreaLarger, smallTreeCrownCompetitionFactor); } this.TestContext.WriteLine(String.Empty); OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); } }
protected static void GrowPspStand(PspStand huffmanPeak, TestStand stand, OrganonVariant variant, int startYear, int endYear, string baseFileName) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand initialTreeData = new TestStand(stand); TreeLifeAndDeath treeGrowth = new TreeLifeAndDeath(); Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); if (configuration.IsEvenAge) { // stand error if less than one year to grow to breast height stand.AgeInYears = stand.BreastHeightAgeInYears + 2; } TestStandDensity density = new TestStandDensity(stand, variant); using StreamWriter densityWriter = density.WriteToCsv(baseFileName + " density.csv", variant, startYear); TreeQuantiles quantiles = new TreeQuantiles(stand); using StreamWriter quantileWriter = quantiles.WriteToCsv(baseFileName + " quantiles.csv", variant, startYear); using StreamWriter treeGrowthWriter = stand.WriteTreesToCsv(baseFileName + " tree growth.csv", variant, startYear); for (int simulationStep = 0, year = startYear + variant.TimeStepInYears; year <= endYear; year += variant.TimeStepInYears, ++simulationStep) { OrganonGrowth.Grow(simulationStep, configuration, stand, calibrationBySpecies); treeGrowth.AccumulateGrowthAndMortality(stand); huffmanPeak.AddIngrowth(year, stand, density); OrganonTest.Verify(ExpectedTreeChanges.DiameterGrowthOrNoChange | ExpectedTreeChanges.HeightGrowthOrNoChange, stand, variant); density = new TestStandDensity(stand, variant); density.WriteToCsv(densityWriter, variant, year); quantiles = new TreeQuantiles(stand); quantiles.WriteToCsv(quantileWriter, variant, year); stand.WriteTreesToCsv(treeGrowthWriter, variant, year); } OrganonTest.Verify(ExpectedTreeChanges.ExpansionFactorConservedOrIncreased | ExpectedTreeChanges.DiameterGrowthOrNoChange | ExpectedTreeChanges.HeightGrowthOrNoChange, treeGrowth, initialTreeData, stand); OrganonTest.Verify(calibrationBySpecies); }
public void GrowApi() { foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); OrganonStandDensity densityStartOfStep = new OrganonStandDensity(stand, variant); for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { float[] crownCompetitionByHeight = OrganonStandDensity.GetCrownCompetitionByHeight(variant, stand); OrganonGrowth.Grow(simulationStep, configuration, stand, densityStartOfStep, calibrationBySpecies, ref crownCompetitionByHeight, out OrganonStandDensity densityEndOfStep, out int _); stand.SetSdiMax(configuration); OrganonTest.Verify(ExpectedTreeChanges.DiameterGrowth | ExpectedTreeChanges.HeightGrowth, stand, variant); OrganonTest.Verify(calibrationBySpecies); densityStartOfStep = densityEndOfStep; } } }
public void CrownGrowthApi() { foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = OrganonTest.CreateDefaultStand(configuration); Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { OrganonStandDensity densityStartOfStep = new OrganonStandDensity(stand, variant); Assert.IsTrue(densityStartOfStep.BasalAreaPerAcre > 0.0F); Assert.IsTrue(densityStartOfStep.CrownCompetitionFactor > 0.0F); Assert.IsTrue(densityStartOfStep.TreesPerAcre > 0.0F); float[] crownCompetitionByHeight = OrganonStandDensity.GetCrownCompetitionByHeight(variant, stand); OrganonTest.Verify(crownCompetitionByHeight, variant); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { variant.AddCrownCompetitionByHeight(treesOfSpecies, crownCompetitionByHeight); OrganonTest.Verify(crownCompetitionByHeight, variant); } OrganonStandDensity densityEndOfStep = new OrganonStandDensity(stand, variant); Assert.IsTrue(densityEndOfStep.BasalAreaPerAcre > 0.0F); Assert.IsTrue(densityEndOfStep.CrownCompetitionFactor > 0.0F); Assert.IsTrue(densityEndOfStep.TreesPerAcre > 0.0F); #pragma warning disable IDE0059 // Unnecessary assignment of a value crownCompetitionByHeight = OrganonGrowth.GrowCrown(variant, stand, densityEndOfStep, calibrationBySpecies); #pragma warning restore IDE0059 // Unnecessary assignment of a value OrganonTest.Verify(ExpectedTreeChanges.NoDiameterOrHeightGrowth, stand, variant); OrganonTest.Verify(calibrationBySpecies); } } }
public void RS39() { string plotFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "OSU", "Organon", "RS39 lower half.xlsx"); PspStand rs39 = new PspStand(plotFilePath, "RS39 lower half", 0.154441F); OrganonVariant variant = new OrganonVariantNwo(); OrganonConfiguration configuration = new OrganonConfiguration(variant); TestStand stand = rs39.ToStand(configuration, 105.0F); int startYear = 1992; stand.WriteCompetitionAsCsv("RS39 lower half initial competition.csv", variant, startYear); OrganonTest.GrowPspStand(rs39, stand, variant, startYear, 2019, Path.GetFileNameWithoutExtension(plotFilePath)); TreeQuantiles measuredQuantiles = new TreeQuantiles(stand, rs39, startYear); using StreamWriter quantileWriter = measuredQuantiles.WriteToCsv("RS39 lower half measured quantiles.csv", variant, startYear); foreach (int measurementYear in rs39.MeasurementYears) { if (measurementYear != startYear) { measuredQuantiles = new TreeQuantiles(stand, rs39, measurementYear); measuredQuantiles.WriteToCsv(quantileWriter, variant, measurementYear); } } }
public void HuffmanPeakNobleFir() { string plotFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "OSU", "Organon", "HPNF.xlsx"); PspStand huffmanPeak = new PspStand(plotFilePath, "HPNF", 0.2F); OrganonVariant variant = new OrganonVariantSwo(); // SWO allows mapping ABAM -> ABGR and ABPR -> ABCO OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); TestStand stand = huffmanPeak.ToStand(configuration, 80.0F); int startYear = 1980; stand.WriteCompetitionAsCsv("HPNF initial competition.csv", variant, startYear); OrganonTest.GrowPspStand(huffmanPeak, stand, variant, startYear, 2015, Path.GetFileNameWithoutExtension(plotFilePath)); TreeQuantiles measuredQuantiles = new TreeQuantiles(stand, huffmanPeak, startYear); using StreamWriter quantileWriter = measuredQuantiles.WriteToCsv("HPNF measured quantiles.csv", variant, startYear); foreach (int measurementYear in huffmanPeak.MeasurementYears) { if (measurementYear != startYear) { measuredQuantiles = new TreeQuantiles(stand, huffmanPeak, measurementYear); measuredQuantiles.WriteToCsv(quantileWriter, variant, measurementYear); } } }
protected static void Verify(ExpectedTreeChanges expectedGrowth, OrganonWarnings expectedWarnings, TestStand stand, OrganonVariant variant) { Assert.IsTrue(stand.AgeInYears >= 0); Assert.IsTrue(stand.AgeInYears <= TestConstant.Maximum.StandAgeInYears); Assert.IsTrue(stand.BreastHeightAgeInYears >= 0); Assert.IsTrue(stand.BreastHeightAgeInYears <= TestConstant.Maximum.StandAgeInYears); Assert.IsTrue(stand.NumberOfPlots >= 1); Assert.IsTrue(stand.NumberOfPlots <= 36); Assert.IsTrue(stand.TreesBySpecies.Count > 0); Assert.IsTrue(stand.GetTreeRecordCount() > 0); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { FiaCode species = treesOfSpecies.Species; Assert.IsTrue(Enum.IsDefined(typeof(FiaCode), species)); for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { // primary tree data float crownRatio = treesOfSpecies.CrownRatio[treeIndex]; Assert.IsTrue(crownRatio >= 0.0F); Assert.IsTrue(crownRatio <= 1.0F); float dbhInInches = treesOfSpecies.Dbh[treeIndex]; Assert.IsTrue(dbhInInches >= 0.0F); Assert.IsTrue(dbhInInches <= TestConstant.Maximum.DiameterInInches); float expansionFactor = treesOfSpecies.LiveExpansionFactor[treeIndex]; Assert.IsTrue(expansionFactor >= 0.0F); Assert.IsTrue(expansionFactor <= TestConstant.Maximum.ExpansionFactor); float heightInFeet = treesOfSpecies.Height[treeIndex]; Assert.IsTrue(heightInFeet >= 0.0F); Assert.IsTrue(heightInFeet <= TestConstant.Maximum.HeightInFeet); float deadExpansionFactor = treesOfSpecies.DeadExpansionFactor[treeIndex]; Assert.IsTrue(deadExpansionFactor >= 0.0F); Assert.IsTrue(deadExpansionFactor <= TestConstant.Maximum.ExpansionFactor); Assert.IsTrue(expansionFactor + deadExpansionFactor <= TestConstant.Maximum.ExpansionFactor); // diameter and height growth float diameterGrowthInInches = treesOfSpecies.DbhGrowth[treeIndex]; if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowth)) { Assert.IsTrue(diameterGrowthInInches > 0.0F, "{0}: {1} {2} did not grow in diameter.", variant.TreeModel, treesOfSpecies.Species, treeIndex); Assert.IsTrue(diameterGrowthInInches <= 0.1F * TestConstant.Maximum.DiameterInInches); } else if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowthOrNoChange)) { Assert.IsTrue(diameterGrowthInInches >= 0.0F); Assert.IsTrue(diameterGrowthInInches <= 0.1F * TestConstant.Maximum.DiameterInInches); } else { Assert.IsTrue(diameterGrowthInInches == 0.0F); } float heightGrowthInFeet = treesOfSpecies.HeightGrowth[treeIndex]; if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowth)) { Assert.IsTrue(heightGrowthInFeet > 0.0F, "{0}: {1} {2} did not grow in height.", variant.TreeModel, treesOfSpecies.Species, treeIndex); Assert.IsTrue(heightGrowthInFeet <= 0.1F * TestConstant.Maximum.HeightInFeet); } else if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowthOrNoChange)) { Assert.IsTrue(heightGrowthInFeet >= 0.0F, "{0}: {1} {2} decreased in height.", variant.TreeModel, treesOfSpecies.Species, treeIndex); Assert.IsTrue(heightGrowthInFeet <= 0.1F * TestConstant.Maximum.HeightInFeet); } else { Assert.IsTrue(heightGrowthInFeet == 0.0F); } // for now, ignore warnings on height exceeding potential height // Assert.IsTrue(stand.TreeWarnings[treeWarningIndex] == 0); } for (int treeIndex = treesOfSpecies.Count; treeIndex < treesOfSpecies.Capacity; ++treeIndex) { Assert.IsTrue(treesOfSpecies.CrownRatio[treeIndex] == 0.0F); Assert.IsTrue(treesOfSpecies.Dbh[treeIndex] == 0.0F); Assert.IsTrue(treesOfSpecies.DeadExpansionFactor[treeIndex] == 0.0F); Assert.IsTrue(treesOfSpecies.Height[treeIndex] == 0.0F); Assert.IsTrue(treesOfSpecies.LiveExpansionFactor[treeIndex] == 0.0F); } } Assert.IsTrue(stand.Warnings.BigSixHeightAbovePotential == false); Assert.IsTrue(stand.Warnings.LessThan50TreeRecords == expectedWarnings.HasFlag(OrganonWarnings.LessThan50TreeRecords)); Assert.IsTrue(stand.Warnings.HemlockSiteIndexOutOfRange == expectedWarnings.HasFlag(OrganonWarnings.HemlockSiteIndex)); Assert.IsTrue(stand.Warnings.OtherSpeciesBasalAreaTooHigh == false); Assert.IsTrue(stand.Warnings.SiteIndexOutOfRange == false); if (variant.TreeModel != TreeModel.OrganonSmc) { // for now, ignore SMC warning for breast height age < 10 Assert.IsTrue(stand.Warnings.TreesOld == false); } // for now, ignore stand.Warnings.TreesYoung }
protected static TestStand CreateDefaultStand(OrganonConfiguration configuration) { // TODO: cover cases with more than one SIMD width per species TestStand stand = new TestStand(configuration.Variant, 0, TestConstant.Default.SiteIndex) { PlantingDensityInTreesPerHectare = 939.0F // 380 trees per acre }; switch (configuration.Variant.TreeModel) { case TreeModel.OrganonNwo: case TreeModel.OrganonSmc: stand.Add(new TreeRecord(1, FiaCode.PseudotsugaMenziesii, 0.1F, 0.4F, 10.0F)); stand.Add(new TreeRecord(2, FiaCode.PseudotsugaMenziesii, 0.2F, 0.5F, 20.0F)); stand.Add(new TreeRecord(3, FiaCode.PseudotsugaMenziesii, 0.3F, 0.6F, 10.0F)); stand.Add(new TreeRecord(4, FiaCode.PseudotsugaMenziesii, 10.0F, 0.5F, 10.0F)); stand.Add(new TreeRecord(5, FiaCode.AbiesGrandis, 0.1F, 0.6F, 1.0F)); stand.Add(new TreeRecord(6, FiaCode.AbiesGrandis, 1.0F, 0.7F, 2.0F)); stand.Add(new TreeRecord(7, FiaCode.TsugaHeterophylla, 0.1F, 0.6F, 5.0F)); stand.Add(new TreeRecord(8, FiaCode.TsugaHeterophylla, 0.5F, 0.7F, 10.0F)); stand.Add(new TreeRecord(9, FiaCode.ThujaPlicata, 0.1F, 0.4F, 10.0F)); stand.Add(new TreeRecord(10, FiaCode.ThujaPlicata, 1.0F, 0.5F, 15.0F)); stand.Add(new TreeRecord(11, FiaCode.TaxusBrevifolia, 0.1F, 0.7F, 2.0F)); stand.Add(new TreeRecord(12, FiaCode.ArbutusMenziesii, 1.0F, 0.5F, 2.0F)); stand.Add(new TreeRecord(13, FiaCode.AcerMacrophyllum, 0.1F, 0.5F, 2.0F)); stand.Add(new TreeRecord(14, FiaCode.QuercusGarryana, 10.0F, 0.5F, 2.0F)); stand.Add(new TreeRecord(15, FiaCode.AlnusRubra, 0.1F, 0.5F, 2.0F)); stand.Add(new TreeRecord(16, FiaCode.CornusNuttallii, 0.1F, 0.5F, 2.0F)); stand.Add(new TreeRecord(17, FiaCode.Salix, 0.1F, 0.5F, 2.0F)); break; case TreeModel.OrganonRap: stand.Add(new TreeRecord(1, FiaCode.AlnusRubra, 0.1F, 0.3F, 30.0F)); stand.Add(new TreeRecord(2, FiaCode.AlnusRubra, 0.2F, 0.4F, 40.0F)); stand.Add(new TreeRecord(3, FiaCode.AlnusRubra, 0.3F, 0.5F, 30.0F)); stand.Add(new TreeRecord(4, FiaCode.PseudotsugaMenziesii, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(5, FiaCode.TsugaHeterophylla, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(6, FiaCode.ThujaPlicata, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(7, FiaCode.AcerMacrophyllum, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(8, FiaCode.CornusNuttallii, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(9, FiaCode.Salix, 0.1F, 0.5F, 1.0F)); break; case TreeModel.OrganonSwo: stand.Add(new TreeRecord(1, FiaCode.PseudotsugaMenziesii, 0.1F, 0.5F, 5.0F)); stand.Add(new TreeRecord(2, FiaCode.AbiesConcolor, 0.1F, 0.5F, 5.0F)); stand.Add(new TreeRecord(3, FiaCode.AbiesGrandis, 0.1F, 0.5F, 5.0F)); stand.Add(new TreeRecord(4, FiaCode.PinusPonderosa, 0.1F, 0.5F, 10.0F)); stand.Add(new TreeRecord(5, FiaCode.PinusLambertiana, 0.1F, 0.5F, 10.0F)); stand.Add(new TreeRecord(6, FiaCode.CalocedrusDecurrens, 0.1F, 0.5F, 10.0F)); stand.Add(new TreeRecord(7, FiaCode.TsugaHeterophylla, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(8, FiaCode.ThujaPlicata, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(9, FiaCode.TaxusBrevifolia, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(10, FiaCode.ArbutusMenziesii, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(11, FiaCode.ChrysolepisChrysophyllaVarChrysophylla, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(12, FiaCode.NotholithocarpusDensiflorus, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(13, FiaCode.QuercusChrysolepis, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(14, FiaCode.AcerMacrophyllum, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(15, FiaCode.QuercusGarryana, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(16, FiaCode.QuercusKelloggii, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(17, FiaCode.AlnusRubra, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(18, FiaCode.CornusNuttallii, 0.1F, 0.5F, 1.0F)); stand.Add(new TreeRecord(19, FiaCode.Salix, 0.1F, 0.5F, 1.0F)); break; default: throw OrganonVariant.CreateUnhandledModelException(configuration.Variant.TreeModel); } stand.SetRedAlderSiteIndexAndGrowthEffectiveAge(); stand.SetSdiMax(configuration); return(stand); }
protected static void Verify(ExpectedTreeChanges expectedGrowth, TreeLifeAndDeath treeGrowth, TestStand initialStand, TestStand finalStand) { foreach (Trees finalTreesOfSpecies in finalStand.TreesBySpecies.Values) { float[] diameterGrowthOfSpecies = treeGrowth.TotalDbhGrowthInInches[finalTreesOfSpecies.Species]; float[] deathOfSpecies = treeGrowth.TotalDeadExpansionFactor[finalTreesOfSpecies.Species]; float[] heightGrowthOfSpecies = treeGrowth.TotalHeightGrowthInFeet[finalTreesOfSpecies.Species]; Trees initialTreesOfSpecies = initialStand.TreesBySpecies[finalTreesOfSpecies.Species]; for (int treeIndex = 0; treeIndex < finalTreesOfSpecies.Count; ++treeIndex) { float totalDbhGrowth = diameterGrowthOfSpecies[treeIndex]; if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowth)) { Assert.IsTrue(totalDbhGrowth > 0.0F); Assert.IsTrue(totalDbhGrowth <= TestConstant.Maximum.DiameterInInches); } else if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowthOrNoChange)) { Assert.IsTrue(totalDbhGrowth >= 0.0F); Assert.IsTrue(totalDbhGrowth <= TestConstant.Maximum.DiameterInInches); } else { Assert.IsTrue(totalDbhGrowth == 0.0F); } float totalHeightGrowth = heightGrowthOfSpecies[treeIndex]; if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowth)) { Assert.IsTrue(totalHeightGrowth > 0.0F); Assert.IsTrue(totalHeightGrowth <= TestConstant.Maximum.HeightInFeet); } else if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowthOrNoChange)) { Assert.IsTrue(totalHeightGrowth >= 0.0F); Assert.IsTrue(totalHeightGrowth <= TestConstant.Maximum.HeightInFeet); } else { Assert.IsTrue(totalHeightGrowth == 0.0F); } float totalDeadExpansionFactor = deathOfSpecies[treeIndex]; Assert.IsTrue(totalDeadExpansionFactor >= 0.0F); Assert.IsTrue(totalDeadExpansionFactor <= TestConstant.Maximum.ExpansionFactor); float initialTotalExpansionFactor = initialTreesOfSpecies.LiveExpansionFactor[treeIndex] + initialTreesOfSpecies.DeadExpansionFactor[treeIndex]; float finalTotalExpansionFactor = finalTreesOfSpecies.LiveExpansionFactor[treeIndex] + totalDeadExpansionFactor; float expansionFactorRatio = finalTotalExpansionFactor / initialTotalExpansionFactor; Assert.IsTrue(expansionFactorRatio >= 0.999F); if (expectedGrowth.HasFlag(ExpectedTreeChanges.ExpansionFactorConservedOrIncreased)) { Assert.IsTrue(initialTotalExpansionFactor >= 0.0F); } else { Assert.IsTrue(initialTotalExpansionFactor > 0.0F); Assert.IsTrue(finalTotalExpansionFactor > 0.0F); Assert.IsTrue(expansionFactorRatio <= 1.001F); } Assert.IsTrue(finalTotalExpansionFactor <= TestConstant.Maximum.ExpansionFactor); } for (int treeIndex = finalTreesOfSpecies.Count; treeIndex < finalTreesOfSpecies.Capacity; ++treeIndex) { Assert.IsTrue(diameterGrowthOfSpecies[treeIndex] == 0.0F); Assert.IsTrue(deathOfSpecies[treeIndex] == 0.0F); Assert.IsTrue(heightGrowthOfSpecies[treeIndex] == 0.0F); Assert.IsTrue(initialTreesOfSpecies.DbhGrowth[treeIndex] == 0.0F); Assert.IsTrue(initialTreesOfSpecies.HeightGrowth[treeIndex] == 0.0F); Assert.IsTrue(finalTreesOfSpecies.DbhGrowth[treeIndex] == 0.0F); Assert.IsTrue(finalTreesOfSpecies.HeightGrowth[treeIndex] == 0.0F); } } }
public TestStand ToStand(OrganonConfiguration configuration, float siteIndex) { int firstPlotMeasurementYear = this.GetFirstMeasurementYear(); // populate Organon version of stand // Currently, PSP stands are assumed to have IsEvenAge = false, which causes Organon to require a stand age of // zero years be passed. TestStand stand = new TestStand(configuration.Variant, 0, siteIndex) { NumberOfPlots = this.plotCount }; foreach (KeyValuePair <FiaCode, int> speciesCount in this.CountTreesBySpecies()) { // skip any unsupported species as they should be remapped in following loops if (configuration.Variant.IsSpeciesSupported(speciesCount.Key) == false) { continue; } // metric PSP data is converted to English units for Organon below stand.TreesBySpecies.Add(speciesCount.Key, new Trees(speciesCount.Key, speciesCount.Value, Units.English)); } float fixedPlotExpansionFactor = this.GetTreesPerAcreExpansionFactor(); foreach (PspTreeMeasurementSeries tree in this.MeasurementsByTag.Values) { int firstTreeMeasurementYear = tree.GetFirstMeasurementYear(); Debug.Assert(firstTreeMeasurementYear >= firstPlotMeasurementYear); if (firstTreeMeasurementYear != firstPlotMeasurementYear) { // tree is ingrowth List <PspTreeMeasurementSeries> ingrowthForYear = this.IngrowthByYear.GetOrAdd(firstTreeMeasurementYear); ingrowthForYear.Add(tree); continue; } FiaCode species = PspStand.MaybeRemapToSupportedSpecies(tree.Species, configuration.Variant); Trees treesOfSpecies = stand.TreesBySpecies[species]; Debug.Assert(treesOfSpecies.Capacity > treesOfSpecies.Count); float dbhInInches = TestConstant.InchesPerCm * tree.DbhInCentimetersByYear[firstPlotMeasurementYear]; float heightInFeet = TreeRecord.EstimateHeightInFeet(species, dbhInInches); treesOfSpecies.Add(tree.Tag, dbhInInches, heightInFeet, TestConstant.Default.CrownRatio, fixedPlotExpansionFactor); } // estimate crown ratios OrganonStandDensity standDensity = new OrganonStandDensity(stand, configuration.Variant); Dictionary <FiaCode, int> indexBySpecies = new Dictionary <FiaCode, int>(); foreach (PspTreeMeasurementSeries tree in this.MeasurementsByTag.Values) { int firstTreeMeasurementYear = tree.GetFirstMeasurementYear(); if (firstTreeMeasurementYear != firstPlotMeasurementYear) { continue; } if (indexBySpecies.TryGetValue(tree.Species, out int treeIndex) == false) { treeIndex = 0; indexBySpecies.Add(tree.Species, treeIndex); } FiaCode species = PspStand.MaybeRemapToSupportedSpecies(tree.Species, configuration.Variant); Trees treesOfSpecies = stand.TreesBySpecies[species]; treesOfSpecies.CrownRatio[treeIndex] = tree.EstimateInitialCrownRatio(standDensity); indexBySpecies[tree.Species] = ++treeIndex; } // complete stand initialization stand.EnsureSiteIndicesSet(configuration.Variant); stand.SetQuantiles(); stand.SetRedAlderSiteIndexAndGrowthEffectiveAge(); stand.SetSdiMax(configuration); return(stand); }
public void HeightGrowthApi() { foreach (OrganonVariant variant in TestConstant.Variants) { OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(variant); Dictionary <FiaCode, SpeciesCalibration> calibrationBySpecies = configuration.CreateSpeciesCalibration(); TestStand stand = OrganonTest.CreateDefaultStand(configuration); float[] crownCompetitionByHeight = OrganonStandDensity.GetCrownCompetitionByHeight(variant, stand); DouglasFir.SiteConstants psmeSite = new DouglasFir.SiteConstants(stand.SiteIndex); WesternHemlock.SiteConstants tsheSite = new WesternHemlock.SiteConstants(stand.HemlockSiteIndex); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { variant.GetHeightPredictionCoefficients(treesOfSpecies.Species, out float B0, out float B1, out float B2); for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { // predicted heights float dbhInInches = treesOfSpecies.Dbh[treeIndex]; float heightInFeet = treesOfSpecies.Height[treeIndex]; float predictedHeightInFeet = 4.5F + MathV.Exp(B0 + B1 * MathV.Pow(dbhInInches, B2)); Assert.IsTrue(predictedHeightInFeet >= 0.0F); // TODO: make upper limit of height species specific Assert.IsTrue(predictedHeightInFeet < TestConstant.Maximum.HeightInFeet); // growth effective age and potential height growth bool verifyAgeAndHeight = false; float growthEffectiveAgeInYears = -1.0F; float potentialHeightGrowth = -1.0F; if ((variant.TreeModel == TreeModel.OrganonNwo) || (variant.TreeModel == TreeModel.OrganonSmc)) { if (treesOfSpecies.Species == FiaCode.TsugaHeterophylla) { growthEffectiveAgeInYears = WesternHemlock.GetFlewellingGrowthEffectiveAge(tsheSite, variant.TimeStepInYears, heightInFeet, out potentialHeightGrowth); } else { growthEffectiveAgeInYears = DouglasFir.GetBrucePsmeAbgrGrowthEffectiveAge(psmeSite, variant.TimeStepInYears, heightInFeet, out potentialHeightGrowth); } verifyAgeAndHeight = true; } else if (variant.TreeModel == TreeModel.OrganonSwo) { if ((treesOfSpecies.Species == FiaCode.PinusPonderosa) || (treesOfSpecies.Species == FiaCode.PseudotsugaMenziesii)) { DouglasFir.GetDouglasFirPonderosaHeightGrowth(treesOfSpecies.Species == FiaCode.PseudotsugaMenziesii, stand.SiteIndex, heightInFeet, out growthEffectiveAgeInYears, out potentialHeightGrowth); verifyAgeAndHeight = true; } } if (verifyAgeAndHeight) { Assert.IsTrue(growthEffectiveAgeInYears >= -2.0F); Assert.IsTrue(growthEffectiveAgeInYears <= 500.0F); Assert.IsTrue(potentialHeightGrowth >= 0.0F); Assert.IsTrue(potentialHeightGrowth < 20.0F); } } } for (int simulationStep = 0; simulationStep < TestConstant.Default.SimulationCyclesToRun; ++simulationStep) { foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { if (variant.IsBigSixSpecies(treesOfSpecies.Species)) { // TODO: why no height calibration in Organon API? OrganonGrowth.GrowHeightBigSixSpecies(configuration, simulationStep, stand, treesOfSpecies, 1.0F, crownCompetitionByHeight, out _); } else { OrganonGrowth.GrowHeightMinorSpecies(configuration, stand, treesOfSpecies, calibrationBySpecies[treesOfSpecies.Species].Height); } stand.SetSdiMax(configuration); for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { float heightInFeet = treesOfSpecies.Height[treeIndex]; // TODO: make upper limit of height species specific Assert.IsTrue(heightInFeet < TestConstant.Maximum.HeightInFeet); } } // since diameter growth is zero in this test any tree which is above its anticipated height for its current diameter // should have zero growth // This is expected behavior the height growth functions and, potentially, height growth limiting. OrganonTest.Verify(ExpectedTreeChanges.HeightGrowthOrNoChange, stand, variant); OrganonTest.Verify(calibrationBySpecies); } } }
public TreeQuantiles(TestStand stand) : this() { foreach (KeyValuePair <FiaCode, int[]> initialDbhQuantile in stand.InitialDbhQuantileBySpecies) { // accumulate stand state into quantiles Trees treesOfSpecies = stand.TreesBySpecies[initialDbhQuantile.Key]; int[] quantileCounts = new int[TestConstant.DbhQuantiles]; float[] quantileDeadExpansionFactor = new float[TestConstant.DbhQuantiles]; float[] quantileLiveExpansionFactor = new float[TestConstant.DbhQuantiles]; float[] quantileMaxDbh = new float[TestConstant.DbhQuantiles]; float[] quantileMeanCrownRatio = new float[TestConstant.DbhQuantiles]; float[] quantileMeanDbh = new float[TestConstant.DbhQuantiles]; float[] quantileMeanHeight = new float[TestConstant.DbhQuantiles]; float[] quantileMinDbh = Enumerable.Repeat(Constant.CentimetersPerInch * TestConstant.Maximum.DiameterInInches, TestConstant.DbhQuantiles).ToArray(); for (int treeIndex = 0; treeIndex < initialDbhQuantile.Value.Length; ++treeIndex) { int quantile = initialDbhQuantile.Value[treeIndex]; float liveExpansionFactor = treesOfSpecies.LiveExpansionFactor[treeIndex]; if (liveExpansionFactor > 0.0F) { quantileCounts[quantile] += 1; quantileDeadExpansionFactor[quantile] += treesOfSpecies.DeadExpansionFactor[treeIndex]; quantileLiveExpansionFactor[quantile] += liveExpansionFactor; quantileMaxDbh[quantile] = MathF.Max(quantileMaxDbh[quantile], treesOfSpecies.Dbh[treeIndex]); quantileMeanCrownRatio[quantile] += liveExpansionFactor * treesOfSpecies.CrownRatio[treeIndex]; quantileMeanDbh[quantile] += liveExpansionFactor * treesOfSpecies.Dbh[treeIndex]; quantileMeanHeight[quantile] += liveExpansionFactor * treesOfSpecies.Height[treeIndex]; quantileMinDbh[quantile] = MathF.Min(quantileMinDbh[quantile], treesOfSpecies.Dbh[treeIndex]); } } // take averages and convert from Organon's English units to metric for (int quantile = 0; quantile < TestConstant.DbhQuantiles; ++quantile) { int quantileCount = quantileCounts[quantile]; if (quantileCount > 0) { float liveExpansionFactor = quantileLiveExpansionFactor[quantile]; quantileDeadExpansionFactor[quantile] = TestConstant.AcresPerHectare * quantileDeadExpansionFactor[quantile]; quantileLiveExpansionFactor[quantile] = TestConstant.AcresPerHectare * liveExpansionFactor; quantileMaxDbh[quantile] = Constant.CentimetersPerInch * quantileMaxDbh[quantile]; quantileMeanCrownRatio[quantile] /= liveExpansionFactor; quantileMeanDbh[quantile] = Constant.CentimetersPerInch * quantileMeanDbh[quantile] / liveExpansionFactor; quantileMeanHeight[quantile] = Constant.MetersPerFoot * quantileMeanHeight[quantile] / liveExpansionFactor; quantileMinDbh[quantile] = Constant.CentimetersPerInch * quantileMinDbh[quantile]; Debug.Assert(quantileMinDbh[quantile] / quantileMaxDbh[quantile] < 1.0001); Debug.Assert(quantileMinDbh[quantile] / quantileMeanDbh[quantile] < 1.0001); Debug.Assert(quantileMeanDbh[quantile] / quantileMaxDbh[quantile] < 1.0001); } } FiaCode species = initialDbhQuantile.Key; this.DeadExpansionFactorBySpecies.Add(species, quantileDeadExpansionFactor); this.LiveExpansionFactorBySpecies.Add(species, quantileLiveExpansionFactor); this.MaxDbhInCmBySpecies.Add(species, quantileMaxDbh); this.MeanCrownRatioBySpecies.Add(species, quantileMeanCrownRatio); this.MeanDbhInCmBySpecies.Add(species, quantileMeanDbh); this.MeanHeightInMetersBySpecies.Add(species, quantileMeanHeight); this.MinDbhInCmBySpecies.Add(species, quantileMinDbh); } }
protected static void Verify(ExpectedTreeChanges expectedGrowth, TestStand stand, OrganonVariant variant) { OrganonTest.Verify(expectedGrowth, OrganonWarnings.None, stand, variant); }