public override float GetGrowthEffectiveAge(OrganonConfiguration configuration, OrganonStand stand, Trees trees, int treeIndex, out float potentialHeightGrowth) { float growthEffectiveAge; if (trees.Species == FiaCode.AlnusRubra) { // GROWTH EFFECTIVE AGE AND POTENTIAL HEIGHT GROWTH FROM WEISKITTEL, HANN, HIBBS, LAM, AND BLUHM (2009) RED ALDER TOP HEIGHT GROWTH float siteIndexFromGround = stand.SiteIndex + 4.5F; RedAlder.WHHLB_HG(siteIndexFromGround, configuration.PDEN, trees.Height[treeIndex], 1.0F, out growthEffectiveAge, out potentialHeightGrowth); } else if (trees.Species == FiaCode.TsugaHeterophylla) { // POTENTIAL HEIGHT GROWTH FROM FLEWELLING'S WESTERN HEMLOCK DOMINANT HEIGHT GROWTH // BUGBUG: why isn't redcedar also on this code path? float siteIndexFromGround = OrganonVariantNwo.ToHemlockSiteIndexStatic(stand.HemlockSiteIndex); // stand.HemlockSiteIndex is interpreted as PSME site index WesternHemlock.SiteConstants tsheSite = new WesternHemlock.SiteConstants(siteIndexFromGround); growthEffectiveAge = WesternHemlock.GetFlewellingGrowthEffectiveAge(tsheSite, this.TimeStepInYears, trees.Height[treeIndex], out potentialHeightGrowth); } else { // POTENTIAL HEIGHT GROWTH FROM BRUCE'S (1981) DOMINANT HEIGHT GROWTH FOR DOUGLAS-FIR AND GRAND FIR DouglasFir.SiteConstants psmeSite = new DouglasFir.SiteConstants(stand.HemlockSiteIndex); // stand.HemlockSiteIndex is interpreted as PSME site index growthEffectiveAge = DouglasFir.GetBrucePsmeAbgrGrowthEffectiveAge(psmeSite, this.TimeStepInYears, trees.Height[treeIndex], out potentialHeightGrowth); } return(growthEffectiveAge); }
public void WesternHemlockApi() { this.TestContext !.WriteLine("siteIndex, age, topHeight"); for (float siteIndexInMeters = 10.0F; siteIndexInMeters < 60.1F; siteIndexInMeters += 10.0F) { WesternHemlock.SiteConstants tsheSite = new WesternHemlock.SiteConstants(Constant.FeetPerMeter * siteIndexInMeters); float previousTopHeight = -1.0F; for (float ageInYears = 0.0F; ageInYears < 100.1F; ++ageInYears) { WesternHemlock.SITECV_F(tsheSite, ageInYears, out float topHeightInMeters); this.TestContext.WriteLine("{0},{1},{2}", siteIndexInMeters, ageInYears, topHeightInMeters); Assert.IsTrue(topHeightInMeters >= 0.0F); // could add check that SI at age 50 is close to specified value Assert.IsTrue(topHeightInMeters > previousTopHeight); Assert.IsTrue(topHeightInMeters < 100.0F); previousTopHeight = topHeightInMeters; } } }
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); } } }