示例#1
0
        public void WriteToCsv(StreamWriter writer, OrganonVariant variant, int year)
        {
            foreach (KeyValuePair <FiaCode, float[]> meanDbhInCmForSpecies in this.MeanDbhInCmBySpecies)
            {
                FiaCode species     = meanDbhInCmForSpecies.Key;
                string  speciesCode = species.ToFourLetterCode();
                // BUGBUG: Huffman Peak hack
                if (species == FiaCode.AbiesConcolor)
                {
                    speciesCode = FiaCode.AbiesProcera.ToFourLetterCode();
                }
                else if (species == FiaCode.AbiesGrandis)
                {
                    speciesCode = FiaCode.AbiesAmabalis.ToFourLetterCode();
                }
                float[] deadExpansionFactors = this.DeadExpansionFactorBySpecies[species];
                float[] liveExpansionFactors = this.LiveExpansionFactorBySpecies[species];
                float[] maxDbh          = this.MaxDbhInCmBySpecies[species];
                float[] meanCrownRatios = this.MeanCrownRatioBySpecies[species];
                float[] meanHeight      = this.MeanHeightInMetersBySpecies[species];
                float[] minDbh          = this.MinDbhInCmBySpecies[species];

                for (int quantile = 0; quantile < TestConstant.DbhQuantiles; ++quantile)
                {
                    writer.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}", variant.TreeModel, year, speciesCode, quantile,
                                     meanDbhInCmForSpecies.Value[quantile], meanHeight[quantile], liveExpansionFactors[quantile],
                                     deadExpansionFactors[quantile], meanCrownRatios[quantile], minDbh[quantile], maxDbh[quantile]);
                }
            }
        }
示例#2
0
        private static float GetMortalityFertilizationAdjustment(FiaCode species, TreeModel treeModel, int simulationStep, OrganonTreatments treatments)
        {
            // fertilization mortality effects currently supported only for non-RAP Douglas-fir
            if ((treatments.FertilizationsPerformed < 1) || (species != FiaCode.PseudotsugaMenziesii) || (treeModel == TreeModel.OrganonRap))
            {
                return(0.0F);
            }

            // non-RAP Douglas-fir
            // Hann 2003 Research Contribution 40, Table 37: Parameters for predicting fertlization response of 5-year mortality
            float c5  = 0.0000552859F;
            float PF2 = 1.5F;
            float PF3 = -0.5F;

            float XTIME  = Constant.DefaultTimeStepInYears * (float)simulationStep;
            float FERTX1 = 0.0F;

            for (int treatmentIndex = 1; treatmentIndex < 5; ++treatmentIndex)
            {
                // BUGBUG: summation range doesn't match 13 or 18 year periods given in Hann 2003 Table 3
                FERTX1 += treatments.PoundsOfNitrogenPerAcre[treatmentIndex] * MathV.Exp(PF3 / PF2 * (treatments.TimeStepsSinceFertilization[0] - treatments.TimeStepsSinceFertilization[treatmentIndex]));
            }
            float FERTADJ = c5 * MathV.Pow(treatments.PoundsOfNitrogenPerAcre[0] + FERTX1, PF2) * MathV.Exp(PF3 * (XTIME - treatments.TimeStepsSinceFertilization[0]));

            return(FERTADJ);
        }
示例#3
0
        protected override float GetHeightToLargestCrownWidth(FiaCode species, float HT, float CR)
        {
            float B1 = species switch
            {
                // Hann(1999) FS 45: 217-225
                FiaCode.PseudotsugaMenziesii => 0.062000F,
                // Hann and Hanus(2001) FRL Research Contribution 34
                FiaCode.AbiesGrandis => 0.028454F,
                // Hann and Hanus(2001) FRL Research Contribution 34
                FiaCode.TsugaHeterophylla or
                FiaCode.ThujaPlicata or
                FiaCode.TaxusBrevifolia => 0.209806F,
                // Hann and Hanus(2001) FRL Research Contribution 34
                FiaCode.ArbutusMenziesii or
                FiaCode.AcerMacrophyllum or
                FiaCode.QuercusGarryana or
                FiaCode.AlnusRubra or
                FiaCode.CornusNuttallii or
                FiaCode.Salix => 0.0F,
                _ => throw Trees.CreateUnhandledSpeciesException(species),
            };
            float CL   = CR * HT;
            float HLCW = HT - (1.0F - B1) * CL;

            return(HLCW);
        }
示例#4
0
        public override void GetHeightPredictionCoefficients(FiaCode species, out float B0, out float B1, out float B2)
        {
            switch (species)
            {
            // Hann, Bluhm, and Hibbs(2011) Forest Biometrics Research Paper 1
            case FiaCode.AlnusRubra:
                B0 = 6.75650139F;
                B1 = -4.6252377F;
                B2 = -0.23208200F;
                break;

            // Hanus, Marshall, and Hann(1999) FRL Research Contribution 25
            case FiaCode.PseudotsugaMenziesii:
                B0 = 7.262195456F;
                B1 = -5.899759104F;
                B2 = -0.287207389F;
                break;

            // Hanus, Marshall, and Hann(1999) FRL Research Contribution 25
            case FiaCode.TsugaHeterophylla:
                B0 = 6.555344622F;
                B1 = -5.137174162F;
                B2 = -0.364550800F;
                break;

            // Hann and Hanus(2002) OSU Department of Forest Management Internal Report #2
            case FiaCode.ThujaPlicata:
                B0 = 6.14817441F;
                B1 = -5.40092761F;
                B2 = -0.38922036F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.AcerMacrophyllum:
                B0 = 5.21462F;
                B1 = -2.70252F;
                B2 = -0.354756F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.CornusNuttallii:
                B0 = 4.49727F;
                B1 = -2.07667F;
                B2 = -0.388650F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.Salix:
                B0 = 4.88361F;
                B1 = -2.47605F;
                B2 = -0.309050F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
        }
示例#5
0
 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);
     }
 }
示例#6
0
 public TreeRecord(int tag, FiaCode species, float dbhInInches, float crownRatio, float expansionFactor)
 {
     this.CrownRatio          = crownRatio;
     this.DbhInInches         = dbhInInches;
     this.HeightInFeet        = TreeRecord.EstimateHeightInFeet(species, dbhInInches);
     this.LiveExpansionFactor = expansionFactor;
     this.Species             = species;
     this.Tag = tag;
 }
