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); } }
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); }