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 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 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 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); }
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); }