示例#7
0
        public static float EstimateHeightInMeters(FiaCode species, float dbhInInches)
        {
            // height-diameter equations from
            // Ishii H, Reynolds JH, Ford ED, Shaw DC. 2000. Height growth and vertical development of an old-growth
            //   Pseudotsuga-Tsuga forest in southwestern Washington State, U.S.A. Canadian Journal of Forest Resources
            //   30:17-24. http://faculty.washington.edu/joel/Papers/IshiiReynoldsetalCJFR2000.pdf
            //   Figure 2: ABAM, PSME, TABR, THPL, and TSHE at Wind River / TT Munger Experimental Forest
            // Fujimori T, Kawanabe S, Hideki S, et al. 1976. Biomass and primary production in forests of three major
            //   vegetation zones of the northwestern United States. Journal of the Japanese Forestry Society 58(10):360-373.
            //   http://andrewsforest.oregonstate.edu/publications/800
            //   Figure 6: ABPR Goat Marsh Research Natural Area
            //
            // also
            // Curtis RO. 2015. Development of Top Heights and Corresponding Diameters in High Elevation Noble Fir Plantations.
            //   Research Paper PNW-RP-603 Pacific Northwest Research Station USFS. https://www.fs.fed.us/pnw/pubs/pnw_rp603.pdf
            //   ABPR 50 year site index: 24 m @ n = 1
            // Franklin JF. ND. Abies procera. https://andrewsforest.oregonstate.edu/sites/default/files/lter/pubs/pdf/pub1168.pdf
            //   ABPR class II 100 year site index: 36 m => 48 cm DBH under Ishii 2000
            float dbhInCm   = Constant.CentimetersPerInch * dbhInInches;
            var   heightInM = species switch
            {
                FiaCode.AbiesAmabalis => 45.8F * (1.0F - MathF.Exp(-0.008F * MathF.Pow(dbhInCm, 1.36F))),
                FiaCode.AbiesProcera => dbhInCm / (0.6035F + 0.0095F * dbhInCm),
                FiaCode.PseudotsugaMenziesii => 60.1F * (1.0F - MathF.Exp(-0.007F * MathF.Pow(dbhInCm, 1.25F))),
                FiaCode.TaxusBrevifolia => 50.0F * (1.0F - MathF.Exp(-0.025F * MathF.Pow(dbhInCm, 0.71F))),
                FiaCode.ThujaPlicata => 68.5F * (1.0F - MathF.Exp(-0.009F * MathF.Pow(dbhInCm, 1.04F))),
                FiaCode.TsugaHeterophylla => 56.9F * (1.0F - MathF.Exp(-0.007F * MathF.Pow(dbhInCm, 1.29F))),
                // simple defaults for other conifers and willows
                FiaCode.AbiesConcolor or
                FiaCode.AbiesGrandis or
                FiaCode.CalocedrusDecurrens or
                FiaCode.NotholithocarpusDensiflorus or
                FiaCode.PinusLambertiana or
                FiaCode.PinusPonderosa or
                FiaCode.Salix => dbhInCm + 1.37F,
                // simple defaults for most hardwoods
                FiaCode.AcerMacrophyllum or
                FiaCode.AlnusRubra or
                FiaCode.ArbutusMenziesii or
                FiaCode.ChrysolepisChrysophyllaVarChrysophylla or
                FiaCode.CornusNuttallii or
                FiaCode.QuercusChrysolepis or
                FiaCode.QuercusGarryana or
                FiaCode.QuercusKelloggii => 0.8F * dbhInCm + 1.37F,
                _ => throw Trees.CreateUnhandledSpeciesException(species),
            };

            ;
            if (heightInM < 1.372F)
            {
                // regression equations above may be inaccurate on small trees, resulting in heights below Organon 2.2.4's 4.5 foot minimum
                // For now, and for simplicity, force these trees to satisfy legacy Organon height requirements.
                heightInM = 1.372F;
            }
            return(heightInM);
        }
示例#8
0
        public TreeQuantiles(TestStand stand, PspStand pspStand, int measurementYear)
            : this()
        {
            float perTreeExpansionFactor = pspStand.GetTreesPerHectareExpansionFactor();

            foreach (KeyValuePair <FiaCode, int[]> initialDbhQuantile in stand.InitialDbhQuantileBySpecies)
            {
                // accumulate stand state into quantiles
                int[]   speciesQuantileCounts = new int[TestConstant.DbhQuantiles];
                float[] speciesQuantileLiveExpansionFactor = new float[TestConstant.DbhQuantiles];
                float[] speciesQuantileMaxDbh  = new float[TestConstant.DbhQuantiles];
                float[] speciesQuantileMeanDbh = new float[TestConstant.DbhQuantiles];
                float[] speciesQuantileMinDbh  = Enumerable.Repeat(Constant.CentimetersPerInch * TestConstant.Maximum.DiameterInInches, TestConstant.DbhQuantiles).ToArray();

                Trees treesOfSpecies = stand.TreesBySpecies[initialDbhQuantile.Key];
                for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex)
                {
                    int quantile = initialDbhQuantile.Value[treeIndex];
                    int tag      = treesOfSpecies.Tag[treeIndex];
                    PspTreeMeasurementSeries measurementSeries = pspStand.MeasurementsByTag[tag];
                    if (measurementSeries.DbhInCentimetersByYear.TryGetValue(measurementYear, out float dbh))
                    {
                        speciesQuantileCounts[quantile] += 1;
                        speciesQuantileLiveExpansionFactor[quantile] += perTreeExpansionFactor;
                        speciesQuantileMaxDbh[quantile]   = MathF.Max(speciesQuantileMaxDbh[quantile], dbh);
                        speciesQuantileMeanDbh[quantile] += dbh;
                        speciesQuantileMinDbh[quantile]   = MathF.Min(speciesQuantileMinDbh[quantile], dbh);
                    }
                }

                for (int quantile = 0; quantile < TestConstant.DbhQuantiles; ++quantile)
                {
                    int quantileCount = speciesQuantileCounts[quantile];
                    if (quantileCount > 0)
                    {
                        speciesQuantileMeanDbh[quantile] = speciesQuantileMeanDbh[quantile] / (float)quantileCount;

                        Debug.Assert(speciesQuantileMinDbh[quantile] / speciesQuantileMaxDbh[quantile] < 1.0001);
                        Debug.Assert(speciesQuantileMinDbh[quantile] / speciesQuantileMeanDbh[quantile] < 1.0001);
                        Debug.Assert(speciesQuantileMeanDbh[quantile] / speciesQuantileMaxDbh[quantile] < 1.0001);
                    }
                }

                FiaCode species = initialDbhQuantile.Key;
                this.DeadExpansionFactorBySpecies.Add(species, new float[TestConstant.DbhQuantiles]);
                this.LiveExpansionFactorBySpecies.Add(species, speciesQuantileLiveExpansionFactor);
                this.MaxDbhInCmBySpecies.Add(species, speciesQuantileMaxDbh);
                this.MeanCrownRatioBySpecies.Add(species, new float[TestConstant.DbhQuantiles]);
                this.MeanDbhInCmBySpecies.Add(species, speciesQuantileMeanDbh);
                this.MeanHeightInMetersBySpecies.Add(species, new float[TestConstant.DbhQuantiles]);
                this.MinDbhInCmBySpecies.Add(species, speciesQuantileMinDbh);
            }
        }
示例#9
0
文件: PspStand.cs 项目: OSU-MARS/SEEM
        private static FiaCode MaybeRemapToSupportedSpecies(FiaCode species, OrganonVariant variant)
        {
            if (variant.IsSpeciesSupported(species))
            {
                return(species);
            }

            if (species == FiaCode.ChrysolepisChrysophyllaVarChrysophylla)
            {
                return(FiaCode.CornusNuttallii);
            }
            else
            {
                throw Trees.CreateUnhandledSpeciesException(species);
            }
        }
