public override int GrowHeightBigSix(OrganonConfiguration configuration, OrganonStand stand, Trees trees, float[] crownCompetitionByHeight) { // WEIGHTED CENTRAL PAI PROCEDURE PARAMETERS FOR RED ALDER float P1; float P2; float P3; float P4; float P5; float P6; float P7; float P8; switch (trees.Species) { // Hann, Bluhm, and Hibbs Red Alder Plantation Analysis case FiaCode.AlnusRubra: P1 = 0.809837005F; P2 = -0.0134163653F; P3 = -0.0609398629F; P4 = 0.5F; P5 = 1.0F; P6 = 2.0F; P7 = 0.1469442410F; P8 = 1.0476380753F; break; // Hann, Marshall, and Hanus(2006) FRL Research Contribution ?? case FiaCode.PseudotsugaMenziesii: P1 = 0.655258886F; P2 = -0.006322913F; P3 = -0.039409636F; P4 = 0.5F; P5 = 0.597617316F; P6 = 2.0F; P7 = 0.631643636F; P8 = 1.010018427F; break; // Johnson(2002) Willamette Industries Report case FiaCode.TsugaHeterophylla: P1 = 1.0F; P2 = -0.0384415F; P3 = -0.0144139F; P4 = 0.5F; P5 = 1.04409F; P6 = 2.0F; P7 = 0.0F; P8 = 1.03F; break; default: throw Trees.CreateUnhandledSpeciesException(trees.Species); } int oldTreeRecordCount = 0; for (int treeIndex = 0; treeIndex < trees.Count; ++treeIndex) { if (trees.LiveExpansionFactor[treeIndex] <= 0.0F) { trees.HeightGrowth[treeIndex] = 0.0F; continue; } float growthEffectiveAge = configuration.Variant.GetGrowthEffectiveAge(configuration, stand, trees, treeIndex, out float potentialHeightGrowth); float crownCompetitionIncrement = OrganonVariant.GetCrownCompetitionFactorByHeight(trees.Height[treeIndex], crownCompetitionByHeight); float crownRatio = trees.CrownRatio[treeIndex]; float FCR = -P5 *MathV.Pow(1.0F - crownRatio, P6) * MathV.Exp(P7 * MathF.Sqrt(crownCompetitionIncrement)); float B0 = P1 * MathV.Exp(P2 * crownCompetitionIncrement); float B1 = MathV.Exp(P3 * MathV.Pow(crownCompetitionIncrement, P4)); float MODIFER = P8 * (B0 + (B1 - B0) * MathV.Exp(FCR)); float CRADJ = OrganonGrowth.GetCrownRatioAdjustment(crownRatio); float heightGrowth = potentialHeightGrowth * MODIFER * CRADJ; Debug.Assert(heightGrowth > 0.0F); trees.HeightGrowth[treeIndex] = heightGrowth; if (growthEffectiveAge > configuration.Variant.OldTreeAgeThreshold) { ++oldTreeRecordCount; } } return(oldTreeRecordCount); }
public override int GrowHeightBigSix(OrganonConfiguration configuration, OrganonStand stand, Trees trees, float[] crownCompetitionByHeight) { float P1; float P2; float P3; float P4; float P5; float P6; float P7; float P8; switch (trees.Species) { // Ritchie and Hann(1990) FRL Research Paper 54 case FiaCode.AbiesGrandis: P1 = 1.0F; P2 = -0.0328142F; P3 = -0.0127851F; P4 = 1.0F; P5 = 6.19784F; P6 = 2.0F; P7 = 0.0F; P8 = 1.01F; break; case FiaCode.PseudotsugaMenziesii: P1 = 0.655258886F; P2 = -0.006322913F; P3 = -0.039409636F; P4 = 0.5F; P5 = 0.597617316F; P6 = 2.0F; P7 = 0.631643636F; P8 = 1.010018427F; break; case FiaCode.TsugaHeterophylla: P1 = 1.0F; P2 = -0.0384415F; P3 = -0.0144139F; P4 = 0.5F; P5 = 1.04409F; P6 = 2.0F; P7 = 0.0F; P8 = 1.03F; break; default: throw Trees.CreateUnhandledSpeciesException(trees.Species); } int oldTreeRecordCount = 0; for (int treeIndex = 0; treeIndex < trees.Count; ++treeIndex) { if (trees.LiveExpansionFactor[treeIndex] <= 0.0F) { trees.HeightGrowth[treeIndex] = 0.0F; continue; } float growthEffectiveAge = configuration.Variant.GetGrowthEffectiveAge(configuration, stand, trees, treeIndex, out float potentialHeightGrowth); float crownCompetitionIncrement = OrganonVariant.GetCrownCompetitionFactorByHeight(trees.Height[treeIndex], crownCompetitionByHeight); float crownRatio = trees.CrownRatio[treeIndex]; float FCR = -P5 *MathV.Pow(1.0F - crownRatio, P6) * MathV.Exp(P7 * MathF.Sqrt(crownCompetitionIncrement)); float B0 = P1 * MathV.Exp(P2 * crownCompetitionIncrement); float B1 = MathV.Exp(P3 * MathV.Pow(crownCompetitionIncrement, P4)); float MODIFER = P8 * (B0 + (B1 - B0) * MathF.Exp(FCR)); // changed from MathV due to FCR of -91 being observed float CRADJ = OrganonGrowth.GetCrownRatioAdjustment(crownRatio); float heightGrowth = potentialHeightGrowth * MODIFER * CRADJ; Debug.Assert(heightGrowth > 0.0F); trees.HeightGrowth[treeIndex] = heightGrowth; if (growthEffectiveAge > configuration.Variant.OldTreeAgeThreshold) { ++oldTreeRecordCount; } } return(oldTreeRecordCount); }
/// <summary> /// Computes old growth index? /// </summary> /// <param name="stand">Stand data.</param> /// <param name="incrementMultiplier">Zero or minus one, usually zero.</param> /// <param name="OG">Old growth indicator.</param> /// <remarks> /// Supports only to 99 inch DBH. /// </remarks> public static float GetOldGrowthIndicator(OrganonVariant variant, OrganonStand stand) { // TODO: move diameter class and stand density information into stand for simplified state management and reduced compute int diameterClasses = 100; float[] treesPerAcreByDiameterClass = new float[diameterClasses]; float[] weightedDbhByDiameterClass = new float[diameterClasses]; float[] weightedHeightByDiameterClass = new float[diameterClasses]; foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { if (variant.IsBigSixSpecies(treesOfSpecies.Species) == false) { continue; } for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex) { float dbhInInches = treesOfSpecies.Dbh[treeIndex]; int dbhIndex = (int)dbhInInches; if (dbhIndex >= treesPerAcreByDiameterClass.Length) { dbhIndex = treesPerAcreByDiameterClass.Length - 1; } float expansionFactor = treesOfSpecies.LiveExpansionFactor[treeIndex]; Debug.Assert(expansionFactor >= 0.0F); Debug.Assert(expansionFactor <= Constant.Maximum.ExpansionFactor); treesPerAcreByDiameterClass[dbhIndex] += expansionFactor; weightedDbhByDiameterClass[dbhIndex] += expansionFactor * dbhInInches; weightedHeightByDiameterClass[dbhIndex] += expansionFactor * treesOfSpecies.Height[treeIndex]; } } float largestFiveTpaWeightedHeight = 0.0F; float largestFiveTpaWeightedDbh = 0.0F; float largeTreeTpa = 0.0F; for (int dbhIndex = weightedHeightByDiameterClass.Length - 1; dbhIndex >= 0; --dbhIndex) { largestFiveTpaWeightedHeight += weightedHeightByDiameterClass[dbhIndex]; largestFiveTpaWeightedDbh += weightedDbhByDiameterClass[dbhIndex]; largeTreeTpa += treesPerAcreByDiameterClass[dbhIndex]; if (largeTreeTpa > 5.0F) { float TRDIFF = treesPerAcreByDiameterClass[dbhIndex] - (largeTreeTpa - 5.0F); largestFiveTpaWeightedHeight = largestFiveTpaWeightedHeight - weightedHeightByDiameterClass[dbhIndex] + ((weightedHeightByDiameterClass[dbhIndex] / treesPerAcreByDiameterClass[dbhIndex]) * TRDIFF); largestFiveTpaWeightedDbh = largestFiveTpaWeightedDbh - weightedDbhByDiameterClass[dbhIndex] + ((weightedDbhByDiameterClass[dbhIndex] / treesPerAcreByDiameterClass[dbhIndex]) * TRDIFF); largeTreeTpa = 5.0F; break; } } float oldGrowthIndicator = 0.0F; if (largeTreeTpa > 0.0F) { float HT5 = largestFiveTpaWeightedHeight / largeTreeTpa; float DBH5 = largestFiveTpaWeightedDbh / largeTreeTpa; oldGrowthIndicator = DBH5 * HT5 / 10000.0F; Debug.Assert(oldGrowthIndicator >= 0.0F); Debug.Assert(oldGrowthIndicator <= 1000.0F); } return(oldGrowthIndicator); }