public void AddIngrowth(int year, OrganonStand stand, OrganonStandDensity standDensity) { List <int> remainingIngrowthYears = this.IngrowthByYear.Keys.Where(key => key > this.yearOfMostRecentIngrowthAdded).ToList(); if ((remainingIngrowthYears.Count < 1) || (remainingIngrowthYears[0] > year)) { // no ingrowth in this simulation step return; } int ingrowthYear = remainingIngrowthYears[0]; Debug.Assert((remainingIngrowthYears.Count == 1) || (remainingIngrowthYears[1] > year)); // for now, assume only one ingrowth measurement per simulation timestep float fixedPlotExpansionFactor = this.GetTreesPerAcreExpansionFactor(); foreach (PspTreeMeasurementSeries tree in this.IngrowthByYear[ingrowthYear]) { Trees treesOfSpecies = stand.TreesBySpecies[tree.Species]; Debug.Assert(treesOfSpecies.Capacity > treesOfSpecies.Count); float dbhInInches = Constant.InchesPerCentimeter * tree.DbhInCentimetersByYear.Values[0]; float heightInFeet = TestConstant.FeetPerMeter * TreeRecord.EstimateHeightInMeters(tree.Species, dbhInInches); treesOfSpecies.Add(tree.Tag, dbhInInches, heightInFeet, tree.EstimateInitialCrownRatio(standDensity), fixedPlotExpansionFactor); } this.yearOfMostRecentIngrowthAdded = ingrowthYear; }
public float EstimateInitialCrownRatio(OrganonStandDensity density) { float initialDiameterInInches = this.GetInitialDiameter() / Constant.CentimetersPerInch; float crownCompetition = density.GetCrownCompetitionFactorLarger(initialDiameterInInches); float crownCompetitionMidpoint = this.Species switch { FiaCode.PseudotsugaMenziesii => 125.0F, FiaCode.ThujaPlicata => 250.0F, FiaCode.TsugaHeterophylla => 300.0F, _ => 200.0F }; return(TestConstant.Default.CrownRatio / (1.0F + MathF.Exp(0.015F * (crownCompetition - crownCompetitionMidpoint)))); }
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 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 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); } }
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 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 OrganonStand ToOrganonStand(OrganonConfiguration configuration, int ageInYears, float siteIndex, int maximumTreesInStand) { if (maximumTreesInStand < 1) { throw new ArgumentOutOfRangeException(nameof(maximumTreesInStand)); } // copy trees from plot to Organon stand with default crown ratios // For now, when the stand size is limited this just copies the first n trees encountered rather than subsampling the plot. // Can move this to a Trees.CopyFrom() and Trees.ChangeUnits() if needed. Stand plotAtAge = this.byAge[ageInYears]; int maximumTreesToCopy = Math.Min(plotAtAge.GetTreeRecordCount(), maximumTreesInStand); int treesCopied = 0; StringBuilder plotIDsAsString = new StringBuilder(); foreach (int plotID in this.plotIDs) { plotIDsAsString.Append(plotID.ToString(CultureInfo.InvariantCulture)); } OrganonStand stand = new OrganonStand(ageInYears, siteIndex) { Name = plotIDsAsString.ToString() }; foreach (Trees plotTreesOfSpecies in plotAtAge.TreesBySpecies.Values) { if (stand.TreesBySpecies.TryGetValue(plotTreesOfSpecies.Species, out Trees? standTreesOfSpecies) == false) { int minimumSize = Math.Min(maximumTreesToCopy - treesCopied, plotTreesOfSpecies.Count); standTreesOfSpecies = new Trees(plotTreesOfSpecies.Species, minimumSize, Units.English); stand.TreesBySpecies.Add(plotTreesOfSpecies.Species, standTreesOfSpecies); } for (int treeIndex = 0; treeIndex < plotTreesOfSpecies.Count; ++treeIndex) { int tag = plotTreesOfSpecies.Tag[treeIndex]; float dbhInInches = Constant.InchesPerCentimeter * plotTreesOfSpecies.Dbh[treeIndex]; float heightInFeet = Constant.FeetPerMeter * plotTreesOfSpecies.Height[treeIndex]; float liveExpansionFactor = Constant.HectaresPerAcre * plotTreesOfSpecies.LiveExpansionFactor[treeIndex]; if (Single.IsNaN(dbhInInches) || (dbhInInches <= 0.0F) || Single.IsNaN(heightInFeet) || (heightInFeet <= 0.0F)) { throw new NotSupportedException("Tree " + tag + " has a missing, zero, or negative height or diameter at age " + ageInYears + "."); } standTreesOfSpecies.Add(tag, dbhInInches, heightInFeet, defaultCrownRatio, liveExpansionFactor); if (++treesCopied >= maximumTreesToCopy) { break; // break inner for loop } } if (++treesCopied >= maximumTreesToCopy) { break; // break foreach } } // estimate crown ratio if (configuration.Variant.TreeModel == TreeModel.OrganonSwo) { // TODO: if needed, add support for old index for NWO and SMC Pacific madrone throw new NotImplementedException("Old tree index not computed."); } stand.EnsureSiteIndicesSet(configuration.Variant); stand.SetRedAlderSiteIndexAndGrowthEffectiveAge(); stand.SetSdiMax(configuration); float defaultOldIndex = 0.0F; OrganonStandDensity density = new OrganonStandDensity(stand, configuration.Variant); foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { // initialize crown ratio from Organon variant for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { float dbhInInches = treesOfSpecies.Dbh[treeIndex]; float heightInFeet = treesOfSpecies.Height[treeIndex]; float crownCompetitionFactorLarger = density.GetCrownCompetitionFactorLarger(dbhInInches); float heightToCrownBase = configuration.Variant.GetHeightToCrownBase(treesOfSpecies.Species, heightInFeet, dbhInInches, crownCompetitionFactorLarger, density.BasalAreaPerAcre, stand.SiteIndex, stand.HemlockSiteIndex, defaultOldIndex); float crownRatio = (heightInFeet - heightToCrownBase) / heightInFeet; Debug.Assert(crownRatio >= 0.0F); Debug.Assert(crownRatio <= 1.0F); treesOfSpecies.CrownRatio[treeIndex] = crownRatio; } // initialize crown ratio from FVS-PN dubbing // https://www.fs.fed.us/fmsc/ftp/fvs/docs/overviews/FVSpn_Overview.pdf, section 4.3.1 // https://sourceforge.net/p/open-fvs/code/HEAD/tree/trunk/pn/crown.f#l67 // for live > 1.0 inch DBH // estimated crown ratio = d0 + d1 * 100.0 * SDI / SDImax // PSME d0 = 5.666442, d1 = -0.025199 if ((stand.TreesBySpecies.Count != 1) || (treesOfSpecies.Species != FiaCode.PseudotsugaMenziesii)) { throw new NotImplementedException(); } // FVS-PN crown ratio dubbing for Douglas-fir // Resulted in 0.28% less volume than Organon NWO on Malcolm Knapp Nelder 1 at stand age 70. // float qmd = stand.GetQuadraticMeanDiameter(); // float reinekeSdi = density.TreesPerAcre * MathF.Pow(0.1F * qmd, 1.605F); // float reinekeSdiMax = MathF.Exp((stand.A1 - Constant.NaturalLogOf10) / stand.A2); // float meanCrownRatioFvs = 5.666442F - 0.025199F * 100.0F * reinekeSdi / reinekeSdiMax; // Debug.Assert(meanCrownRatioFvs >= 0.0F); // Debug.Assert(meanCrownRatioFvs <= 10.0F); // FVS uses a 0 to 10 range, so 10 = 100% crown ratio // float weibullA = 0.0F; // float weibullB = -0.012061F + 1.119712F * meanCrownRatioFvs; // float weibullC = 3.2126F; // int[] dbhOrder = treesOfSpecies.GetDbhSortOrder(); // for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) // { // float dbhFraction = (float)dbhOrder[treeIndex] / (float)treesOfSpecies.Count; // float fvsCrownRatio = weibullA + weibullB * MathV.Pow(-1.0F * MathV.Ln(1.0F - dbhFraction), 1.0F / weibullC); // Debug.Assert(fvsCrownRatio >= 0.0F); // Debug.Assert(fvsCrownRatio <= 10.0F); // treesOfSpecies.CrownRatio[treeIndex] = 0.1F * fvsCrownRatio; // } } // used for checking sensitivity to data order // Ordering not currently advantageous, so disabled for now. // foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) // { // treesOfSpecies.SortByDbh(); // } return(stand); }
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); }