示例#10
0
        protected override float GetHeightToLargestCrownWidth(FiaCode species, float HT, float CR)
        {
            // DISTANCE ABOVE CROWN BASE TO LARGEST CROWN WIDTH
            float B1;
            float B2;

            switch (species)
            {
            // Hann, Bluhm, and Hibbs Red Alder Plantation Analysis
            case FiaCode.AlnusRubra:
                B1 = 0.63619616F;
                B2 = -1.2180562F;
                break;

            // Hann(1999) FS 45: 217-225
            case FiaCode.PseudotsugaMenziesii:
                B1 = 0.062000F;
                B2 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.TsugaHeterophylla:
            case FiaCode.ThujaPlicata:
                B1 = 0.209806F;
                B2 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.AcerMacrophyllum:
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B1 = 0.0F;
                B2 = 0.0F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float CL   = CR * HT;
            float HLCW = HT - (1.0F - B1 * MathV.Exp(MathF.Pow(B2 * (1.0F - HT / 140.0F), 3))) * CL;

            return(HLCW);
        }
示例#11
0
文件: PspStand.cs 项目: OSU-MARS/SEEM
        private void ParseRow(int rowIndex, string[] rowAsStrings)
        {
            if ((rowIndex == 0) || (rowAsStrings[Constant.Psp.ColumnIndex.Tag] == null))
            {
                return;
            }

            int plot = Int32.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Plot]);

            this.plotCount = Math.Max(this.plotCount, plot);

            int tag = Int32.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Tag]);

            if (this.MeasurementsByTag.TryGetValue(tag, out PspTreeMeasurementSeries? tree) == false)
            {
                FiaCode species = FiaCodeExtensions.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Species]);
                if (species == FiaCode.Alnus)
                {
                    // remap Alnus viridis ssp sinuata to Alnus rubra as no Organon variant has support
                    species = FiaCode.AlnusRubra;
                }
                tree = new PspTreeMeasurementSeries(tag, species);
                this.MeasurementsByTag.Add(tag, tree);
            }

            int status = Int32.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Status]);
            int year   = Int32.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Year]);

            if (status < Constant.Psp.TreeStatus.Dead) // dead or not found trees lack diameter measurements
            {
                float dbhInCentimeters = float.Parse(rowAsStrings[Constant.Psp.ColumnIndex.Dbh]);
                Debug.Assert(dbhInCentimeters >= 5.0F);
                if (tree.DbhInCentimetersByYear.TryAdd(year, dbhInCentimeters) == false)
                {
                    // in case of a conflict, use whichever DBH comes last for consistency with the code above.
                    // For example, tree 8824 in RS39 has two 2013 records.
                    tree.DbhInCentimetersByYear[year] = dbhInCentimeters;
                }
            }

            this.MeasurementYears.Add(year);
        }
示例#12
0
        protected override float GetLargestCrownWidth(FiaCode species, float MCW, float CR, float DBH, float HT)
        {
            float B1;
            float B2;
            float B3;

            switch (species)
            {
            // Hann(1997) FRL Research Contribution 17
            case FiaCode.PseudotsugaMenziesii:
                B1 = 0.0F;
                B2 = 0.00436324F;
                B3 = 0.6020020F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.AbiesGrandis:
                B1 = 0.0F;
                B2 = 0.00308402F;
                B3 = 0.0F;
                break;

            // Hann(1997) FRL Research Contribution 17
            // BUGBUG: all coefficients are zero
            case FiaCode.TsugaHeterophylla:
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // IC of Hann(1997) FRL Research Contribution 17
            case FiaCode.ThujaPlicata:
                B1 = -0.2513890F;
                B2 = 0.006925120F;
                B3 = 0.985922F;
                break;

            // WH of Hann(1997) FRL Research Contribution 17
            // BUGBUG: all coefficients are zero
            case FiaCode.TaxusBrevifolia:
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.ArbutusMenziesii:
                B1 = 0.118621F;
                B2 = 0.00384872F;
                B3 = 0.0F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.AcerMacrophyllum:
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 1.470180F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.QuercusGarryana:
                B1 = 0.3648110F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.AlnusRubra:
                B1 = 0.3227140F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // GC of Hann(1997) FRL Research Contribution 17
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 1.61440F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float CL  = CR * HT;
            float LCW = MCW * MathV.Pow(CR, B1 + B2 * CL + B3 * (DBH / HT));

            return(LCW);
        }
示例#13
0
 public PspTreeMeasurementSeries(int tag, FiaCode species)
 {
     this.DbhInCentimetersByYear = new SortedList <int, float>(Constant.Psp.DefaultNumberOfStandMeasurements);
     this.Species = species;
     this.Tag     = tag;
 }
示例#14
0
        // OG only used for madrone
        public override float GetHeightToCrownBase(FiaCode species, float HT, float DBH, float CCFL, float BA, float siteIndex, float hemlockSiteIndex, float OG)
        {
            float B0;
            float B1;
            float B2;
            float B3;
            float B4;
            float B5;
            float B6 = 0.0F;

            switch (species)
            {
            // Hann and Hanus (2004) FS 34: 1193-2003
            case FiaCode.PseudotsugaMenziesii:
                B0 = 6.18464679F;
                B1 = -0.00328764F;
                B2 = -0.00136555F;
                B3 = -1.19702220F;
                B4 = 3.17028263F;
                B5 = 0.0F;
                break;

            // Zumrawi and Hann (1989) FRL Research Paper 52
            case FiaCode.AbiesGrandis:
                B0 = 1.04746F;
                B1 = -0.0066643F;
                B2 = -0.0067129F;
                B3 = 0.0F;
                B4 = 0.0F;
                B5 = 0.0F;
                break;

            // Johnson (2002) Willamette Industries Report
            case FiaCode.TsugaHeterophylla:
                B0 = 1.92682F;
                B1 = -0.00280478F;
                B2 = -0.0011939F;
                B3 = -0.513134F;
                B4 = 3.68901F;
                B5 = 0.00742219F;
                break;

            // Hann and Hanus(2002) OSU Department of Forest Management Internal Report #2
            case FiaCode.ThujaPlicata:
                B0 = 4.49102006F;
                B1 = 0.0F;
                B2 = -0.00132412F;
                B3 = -1.01460531F;
                B4 = 0.0F;
                B5 = 0.01340624F;
                break;

            // Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.TaxusBrevifolia:
                B0 = 0.0F;
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 0.0F;
                B4 = 2.030940382F;
                B5 = 0.0F;
                break;

            // Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.ArbutusMenziesii:
                B0 = 2.955339267F;
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = -0.798610738F;
                B4 = 3.095269471F;
                B5 = 0.0F;
                B6 = 0.700465646F;
                break;

            // BL Coefficients from Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.AcerMacrophyllum:
                B0 = 0.9411395642F;
                B1 = -0.00768402F;
                B2 = -0.005476131F;
                B3 = 0.0F;
                B4 = 0.0F;
                B5 = 0.0F;
                break;

            // Gould, Marshall, and Harrington (2008) West.J.Appl.For. 23: 26-33
            case FiaCode.QuercusGarryana:
                B0 = 1.05786632F;
                B1 = 0.0F;
                B2 = -0.00183283F;
                B3 = -0.28644547F;
                B4 = 0.0F;
                B5 = 0.0F;
                break;

            // Hann and Hanus (2002) OSU Department of Forest Management Internal Report #1
            case FiaCode.AlnusRubra:
                B0 = 0.56713781F;
                B1 = -0.010377976F;
                B2 = -0.002066036F;
                B3 = 0.0F;
                B4 = 1.39796223F;
                B5 = 0.0F;
                B6 = 0.0F;
                break;

            // Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B0 = 0.0F;
                B1 = 0.0F;
                B2 = -0.005666559F;
                B3 = -0.745540494F;
                B4 = 0.0F;
                B5 = 0.038476613F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }

            float HCB;

            if (species == FiaCode.TsugaHeterophylla)
            {
                // HCB = HT / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * SI_2 + B6 * OG * OG));
                HCB = HT / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * hemlockSiteIndex));
            }
            else
            {
                HCB = HT / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * siteIndex + B6 * OG * OG));
            }
            Debug.Assert(HCB >= 0.0F);
            Debug.Assert(HCB <= HT);
            return(HCB);
        }
