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); }
public override void ReduceExpansionFactors(OrganonStand stand, OrganonStandDensity densityBeforeGrowth, Trees trees, float fertilizationExponent) { // SMC MORTALITY float B0; float B1; float B2; float B3; float B4; float B5; float siteIndex = stand.SiteIndex; switch (trees.Species) { // Hann, Marshall, and Hanus(2006) FRL Research Contribution 49 case FiaCode.PseudotsugaMenziesii: B0 = -3.12161659F; B1 = -0.44724396F; B2 = 0.0F; B3 = -2.48387172F; B4 = 0.01843137F; B5 = 0.01353918F; break; // Unpublished Equation on File at OSU Dept.Forest Resources case FiaCode.AbiesGrandis: B0 = -7.60159F; B1 = -0.200523F; B2 = 0.0F; B3 = 0.0F; B4 = 0.0441333F; B5 = 0.00063849F; break; // Hann, Marshall, Hanus(2003) FRL Research Contribution 40 case FiaCode.TsugaHeterophylla: case FiaCode.ThujaPlicata: B0 = -0.761609F; B1 = -0.529366F; B2 = 0.0F; B3 = -4.74019F; B4 = 0.0119587F; B5 = 0.00756365F; siteIndex = stand.HemlockSiteIndex; // BUGBUG: why does redcedar get hemlock site index only here? break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.TaxusBrevifolia: B0 = -4.072781265F; B1 = -0.176433475F; B2 = 0.0F; B3 = -1.729453975F; B4 = 0.0F; B5 = 0.012525642F; break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.ArbutusMenziesii: B0 = -6.089598985F; B1 = -0.245615070F; B2 = 0.0F; B3 = -3.208265570F; B4 = 0.033348079F; B5 = 0.013571319F; break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.AcerMacrophyllum: B0 = -2.976822456F; B1 = 0.0F; B2 = 0.0F; B3 = -6.223250962F; B4 = 0.0F; B5 = 0.0F; break; // Gould, Marshall, and Harrington(2008) West.J.Appl.For. 23: 26-33 case FiaCode.QuercusGarryana: B0 = -6.00031085F; B1 = -0.10490823F; B2 = 0.0F; B3 = -0.99541909F; B4 = 0.00912739F; B5 = 0.87115652F; break; // best guess case FiaCode.AlnusRubra: B0 = -2.0F; B1 = -0.5F; B2 = 0.015F; B3 = -3.0F; B4 = 0.015F; B5 = 0.01F; break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.CornusNuttallii: B0 = -3.020345211F; B1 = 0.0F; B2 = 0.0F; B3 = -8.467882343F; B4 = 0.013966388F; B5 = 0.009461545F; break; // buest guess case FiaCode.Salix: B0 = -1.386294361F; B1 = 0.0F; B2 = 0.0F; B3 = 0.0F; B4 = 0.0F; B5 = 0.0F; break; default: throw Trees.CreateUnhandledSpeciesException(trees.Species); } float[]? mortalityKforRedAlder = null; if (trees.Species == FiaCode.AlnusRubra) { mortalityKforRedAlder = new float[trees.Capacity]; } for (int treeIndex = 0; treeIndex < trees.Count; ++treeIndex) { if (trees.LiveExpansionFactor[treeIndex] <= 0.0F) { continue; } float dbhInInches = trees.Dbh[treeIndex]; float basalAreaLarger = densityBeforeGrowth.GetBasalAreaLarger(dbhInInches); if (trees.Species == FiaCode.AbiesGrandis) { basalAreaLarger /= dbhInInches; } else if (trees.Species == FiaCode.QuercusGarryana) { basalAreaLarger = MathV.Ln(basalAreaLarger + 5.0F); } float crownRatio = trees.CrownRatio[treeIndex]; float PMK = B0 + B1 * dbhInInches + B2 * dbhInInches * dbhInInches + B3 * crownRatio + B4 * siteIndex + B5 * basalAreaLarger + fertilizationExponent; if (trees.Species == FiaCode.AlnusRubra) { mortalityKforRedAlder ![treeIndex] = PMK;
public override void ReduceExpansionFactors(OrganonStand stand, OrganonStandDensity densityBeforeGrowth, Trees trees, float fertilizationExponent) { // RAP MORTALITY float B0; float B1; float B2; float B3; float B4; float B5; float POW = 0.2F; switch (trees.Species) { // RA Coefficients from Hann, Bluhm, and Hibbs New Red Alder Equation case FiaCode.AlnusRubra: B0 = -4.333150734F; B1 = -0.9856713799F; B2 = 0.0F; B3 = -2.583317081F; B4 = 0.0369852164F; B5 = 0.0394546978F; POW = 1.0F; break; // Hann, Marshall, and Hanus(2006) FRL Research Contribution 49 case FiaCode.PseudotsugaMenziesii: B0 = -3.12161659F; B1 = -0.44724396F; B2 = 0.0F; B3 = -2.48387172F; B4 = 0.01843137F; B5 = 0.01353918F; break; // Hann, Marshall, Hanus(2003) FRL Research Contribution 40 case FiaCode.TsugaHeterophylla: B0 = -0.761609F; B1 = -0.529366F; B2 = 0.0F; B3 = -4.74019F; B4 = 0.0119587F; B5 = 0.00756365F; break; // WH of Hann, Marshall, Hanus(2003) FRL Research Contribution 40 case FiaCode.ThujaPlicata: B0 = -0.761609F; B1 = -0.529366F; B2 = 0.0F; B3 = -4.74019F; B4 = 0.0119587F; B5 = 0.00756365F; break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.AcerMacrophyllum: B0 = -2.976822456F; B1 = 0.0F; B2 = 0.0F; B3 = -6.223250962F; B4 = 0.0F; B5 = 0.0F; break; // Hann and Hanus(2001) FRL Research Contribution 34 case FiaCode.CornusNuttallii: B0 = -3.020345211F; B1 = 0.0F; B2 = 0.0F; B3 = -8.467882343F; B4 = 0.013966388F; B5 = 0.009461545F; break; // best guess case FiaCode.Salix: B0 = -1.386294361F; B1 = 0.0F; B2 = 0.0F; B3 = 0.0F; B4 = 0.0F; B5 = 0.0F; break; default: throw Trees.CreateUnhandledSpeciesException(trees.Species); } // BUGBUG: Fortran code didn't use red alder site index for red alder and used hemlock site index for all conifers, not just hemlock and redcedar float siteIndex = stand.HemlockSiteIndex; // interpreted as Douglas-fir site index if (trees.Species == FiaCode.AlnusRubra) { siteIndex = stand.SiteIndex; } else if ((trees.Species == FiaCode.TsugaHeterophylla) || (trees.Species == FiaCode.ThujaPlicata)) { siteIndex = OrganonVariantNwo.ToHemlockSiteIndexStatic(siteIndex); // convert from Douglas-fir site index to actual hemlock site inde } for (int treeIndex = 0; treeIndex < trees.Count; ++treeIndex) { if (trees.LiveExpansionFactor[treeIndex] <= 0.0F) { continue; } float dbhInInches = trees.Dbh[treeIndex]; float basalAreaLarger = densityBeforeGrowth.GetBasalAreaLarger(dbhInInches); float crownRatio = trees.CrownRatio[treeIndex]; float PMK = B0 + B1 * dbhInInches + B2 * dbhInInches * dbhInInches + B3 * crownRatio + B4 * siteIndex + B5 * basalAreaLarger + fertilizationExponent; float XPM = 1.0F / (1.0F + MathV.Exp(-PMK)); float survivalProbability = POW == 1.0 ? 1.0F - XPM : MathV.Pow(1.0F - XPM, POW); // RAP is the only variant using unfertlized POW != 1 survivalProbability *= OrganonGrowth.GetCrownRatioAdjustment(crownRatio); Debug.Assert(survivalProbability >= 0.0F); Debug.Assert(survivalProbability <= 1.0F); float newLiveExpansionFactor = survivalProbability * trees.LiveExpansionFactor[treeIndex]; if (newLiveExpansionFactor < 0.00001F) { newLiveExpansionFactor = 0.0F; } float mortalityExpansionFactor = trees.LiveExpansionFactor[treeIndex] - newLiveExpansionFactor; trees.DeadExpansionFactor[treeIndex] = mortalityExpansionFactor; trees.LiveExpansionFactor[treeIndex] = newLiveExpansionFactor; } }
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 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); }
/// <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); }
public static void ReduceExpansionFactors(OrganonConfiguration configuration, int simulationStep, OrganonStand stand, OrganonStandDensity densityBeforeGrowth) { foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values) { FiaCode species = treesOfSpecies.Species; float fertilizationExponent = OrganonMortality.GetMortalityFertilizationAdjustment(species, configuration.Variant.TreeModel, simulationStep, configuration.Treatments); configuration.Variant.ReduceExpansionFactors(stand, densityBeforeGrowth, treesOfSpecies, fertilizationExponent); } }