示例#15
0
        protected override float GetCrownWidth(FiaCode species, float HLCW, float largestCrownWidth, float HT, float DBH, float XL)
        {
            float B1;
            float B2;
            float B3;

            switch (species)
            {
            // Hann(1999) FS 45: 217-225
            case FiaCode.PseudotsugaMenziesii:
                B1 = 0.929973F;
                B2 = -0.135212F;
                B3 = -0.0157579F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.AbiesGrandis:
                B1 = 0.999291F;
                B2 = 0.0F;
                B3 = -0.0314603F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.TsugaHeterophylla:
            case FiaCode.ThujaPlicata:
            case FiaCode.TaxusBrevifolia:
                B1 = 0.629785F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.ArbutusMenziesii:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.AcerMacrophyllum:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.QuercusGarryana:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.AlnusRubra:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.CornusNuttallii:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.Salix:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float RP    = (HT - XL) / (HT - HLCW);
            float RATIO = HT / DBH;

            if (species == FiaCode.PseudotsugaMenziesii)
            {
                if (RATIO > 50.0F)
                {
                    RATIO = 50.0F;
                }
            }
            else if (species == FiaCode.AbiesGrandis)
            {
                if (RATIO > 31.0)
                {
                    RATIO = 31.0F;
                }
            }

            float crownWidthMultiplier = MathV.Pow(RP, B1 + B2 * MathF.Sqrt(RP) + B3 * RATIO);

            Debug.Assert(crownWidthMultiplier >= 0.0F);
            Debug.Assert(crownWidthMultiplier <= 1.0F);

            float crownWidth = largestCrownWidth * crownWidthMultiplier;

            return(crownWidth);
        }
示例#16
0
        public override void GetHeightPredictionCoefficients(FiaCode species, out float B0, out float B1, out float B2)
        {
            switch (species)
            {
            // Hanus, Marshall, and Hann(1999) FRL Research Contribution 25
            case FiaCode.PseudotsugaMenziesii:
                B0 = 7.262195456F;
                B1 = -5.899759104F;
                B2 = -0.287207389F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.AbiesGrandis:
                B0 = 7.42808F;
                B1 = -5.80832F;
                B2 = -0.240317F;
                break;

            // Hanus, Marshall, and Hann(1999) FRL Research Contribution 25
            case FiaCode.TsugaHeterophylla:
                B0 = 6.555344622F;
                B1 = -5.137174162F;
                B2 = -0.364550800F;
                break;

            // Hann and Hanus(2002) OSU Department of Forest Management Internal Report #2
            case FiaCode.ThujaPlicata:
                B0 = 6.14817441F;
                B1 = -5.40092761F;
                B2 = -0.38922036F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.TaxusBrevifolia:
                B0 = 9.30172F;
                B1 = -7.50951F;
                B2 = -0.100000F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.ArbutusMenziesii:
                B0 = 5.84487F;
                B1 = -3.84795F;
                B2 = -0.289213F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.AcerMacrophyllum:
                B0 = 5.21462F;
                B1 = -2.70252F;
                B2 = -0.354756F;
                break;

            // Gould, Marshall, and Harrington(2008) West.J.Appl.For. 23: 26-33
            case FiaCode.QuercusGarryana:
                B0 = 4.69753118F;
                B1 = -3.51586969F;
                B2 = -0.57665068F;
                break;

            // Hann and Hanus(2002) OSU Department of Forest Management Internal Report #1
            case FiaCode.AlnusRubra:
                B0 = 5.59759126F;
                B1 = -3.19942952F;
                B2 = -0.38783403F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.CornusNuttallii:
                B0 = 4.49727F;
                B1 = -2.07667F;
                B2 = -0.388650F;
                break;

            // Wang and Hann(1988) FRL Research Paper 51
            case FiaCode.Salix:
                B0 = 4.88361F;
                B1 = -2.47605F;
                B2 = -0.309050F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
        }
示例#17
0
        private void ParseRow(int rowIndex, string[] rowAsStrings)
        {
            if (rowIndex == 0)
            {
                // parse header
                for (int columnIndex = 0; columnIndex < rowAsStrings.Length; ++columnIndex)
                {
                    string columnHeader = rowAsStrings[columnIndex];
                    if (String.IsNullOrWhiteSpace(columnHeader))
                    {
                        break;
                    }
                    if (columnHeader.Equals("species", StringComparison.OrdinalIgnoreCase))
                    {
                        this.speciesColumnIndex = columnIndex;
                    }
                    else if (columnHeader.Equals("plot", StringComparison.OrdinalIgnoreCase))
                    {
                        this.plotColumnIndex = columnIndex;
                    }
                    else if (columnHeader.Equals("tree", StringComparison.OrdinalIgnoreCase))
                    {
                        this.treeColumnIndex = columnIndex;
                    }
                    else if (columnHeader.Equals("age", StringComparison.OrdinalIgnoreCase))
                    {
                        this.ageColumnIndex = columnIndex;
                    }
                    else if (columnHeader.StartsWith("dbh", StringComparison.OrdinalIgnoreCase))
                    {
                        this.dbhColumnIndex = columnIndex;
                        if (columnHeader.EndsWith("mm", StringComparison.Ordinal))
                        {
                            this.dbhScaleFactor = 0.1F; // otherwise, assume cm
                        }
                    }
                    else if (columnHeader.Equals("height", StringComparison.OrdinalIgnoreCase) ||
                             columnHeader.Equals("height, m", StringComparison.OrdinalIgnoreCase))
                    {
                        this.heightColumnIndex = columnIndex;
                    }
                    else if (columnHeader.Equals("height, dm", StringComparison.OrdinalIgnoreCase))
                    {
                        this.heightColumnIndex = columnIndex;
                        this.heightScaleFactor = 0.1F; // otherwise, assume m
                    }
                    else if (columnHeader.StartsWith("expansion factor", StringComparison.OrdinalIgnoreCase))
                    {
                        this.expansionFactorColumnIndex = columnIndex;
                    }
                    else if (columnHeader.Equals("treecond", StringComparison.OrdinalIgnoreCase))
                    {
                        this.treeConditionColumnIndex = columnIndex;
                    }
                    else
                    {
                        // ignore column for now
                    }
                }

                // check header
                if (this.speciesColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.speciesColumnIndex), "Species column not found.");
                }
                if (this.plotColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.plotColumnIndex), "Plot column not found.");
                }
                if (this.treeColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.treeColumnIndex), "Tree number column not found.");
                }
                if (this.ageColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.ageColumnIndex), "Tree age column not found.");
                }
                if (this.dbhColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.dbhColumnIndex), "DBH column not found.");
                }
                if (this.heightColumnIndex < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(this.heightColumnIndex), "Height column not found.");
                }
                if ((this.expansionFactorColumnIndex < 0) && (this.defaultExpansionFactor <= 0.0F))
                {
                    throw new ArgumentOutOfRangeException(nameof(this.expansionFactorColumnIndex), "Expansion factor column not found.");
                }

                return;
            }

            if (rowAsStrings[this.treeColumnIndex] == null)
            {
                return; // assume end of data in file
            }

            // filter by plot
            int  plot           = Int32.Parse(rowAsStrings[this.plotColumnIndex]);
            bool treeInPlotList = false;

            for (int idIndex = 0; idIndex < this.plotIDs.Count; ++idIndex)
            {
                if (plot == this.plotIDs[idIndex])
                {
                    treeInPlotList = true;
                    break;
                }
            }
            if (treeInPlotList == false)
            {
                // tree is not in the list of plots specified
                return;
            }

            // exclude dead trees
            if (this.treeConditionColumnIndex >= 0)
            {
                if (String.IsNullOrWhiteSpace(rowAsStrings[this.treeConditionColumnIndex]) == false)
                {
                    int treeCondition = Int32.Parse(rowAsStrings[this.treeConditionColumnIndex]);
                    if (treeCondition == Constant.MalcolmKnapp.TreeCondition.Dead)
                    {
                        return;
                    }
                }
            }

            // parse data
            int age = Int32.Parse(rowAsStrings[this.ageColumnIndex]);

            if (this.byAge.TryGetValue(age, out Stand? plotAtAge) == false)
            {
                plotAtAge = new Stand();
                this.byAge.Add(age, plotAtAge);
            }

            FiaCode species = FiaCodeExtensions.Parse(rowAsStrings[this.speciesColumnIndex]);

            if (plotAtAge.TreesBySpecies.TryGetValue(species, out Trees? treesOfSpecies) == false)
            {
                treesOfSpecies = new Trees(species, 1, Units.Metric);
                plotAtAge.TreesBySpecies.Add(species, treesOfSpecies);
            }

            int    tag         = Int32.Parse(rowAsStrings[this.treeColumnIndex]);
            string dbhAsString = rowAsStrings[this.dbhColumnIndex];
            float  dbh         = Single.NaN;

            if ((String.IsNullOrWhiteSpace(dbhAsString) == false) && (String.Equals(dbhAsString, "NA", StringComparison.OrdinalIgnoreCase) == false))
            {
                dbh = this.dbhScaleFactor * Single.Parse(dbhAsString);
            }
            string heightAsString = rowAsStrings[this.heightColumnIndex];
            float  height         = Single.NaN;

            if ((String.IsNullOrWhiteSpace(heightAsString) == false) && (String.Equals(heightAsString, "NA", StringComparison.OrdinalIgnoreCase) == false))
            {
                height = this.heightScaleFactor * Single.Parse(heightAsString);
            }
            float expansionFactor = this.defaultExpansionFactor;

            if (this.expansionFactorColumnIndex >= 0)
            {
                expansionFactor = Single.Parse(rowAsStrings[this.expansionFactorColumnIndex]);
            }

            // add trees with placeholder crown ratio
            treesOfSpecies.Add(tag, dbh, height, this.defaultCrownRatio, expansionFactor);
        }
示例#18
0
        protected override float GetCrownWidth(FiaCode species, float HLCW, float largestCrownWidth, float HT, float DBH, float XL)
        {
            float B1;
            float B2;
            float B3;

            switch (species)
            {
            // Hann, Bluhm, and Hibbs Red Alder Plantation Analysis
            case FiaCode.AlnusRubra:
                B1 = 0.63420194F;
                B2 = 0.17649614F;
                B3 = -0.02315018F;
                break;

            // Hann(1999) FS 45: 217-225
            case FiaCode.PseudotsugaMenziesii:
                B1 = 0.929973F;
                B2 = -0.135212F;
                B3 = -0.0157579F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.ThujaPlicata:
            case FiaCode.TsugaHeterophylla:
                B1 = 0.629785F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann and Hanus(2001) FRL Research Contribution 34
            case FiaCode.AcerMacrophyllum:
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B1 = 0.5F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float RP    = (HT - XL) / (HT - HLCW);
            float RATIO = HT / DBH;

            if (species == FiaCode.PseudotsugaMenziesii)
            {
                if (RATIO > 50.0F)
                {
                    RATIO = 50.0F;
                }
            }

            float crownWidthMultiplier = MathV.Pow(RP, B1 + B2 * MathF.Sqrt(RP) + B3 * RATIO);

            Debug.Assert(crownWidthMultiplier >= 0.0F);
            Debug.Assert(crownWidthMultiplier <= 3.5F); // BUGBUG: red alder coefficients inherited from Fortran lead to negative powers of RP

            float crownWidth = largestCrownWidth * crownWidthMultiplier;

            return(crownWidth);
        }
示例#19
0
        protected static void Verify(ExpectedTreeChanges expectedGrowth, OrganonWarnings expectedWarnings, TestStand stand, OrganonVariant variant)
        {
            Assert.IsTrue(stand.AgeInYears >= 0);
            Assert.IsTrue(stand.AgeInYears <= TestConstant.Maximum.StandAgeInYears);
            Assert.IsTrue(stand.BreastHeightAgeInYears >= 0);
            Assert.IsTrue(stand.BreastHeightAgeInYears <= TestConstant.Maximum.StandAgeInYears);
            Assert.IsTrue(stand.NumberOfPlots >= 1);
            Assert.IsTrue(stand.NumberOfPlots <= 36);
            Assert.IsTrue(stand.TreesBySpecies.Count > 0);
            Assert.IsTrue(stand.GetTreeRecordCount() > 0);

            foreach (Trees treesOfSpecies in stand.TreesBySpecies.Values)
            {
                FiaCode species = treesOfSpecies.Species;
                Assert.IsTrue(Enum.IsDefined(typeof(FiaCode), species));

                for (int treeIndex = 0; treeIndex < treesOfSpecies.Count; ++treeIndex)
                {
                    // primary tree data
                    float crownRatio = treesOfSpecies.CrownRatio[treeIndex];
                    Assert.IsTrue(crownRatio >= 0.0F);
                    Assert.IsTrue(crownRatio <= 1.0F);
                    float dbhInInches = treesOfSpecies.Dbh[treeIndex];
                    Assert.IsTrue(dbhInInches >= 0.0F);
                    Assert.IsTrue(dbhInInches <= TestConstant.Maximum.DiameterInInches);
                    float expansionFactor = treesOfSpecies.LiveExpansionFactor[treeIndex];
                    Assert.IsTrue(expansionFactor >= 0.0F);
                    Assert.IsTrue(expansionFactor <= TestConstant.Maximum.ExpansionFactor);
                    float heightInFeet = treesOfSpecies.Height[treeIndex];
                    Assert.IsTrue(heightInFeet >= 0.0F);
                    Assert.IsTrue(heightInFeet <= TestConstant.Maximum.HeightInFeet);

                    float deadExpansionFactor = treesOfSpecies.DeadExpansionFactor[treeIndex];
                    Assert.IsTrue(deadExpansionFactor >= 0.0F);
                    Assert.IsTrue(deadExpansionFactor <= TestConstant.Maximum.ExpansionFactor);
                    Assert.IsTrue(expansionFactor + deadExpansionFactor <= TestConstant.Maximum.ExpansionFactor);

                    // diameter and height growth
                    float diameterGrowthInInches = treesOfSpecies.DbhGrowth[treeIndex];
                    if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowth))
                    {
                        Assert.IsTrue(diameterGrowthInInches > 0.0F, "{0}: {1} {2} did not grow in diameter.", variant.TreeModel, treesOfSpecies.Species, treeIndex);
                        Assert.IsTrue(diameterGrowthInInches <= 0.1F * TestConstant.Maximum.DiameterInInches);
                    }
                    else if (expectedGrowth.HasFlag(ExpectedTreeChanges.DiameterGrowthOrNoChange))
                    {
                        Assert.IsTrue(diameterGrowthInInches >= 0.0F);
                        Assert.IsTrue(diameterGrowthInInches <= 0.1F * TestConstant.Maximum.DiameterInInches);
                    }
                    else
                    {
                        Assert.IsTrue(diameterGrowthInInches == 0.0F);
                    }
                    float heightGrowthInFeet = treesOfSpecies.HeightGrowth[treeIndex];
                    if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowth))
                    {
                        Assert.IsTrue(heightGrowthInFeet > 0.0F, "{0}: {1} {2} did not grow in height.", variant.TreeModel, treesOfSpecies.Species, treeIndex);
                        Assert.IsTrue(heightGrowthInFeet <= 0.1F * TestConstant.Maximum.HeightInFeet);
                    }
                    else if (expectedGrowth.HasFlag(ExpectedTreeChanges.HeightGrowthOrNoChange))
                    {
                        Assert.IsTrue(heightGrowthInFeet >= 0.0F, "{0}: {1} {2} decreased in height.", variant.TreeModel, treesOfSpecies.Species, treeIndex);
                        Assert.IsTrue(heightGrowthInFeet <= 0.1F * TestConstant.Maximum.HeightInFeet);
                    }
                    else
                    {
                        Assert.IsTrue(heightGrowthInFeet == 0.0F);
                    }

                    // for now, ignore warnings on height exceeding potential height
                    // Assert.IsTrue(stand.TreeWarnings[treeWarningIndex] == 0);
                }

                for (int treeIndex = treesOfSpecies.Count; treeIndex < treesOfSpecies.Capacity; ++treeIndex)
                {
                    Assert.IsTrue(treesOfSpecies.CrownRatio[treeIndex] == 0.0F);
                    Assert.IsTrue(treesOfSpecies.Dbh[treeIndex] == 0.0F);
                    Assert.IsTrue(treesOfSpecies.DeadExpansionFactor[treeIndex] == 0.0F);
                    Assert.IsTrue(treesOfSpecies.Height[treeIndex] == 0.0F);
                    Assert.IsTrue(treesOfSpecies.LiveExpansionFactor[treeIndex] == 0.0F);
                }
            }

            Assert.IsTrue(stand.Warnings.BigSixHeightAbovePotential == false);
            Assert.IsTrue(stand.Warnings.LessThan50TreeRecords == expectedWarnings.HasFlag(OrganonWarnings.LessThan50TreeRecords));
            Assert.IsTrue(stand.Warnings.HemlockSiteIndexOutOfRange == expectedWarnings.HasFlag(OrganonWarnings.HemlockSiteIndex));
            Assert.IsTrue(stand.Warnings.OtherSpeciesBasalAreaTooHigh == false);
            Assert.IsTrue(stand.Warnings.SiteIndexOutOfRange == false);
            if (variant.TreeModel != TreeModel.OrganonSmc)
            {
                // for now, ignore SMC warning for breast height age < 10
                Assert.IsTrue(stand.Warnings.TreesOld == false);
            }
            // for now, ignore stand.Warnings.TreesYoung
        }
示例#20
0
        public override float GetMaximumCrownWidth(FiaCode species, float D, float H)
        {
            float B0;
            float B1;
            float B2;
            float K;
            float PKDBH;

            switch (species)
            {
            // Hann, Bluhm, and Hibbs Red Alder Plantation Analysis
            case FiaCode.AlnusRubra:
                B0    = 2.320746348F;
                B1    = 6.661401926F;
                B2    = 0.0F;
                K     = 0.6F;
                PKDBH = 999.99F;
                break;

            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.PseudotsugaMenziesii:
                B0    = 4.6198F;
                B1    = 1.8426F;
                B2    = -0.011311F;
                K     = 1.0F;
                PKDBH = 81.45F;
                break;

            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.TsugaHeterophylla:
                B0    = 4.5652F;
                B1    = 1.4147F;
                B2    = 0.0F;
                K     = 1.0F;
                PKDBH = 999.99F;
                break;

            // Smith(1966) Proc. 6th World Forestry Conference
            case FiaCode.ThujaPlicata:
                B0    = 4.0F;
                B1    = 1.65F;
                B2    = 0.0F;
                K     = 1.0F;
                PKDBH = 999.99F;
                break;

            // Ek(1974) School of Natural Res., U.Wisc., Forestry Res. Notes.
            case FiaCode.AcerMacrophyllum:
                B0    = 4.0953F;
                B1    = 2.3849F;
                B2    = -0.011630F;
                K     = 1.0F;
                PKDBH = 102.53F;
                break;

            // GC of Paine and Hann (1982) FRL Research Paper 46
            // GC of Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B0    = 2.9793895F;
                B1    = 1.5512443F;
                B2    = -0.01416129F;
                K     = 1.0F;
                PKDBH = 54.77F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }

            float DBH = D;

            if (DBH > PKDBH)
            {
                DBH = PKDBH;
            }
            float HT = H;
            float MCW;

            if (HT < 4.501F)
            {
                MCW = HT / 4.5F * B0;
            }
            else
            {
                MCW = B0 + B1 * MathV.Pow(DBH, K) + B2 * DBH * DBH;
            }
            return(MCW);
        }
示例#21
0
        protected override float GetLargestCrownWidth(FiaCode species, float MCW, float CR, float DBH, float HT)
        {
            float B0;
            float B1;
            float B2;
            float B3;

            switch (species)
            {
            // Hann, Bluhm, and Hibbs Red Alder Plantation Analysis
            case FiaCode.AlnusRubra:
                B0 = 0.78160725F;
                B1 = 0.44092737F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.PseudotsugaMenziesii:
                B0 = 1.0F;
                B1 = 0.0F;
                B2 = 0.00436324F;
                B3 = 0.6020020F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.TsugaHeterophylla:
                B0 = 1.0F;
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 0.0F;
                break;

            // IC of Hann(1997) FRL Research Contribution 17
            case FiaCode.ThujaPlicata:
                B0 = 1.0F;
                B1 = -0.2513890F;
                B2 = 0.006925120F;
                B3 = 0.985922F;
                break;

            // Hann(1997) FRL Research Contribution 17
            case FiaCode.AcerMacrophyllum:
                B0 = 1.0F;
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 1.47018F;
                break;

            // GC of Hann(1997) FRL Research Contribution 17
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B0 = 1.0F;
                B1 = 0.0F;
                B2 = 0.0F;
                B3 = 1.61440F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float CL  = CR * HT;
            float LCW = B0 * MCW * MathV.Pow(CR, B1 + B2 * CL + B3 * (DBH / HT));

            return(LCW);
        }
示例#22
0
 public static float EstimateHeightInFeet(FiaCode species, float dbhInInches)
 {
     return(TestConstant.FeetPerMeter * TreeRecord.EstimateHeightInMeters(species, dbhInInches));
 }
示例#23
0
        // OG unused
        public override float GetHeightToCrownBase(FiaCode species, float HT, float DBH, float CCFL, float BA, float siteIndex, float hemlockSiteIndex, float OG)
        {
            float B0;
            float B1;
            float B2;
            float B3;
            float B4;
            float B5;
            // float B6 = 0.0F; // always zero
            float K = 0.0F;

            switch (species)
            {
            // Hann, Bluhm, and Hibbs (2011) Development and Evaluation of the Tree-Level Equations and Their Combined
            //   Stand-Level Behavior in the Red Alder Plantation Version of Organon
            case FiaCode.AlnusRubra:
                B0 = 3.73113020F;
                B1 = -0.021546486F;
                B2 = -0.0016572840F;
                B3 = -1.0649544F;
                B4 = 7.47699601F;
                B5 = 0.0252953320F;
                K  = 1.6F;
                break;

            // Hann and Hanus (2004) FS 34: 1193-2003
            case FiaCode.PseudotsugaMenziesii:
                B0 = 6.18464679F;
                B1 = -0.00328764F;
                B2 = -0.00136555F;
                B3 = -1.19702220F;
                B4 = 3.17028263F;
                B5 = 0.0F;
                break;

            // Johnson (2002) Willamette Industries Report
            case FiaCode.TsugaHeterophylla:
                B0 = 1.92682F;
                B1 = -0.00280478F;
                B2 = -0.0011939F;
                B3 = -0.513134F;
                B4 = 3.68901F;
                B5 = 0.00742219F;
                break;

            // Hann and Hanus (2002) OSU Department of Forest Management Internal Report #2
            case FiaCode.ThujaPlicata:
                B0 = 4.49102006F;
                B1 = 0.0F;
                B2 = -0.00132412F;
                B3 = -1.01460531F;
                B4 = 0.0F;
                B5 = 0.01340624F;
                break;

            // Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.AcerMacrophyllum:
                B0 = 0.9411395642F;
                B1 = -0.00768402F;
                B2 = -0.005476131F;
                B3 = 0.0F;
                B4 = 0.0F;
                B5 = 0.0F;
                break;

            // Hanus, Hann, and Marshall (2000) FRL Research Contribution 29
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B0 = 0.0F;
                B1 = 0.0F;
                B2 = -0.005666559F;
                B3 = -0.745540494F;
                B4 = 0.0F;
                B5 = 0.038476613F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }

            float HCB;

            if (species == FiaCode.AlnusRubra)
            {
                // HCB = (HT - K) / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * SI_1 + B6 * OG * OG)) + K;
                HCB = (HT - K) / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * siteIndex)) + K;
            }
            else
            {
                float SITE = hemlockSiteIndex;
                if (species == FiaCode.TsugaHeterophylla)
                {
                    SITE = 0.480F + (1.110F * (hemlockSiteIndex + 4.5F));
                }
                // HCB = HT / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * SITE + B6 * OG * OG));
                HCB = HT / (1.0F + MathV.Exp(B0 + B1 * HT + B2 * CCFL + B3 * MathV.Ln(BA) + B4 * (DBH / HT) + B5 * SITE));
            }
            Debug.Assert(HCB >= 0.0F);
            Debug.Assert(HCB <= HT);
            return(HCB);
        }
示例#24
0
        public override float GetMaximumCrownWidth(FiaCode species, float D, float H)
        {
            float B0;
            float B1;
            float B2;
            float PKDBH;

            switch (species)
            {
            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.PseudotsugaMenziesii:
                B0    = 4.6198F;
                B1    = 1.8426F;
                B2    = -0.011311F;
                PKDBH = 81.45F;
                break;

            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.AbiesGrandis:
                B0    = 6.1880F;
                B1    = 1.0069F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.TsugaHeterophylla:
                B0    = 4.5652F;
                B1    = 1.4147F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // Smith(1966) Proc. 6th World Forestry Conference
            case FiaCode.ThujaPlicata:
                B0    = 4.0F;
                B1    = 1.65F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // WH of Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.TaxusBrevifolia:
                B0    = 4.5652F;
                B1    = 1.4147F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.ArbutusMenziesii:
                B0    = 3.4298629F;
                B1    = 1.3532302F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // Ek(1974) School of Natural Res., U.Wisc., Forestry Res. Notes.
            case FiaCode.AcerMacrophyllum:
                B0    = 4.0953F;
                B1    = 2.3849F;
                B2    = -0.011630F;
                PKDBH = 102.53F;
                break;

            // Paine and Hann (1982) FRL Research Paper 46
            case FiaCode.QuercusGarryana:
                B0    = 3.0785639F;
                B1    = 1.9242211F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // Smith(1966) Proc. 6th World Forestry Conference
            case FiaCode.AlnusRubra:
                B0    = 8.0F;
                B1    = 1.53F;
                B2    = 0.0F;
                PKDBH = 999.99F;
                break;

            // GC of Paine and Hann(1982) FRL Research Paper 46
            case FiaCode.CornusNuttallii:
            case FiaCode.Salix:
                B0    = 2.9793895F;
                B1    = 1.5512443F;
                B2    = -0.01416129F;
                PKDBH = 54.77F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }
            float DBH = D;

            if (DBH > PKDBH)
            {
                DBH = PKDBH;
            }
            float HT = H;
            float MCW;

            if (HT < 4.501F)
            {
                MCW = HT / 4.5F * B0;
            }
            else
            {
                MCW = B0 + B1 * DBH + B2 * DBH * DBH;
            }
            return(MCW);
        }
示例#25
0
        public TreeQuantiles(TestStand stand)
            : this()
        {
            foreach (KeyValuePair <FiaCode, int[]> initialDbhQuantile in stand.InitialDbhQuantileBySpecies)
            {
                // accumulate stand state into quantiles
                Trees treesOfSpecies = stand.TreesBySpecies[initialDbhQuantile.Key];

                int[]   quantileCounts = new int[TestConstant.DbhQuantiles];
                float[] quantileDeadExpansionFactor = new float[TestConstant.DbhQuantiles];
                float[] quantileLiveExpansionFactor = new float[TestConstant.DbhQuantiles];
                float[] quantileMaxDbh         = new float[TestConstant.DbhQuantiles];
                float[] quantileMeanCrownRatio = new float[TestConstant.DbhQuantiles];
                float[] quantileMeanDbh        = new float[TestConstant.DbhQuantiles];
                float[] quantileMeanHeight     = new float[TestConstant.DbhQuantiles];
                float[] quantileMinDbh         = Enumerable.Repeat(Constant.CentimetersPerInch * TestConstant.Maximum.DiameterInInches, TestConstant.DbhQuantiles).ToArray();
                for (int treeIndex = 0; treeIndex < initialDbhQuantile.Value.Length; ++treeIndex)
                {
                    int   quantile            = initialDbhQuantile.Value[treeIndex];
                    float liveExpansionFactor = treesOfSpecies.LiveExpansionFactor[treeIndex];
                    if (liveExpansionFactor > 0.0F)
                    {
                        quantileCounts[quantile] += 1;
                        quantileDeadExpansionFactor[quantile] += treesOfSpecies.DeadExpansionFactor[treeIndex];
                        quantileLiveExpansionFactor[quantile] += liveExpansionFactor;
                        quantileMaxDbh[quantile]          = MathF.Max(quantileMaxDbh[quantile], treesOfSpecies.Dbh[treeIndex]);
                        quantileMeanCrownRatio[quantile] += liveExpansionFactor * treesOfSpecies.CrownRatio[treeIndex];
                        quantileMeanDbh[quantile]        += liveExpansionFactor * treesOfSpecies.Dbh[treeIndex];
                        quantileMeanHeight[quantile]     += liveExpansionFactor * treesOfSpecies.Height[treeIndex];
                        quantileMinDbh[quantile]          = MathF.Min(quantileMinDbh[quantile], treesOfSpecies.Dbh[treeIndex]);
                    }
                }

                // take averages and convert from Organon's English units to metric
                for (int quantile = 0; quantile < TestConstant.DbhQuantiles; ++quantile)
                {
                    int quantileCount = quantileCounts[quantile];
                    if (quantileCount > 0)
                    {
                        float liveExpansionFactor = quantileLiveExpansionFactor[quantile];
                        quantileDeadExpansionFactor[quantile] = TestConstant.AcresPerHectare * quantileDeadExpansionFactor[quantile];
                        quantileLiveExpansionFactor[quantile] = TestConstant.AcresPerHectare * liveExpansionFactor;
                        quantileMaxDbh[quantile]          = Constant.CentimetersPerInch * quantileMaxDbh[quantile];
                        quantileMeanCrownRatio[quantile] /= liveExpansionFactor;
                        quantileMeanDbh[quantile]         = Constant.CentimetersPerInch * quantileMeanDbh[quantile] / liveExpansionFactor;
                        quantileMeanHeight[quantile]      = Constant.MetersPerFoot * quantileMeanHeight[quantile] / liveExpansionFactor;
                        quantileMinDbh[quantile]          = Constant.CentimetersPerInch * quantileMinDbh[quantile];

                        Debug.Assert(quantileMinDbh[quantile] / quantileMaxDbh[quantile] < 1.0001);
                        Debug.Assert(quantileMinDbh[quantile] / quantileMeanDbh[quantile] < 1.0001);
                        Debug.Assert(quantileMeanDbh[quantile] / quantileMaxDbh[quantile] < 1.0001);
                    }
                }

                FiaCode species = initialDbhQuantile.Key;
                this.DeadExpansionFactorBySpecies.Add(species, quantileDeadExpansionFactor);
                this.LiveExpansionFactorBySpecies.Add(species, quantileLiveExpansionFactor);
                this.MaxDbhInCmBySpecies.Add(species, quantileMaxDbh);
                this.MeanCrownRatioBySpecies.Add(species, quantileMeanCrownRatio);
                this.MeanDbhInCmBySpecies.Add(species, quantileMeanDbh);
                this.MeanHeightInMetersBySpecies.Add(species, quantileMeanHeight);
                this.MinDbhInCmBySpecies.Add(species, quantileMinDbh);
            }
        }
示例#26
0
        protected override float GetMaximumHeightToCrownBase(FiaCode species, float HT, float CCFL)
        {
            float B0;
            float B1;
            float B2;
            float B3;
            float LIMIT;

            switch (species)
            {
            case FiaCode.PseudotsugaMenziesii:
                B0    = 0.96F;
                B1    = 0.26F;
                B2    = -0.34758F;
                B3    = 1.5F;
                LIMIT = 0.95F;
                break;

            case FiaCode.AbiesGrandis:
                B0    = 0.96F;
                B1    = 0.31F;
                B2    = -2.450718394F;
                B3    = 1.0F;
                LIMIT = 0.95F;
                break;

            case FiaCode.TsugaHeterophylla:
                B0    = 1.01F;
                B1    = 0.36F;
                B2    = -0.944528054F;
                B3    = 0.6F;
                LIMIT = 0.96F;
                break;

            case FiaCode.ThujaPlicata:
                B0    = 0.96F;
                B1    = 0.31F;
                B2    = -1.059636222F;
                B3    = 1.0F;
                LIMIT = 0.95F;
                break;

            case FiaCode.TaxusBrevifolia:
                B0    = 0.85F;
                B1    = 0.35F;
                B2    = -0.922868139F;
                B3    = 0.8F;
                LIMIT = 0.80F;
                break;

            case FiaCode.ArbutusMenziesii:
                B0    = 0.981F;
                B1    = 0.161F;
                B2    = -1.73666044F;
                B3    = 1.0F;
                LIMIT = 0.98F;
                break;

            case FiaCode.AcerMacrophyllum:
                B0    = 1.0F;
                B1    = 0.45F;
                B2    = -1.020016685F;
                B3    = 1.0F;
                LIMIT = 0.95F;
                break;

            case FiaCode.QuercusGarryana:
                B0    = 1.0F;
                B1    = 0.3F;
                B2    = -0.95634399F;
                B3    = 1.1F;
                LIMIT = 0.98F;
                break;

            case FiaCode.AlnusRubra:
                B0    = 0.93F;
                B1    = 0.18F;
                B2    = -0.928243505F;
                B3    = 1.0F;
                LIMIT = 0.92F;
                break;

            case FiaCode.CornusNuttallii:
                B0    = 1.0F;
                B1    = 0.45F;
                B2    = -1.020016685F;
                B3    = 1.0F;
                LIMIT = 0.95F;
                break;

            case FiaCode.Salix:
                B0    = 0.985F;
                B1    = 0.285F;
                B2    = -0.969750805F;
                B3    = 0.9F;
                LIMIT = 0.98F;
                break;

            default:
                throw Trees.CreateUnhandledSpeciesException(species);
            }

            float MAXBR = B0 - B1 * MathV.Exp(B2 * MathV.Pow(CCFL / 100.0F, B3));

            if (MAXBR > LIMIT)
            {
                MAXBR = LIMIT;
            }
            float MAXHCB = MAXBR * HT;

            return(MAXHCB);
        }
示例#27
0
文件: PspStand.cs 项目: OSU-MARS/SEEM
        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);
        }