private static PlotsWithHeight GetPlot14() { string plotFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "OSU", "Organon", "Malcolm Knapp plots 14-18+34 Ministry.xlsx"); PlotsWithHeight plot = new PlotsWithHeight(new List <int>() { 14 }, 4.48F); plot.Read(plotFilePath, "0.2 ha"); return(plot); }
private static PlotsWithHeight GetNelder() { string plotFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "OSU", "Organon", "Malcolm Knapp Nelder 1.xlsx"); PlotsWithHeight plot = new PlotsWithHeight(new List <int>() { 1 }, 1.327F); plot.Read(plotFilePath, "1"); return(plot); }
public void StandGrowthPerformance() { int thinningPeriod = 4; int runs = 4; // 1 warmup run + measured runs int trees = 300; #if DEBUG runs = 1; // do only functional validation of test on DEBUG builds to reduce test execution time trees = 10; #endif PlotsWithHeight nelder = PublicApi.GetNelder(); OrganonConfiguration configuration = PublicApi.CreateOrganonConfiguration(new OrganonVariantNwo()); configuration.Treatments.Harvests.Add(new ThinByIndividualTreeSelection(thinningPeriod)); OrganonStand stand = nelder.ToOrganonStand(configuration, 20, 130.0F, trees); stand.PlantingDensityInTreesPerHectare = TestConstant.NelderReplantingDensityInTreesPerHectare; Objective landExpectationValue = new Objective() { IsLandExpectationValue = true, PlanningPeriods = 9 }; HeuristicParameters defaultParameters = new HeuristicParameters(); TimeSpan runtime = TimeSpan.Zero; for (int run = 0; run < runs; ++run) { // after warmup: 3 runs * 300 trees = 900 measured growth simulations on i7-3770 (4th gen, Sandy Bridge) // dispersion of 5 runs min mean median max // .NET 5.0 with removed tree compaction 1.67 1.72 1.72 1.82 Hero hero = new Hero(stand, configuration, landExpectationValue, defaultParameters) { IsStochastic = false, MaximumIterations = 2 }; hero.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); if (run > 0) { // skip first run as a warmup run runtime += hero.Run(); } } this.TestContext !.WriteLine(runtime.TotalSeconds.ToString()); }
public void Plot14ImmediateThin() { int thinPeriod = 1; int lastPeriod = 4; bool useScaledVolume = false; PlotsWithHeight plot14 = PublicApi.GetPlot14(); OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(new OrganonVariantNwo()); OrganonStand stand = plot14.ToOrganonStand(configuration, 30, 130.0F); stand.PlantingDensityInTreesPerHectare = TestConstant.Plot14ReplantingDensityInTreesPerHectare; configuration.Treatments.Harvests.Add(new ThinByPrescription(thinPeriod) { FromAbovePercentage = 0.0F, ProportionalPercentage = 30.0F, FromBelowPercentage = 0.0F }); OrganonStandTrajectory thinnedTrajectory = new OrganonStandTrajectory(stand, configuration, TimberValue.Default, lastPeriod, useScaledVolume); AssertNullable.IsNotNull(thinnedTrajectory.StandByPeriod[0]); Assert.IsTrue(thinnedTrajectory.StandByPeriod[0] !.GetTreeRecordCount() == 222); thinnedTrajectory.Simulate(); // verify thinned trajectory // 0 1 2 3 4 float[] minimumThinnedQmd = new float[] { 9.16F, 10.47F, 11.64F, 12.64F, 13.52F }; // in // 0 1 2 3 4 float[] minimumThinnedTopHeight = new float[] { 92.9F, 101.4F, 110.4F, 118.9F, 126.7F }; // ft float[] minimumThinnedVolume; if (thinnedTrajectory.UseScaledVolume) { minimumThinnedVolume = new float[] { 51.59F, 51.75F, 66.71F, 81.88F, 97.72F }; // Poudel 2018 + Scribner long log net MBF/ha } else { // 0 1 2 3 4 minimumThinnedVolume = new float[] { 43.74F, 49.00F, 68.86F, 87.95F, 105.8F }; // Browning 1977 (FIA) MBF/ha } PublicApi.Verify(thinnedTrajectory, minimumThinnedQmd, minimumThinnedTopHeight, minimumThinnedVolume, thinPeriod, lastPeriod, 65, 70, configuration.Variant.TimeStepInYears); PublicApi.Verify(thinnedTrajectory, minimumThinnedVolume, thinPeriod); Assert.IsTrue(thinnedTrajectory.GetFirstHarvestAge() == 30); }
public void NelderHero() { int thinningPeriod = 4; int treeCount = 100; int expectedTreesSelectedWithFiaVolume = 0; float minObjectiveFunctionWithFiaVolume = 4.154F; // USk$/ha float minObjectiveFunctionWithScaledVolume = 3.454F; // USk$/ha float minThinnedMbfWithFiaVolume = 0.0F; #if DEBUG treeCount = 48; expectedTreesSelectedWithFiaVolume = 0; minObjectiveFunctionWithFiaVolume = 1.790F; // USk$/ha minObjectiveFunctionWithScaledVolume = 1.357F; // USk$/ha minThinnedMbfWithFiaVolume = 0.0F; #endif PlotsWithHeight nelder = PublicApi.GetNelder(); OrganonConfiguration configuration = new OrganonConfiguration(new OrganonVariantNwo()); configuration.Treatments.Harvests.Add(new ThinByIndividualTreeSelection(thinningPeriod)); OrganonStand stand = nelder.ToOrganonStand(configuration, 20, 130.0F, treeCount); stand.PlantingDensityInTreesPerHectare = TestConstant.NelderReplantingDensityInTreesPerHectare; Objective landExpectationValue = new Objective() { IsLandExpectationValue = true, PlanningPeriods = 9 }; Hero hero = new Hero(stand, configuration, landExpectationValue, new HeuristicParameters() { UseScaledVolume = false }) { //IsStochastic = true, MaximumIterations = 10 }; //hero.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); hero.CurrentTrajectory.SetTreeSelection(0, thinningPeriod); hero.Run(); this.Verify(hero); int[] treeSelection = hero.BestTrajectory.IndividualTreeSelectionBySpecies[FiaCode.PseudotsugaMenziesii]; int treesSelected = treeSelection.Sum() / thinningPeriod; if (hero.BestTrajectory.UseScaledVolume) { this.TestContext !.WriteLine("best objective: {0} observed, near {1} expected", hero.BestObjectiveFunction, minObjectiveFunctionWithScaledVolume); Assert.IsTrue(hero.BestObjectiveFunction > minObjectiveFunctionWithScaledVolume); Assert.IsTrue(hero.BestObjectiveFunction < 1.02F * minObjectiveFunctionWithScaledVolume); } else { // expected standing volume, MBF, for no trees harvested // 0.122, 0.971, 3.18, 6.749, 11.56, 17.54, 24.56, 32.44, 40.97, 49.98 // expected NPV, US$/ha, for no trees harvested // -90.96, 61.62, 373.49, 781.90, 1228.99, 1674.68, 2085.93, 2438.25, 2717.76, 2918.96 this.TestContext !.WriteLine("best objective: {0} observed, near {1} expected", hero.BestObjectiveFunction, minObjectiveFunctionWithFiaVolume); Assert.IsTrue(hero.BestObjectiveFunction > minObjectiveFunctionWithFiaVolume); Assert.IsTrue(hero.BestObjectiveFunction < 1.01F * minObjectiveFunctionWithFiaVolume); Assert.IsTrue(hero.BestTrajectory.ThinningVolume.ScribnerTotal[thinningPeriod] >= minThinnedMbfWithFiaVolume); Assert.IsTrue(hero.BestTrajectory.ThinningVolume.ScribnerTotal[thinningPeriod] <= 1.01 * minThinnedMbfWithFiaVolume); Assert.IsTrue(treesSelected == expectedTreesSelectedWithFiaVolume); } }
public void NelderTrajectory() { int expectedUnthinnedTreeRecordCount = 661; int lastPeriod = 9; bool useScaledVolume = false; PlotsWithHeight nelder = PublicApi.GetNelder(); OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(new OrganonVariantNwo()); OrganonStand stand = nelder.ToOrganonStand(configuration, 20, 130.0F); stand.PlantingDensityInTreesPerHectare = TestConstant.NelderReplantingDensityInTreesPerHectare; OrganonStandTrajectory unthinnedTrajectory = new OrganonStandTrajectory(stand, configuration, TimberValue.Default, lastPeriod, useScaledVolume); unthinnedTrajectory.Simulate(); foreach (Stand?unthinnedStand in unthinnedTrajectory.StandByPeriod) { AssertNullable.IsNotNull(unthinnedStand); Assert.IsTrue(unthinnedStand.GetTreeRecordCount() == expectedUnthinnedTreeRecordCount); } int thinPeriod = 3; configuration.Treatments.Harvests.Add(new ThinByPrescription(thinPeriod) { FromAbovePercentage = 20.0F, ProportionalPercentage = 15.0F, FromBelowPercentage = 10.0F }); OrganonStandTrajectory thinnedTrajectory = new OrganonStandTrajectory(stand, configuration, TimberValue.Default, lastPeriod, useScaledVolume); AssertNullable.IsNotNull(thinnedTrajectory.StandByPeriod[0]); Assert.IsTrue(thinnedTrajectory.StandByPeriod[0] !.GetTreeRecordCount() == expectedUnthinnedTreeRecordCount); thinnedTrajectory.Simulate(); for (int periodIndex = 0; periodIndex < thinPeriod; ++periodIndex) { Stand?unthinnedStand = thinnedTrajectory.StandByPeriod[periodIndex]; AssertNullable.IsNotNull(unthinnedStand); Assert.IsTrue(unthinnedStand.GetTreeRecordCount() == expectedUnthinnedTreeRecordCount); } int expectedThinnedTreeRecordCount = 328; // must be updated if prescription changes for (int periodIndex = thinPeriod; periodIndex < thinnedTrajectory.PlanningPeriods; ++periodIndex) { Stand?thinnedStand = thinnedTrajectory.StandByPeriod[periodIndex]; AssertNullable.IsNotNull(thinnedStand); Assert.IsTrue(thinnedStand.GetTreeRecordCount() == expectedThinnedTreeRecordCount); } // verify unthinned trajectory // 0 1 2 3 4 5 6 7 8 9 float[] minimumUnthinnedQmd = new float[] { 6.61F, 8.17F, 9.52F, 10.67F, 11.68F, 12.56F, 13.34F, 14.05F, 14.69F, 15.28F }; // in // 0 1 2 3 4 5 6 7 8 9 float[] minimumUnthinnedTopHeight = new float[] { 54.1F, 67.9F, 80.3F, 91.6F, 101.9F, 111.3F, 119.9F, 127.8F, 135.0F, 141.7F }; // ft float[] minimumUnthinnedVolume; if (unthinnedTrajectory.UseScaledVolume) { minimumUnthinnedVolume = new float[] { 9.758F, 19.01F, 31.07F, 47.24F, 62.21F, 75.09F, 89.64F, 103.7F, 116.5F, 128.9F }; // Poudel 2018 + Scribner long log net MBF/ha } else { // 0 1 2 3 4 5 6 7 8 9 minimumUnthinnedVolume = new float[] { 4.428F, 15.02F, 30.49F, 48.39F, 66.72F, 84.45F, 101.1F, 116.4F, 130.6F, 143.6F }; // FIA SV6x32 MBF/ha } PublicApi.Verify(unthinnedTrajectory, minimumUnthinnedQmd, minimumUnthinnedTopHeight, minimumUnthinnedVolume, 0, lastPeriod, 0, 0, configuration.Variant.TimeStepInYears); // verify thinned trajectory // 0 1 2 3 4 5 6 7 8 9 float[] minimumThinnedQmd = new float[] { 6.61F, 8.19F, 9.53F, 11.81F, 13.44F, 14.80F, 15.99F, 17.05F, 18.00F, 18.85F }; // in // 0 1 2 3 4 5 6 7 8 9 float[] minimumThinnedTopHeight = new float[] { 54.1F, 67.9F, 80.3F, 88.3F, 98.4F, 108.0F, 116.9F, 125.0F, 132.5F, 139.4F }; // ft float[] minimumThinnedVolume; if (thinnedTrajectory.UseScaledVolume) { minimumThinnedVolume = new float[] { 9.758F, 19.01F, 31.07F, 28.25F, 41.77F, 54.37F, 68.44F, 85.10F, 100.4F, 114.7F }; // Poudel 2018 + Scribner long log net MBF/ha } else { // 0 1 2 3 4 5 6 7 8 9 minimumThinnedVolume = new float[] { 4.428F, 15.02F, 30.50F, 30.64F, 47.26F, 64.81F, 82.54F, 99.87F, 116.3F, 131.7F }; // FIA MBF/ha } PublicApi.Verify(thinnedTrajectory, minimumThinnedQmd, minimumThinnedTopHeight, minimumThinnedVolume, thinPeriod, lastPeriod, 200, 400, configuration.Variant.TimeStepInYears); PublicApi.Verify(thinnedTrajectory, minimumThinnedVolume, thinPeriod); }
public void NelderOtherHeuristics() { int thinningPeriod = 4; int treeCount = 75; #if DEBUG treeCount = 25; #endif PlotsWithHeight nelder = PublicApi.GetNelder(); OrganonConfiguration configuration = OrganonTest.CreateOrganonConfiguration(new OrganonVariantNwo()); configuration.Treatments.Harvests.Add(new ThinByIndividualTreeSelection(thinningPeriod)); OrganonStand stand = nelder.ToOrganonStand(configuration, 20, 130.0F, treeCount); stand.PlantingDensityInTreesPerHectare = TestConstant.NelderReplantingDensityInTreesPerHectare; Objective landExpectationValue = new Objective() { IsLandExpectationValue = true, PlanningPeriods = 9 }; Objective volume = new Objective() { PlanningPeriods = landExpectationValue.PlanningPeriods }; HeuristicParameters defaultParameters = new HeuristicParameters() { UseScaledVolume = false }; GeneticParameters geneticParameters = new GeneticParameters(treeCount) { PopulationSize = 7, MaximumGenerations = 5, UseScaledVolume = defaultParameters.UseScaledVolume }; GeneticAlgorithm genetic = new GeneticAlgorithm(stand, configuration, landExpectationValue, geneticParameters); TimeSpan geneticRuntime = genetic.Run(); GreatDeluge deluge = new GreatDeluge(stand, configuration, volume, defaultParameters) { RainRate = 5, LowerWaterAfter = 9, StopAfter = 10 }; deluge.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); TimeSpan delugeRuntime = deluge.Run(); RecordTravel recordTravel = new RecordTravel(stand, configuration, landExpectationValue, defaultParameters) { StopAfter = 10 }; recordTravel.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); TimeSpan recordRuntime = recordTravel.Run(); SimulatedAnnealing annealer = new SimulatedAnnealing(stand, configuration, volume, defaultParameters) { Iterations = 100 }; annealer.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); TimeSpan annealerRuntime = annealer.Run(); TabuParameters tabuParameters = new TabuParameters() { UseScaledVolume = defaultParameters.UseScaledVolume }; TabuSearch tabu = new TabuSearch(stand, configuration, landExpectationValue, tabuParameters) { Iterations = 7, //Jump = 2, MaximumTenure = 5 }; tabu.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); TimeSpan tabuRuntime = tabu.Run(); ThresholdAccepting thresholdAcceptor = new ThresholdAccepting(stand, configuration, volume, defaultParameters); thresholdAcceptor.IterationsPerThreshold.Clear(); thresholdAcceptor.Thresholds.Clear(); thresholdAcceptor.IterationsPerThreshold.Add(10); thresholdAcceptor.Thresholds.Add(1.0F); thresholdAcceptor.RandomizeTreeSelection(TestConstant.Default.SelectionPercentage); TimeSpan acceptorRuntime = thresholdAcceptor.Run(); RandomGuessing random = new RandomGuessing(stand, configuration, volume, defaultParameters) { Iterations = 4 }; TimeSpan randomRuntime = random.Run(); configuration.Treatments.Harvests.Clear(); configuration.Treatments.Harvests.Add(new ThinByPrescription(thinningPeriod)); PrescriptionParameters prescriptionParameters = new PrescriptionParameters() { Maximum = 60.0F, Minimum = 50.0F, Step = 10.0F, UseScaledVolume = defaultParameters.UseScaledVolume }; PrescriptionEnumeration enumerator = new PrescriptionEnumeration(stand, configuration, landExpectationValue, prescriptionParameters); TimeSpan enumerationRuntime = enumerator.Run(); // heuristics assigned to volume optimization this.Verify(deluge); this.Verify(annealer); this.Verify(thresholdAcceptor); this.Verify(random); // heuristics assigned to net present value optimization this.Verify(genetic); this.Verify(enumerator); this.Verify(recordTravel); this.Verify(tabu); HeuristicSolutionDistribution distribution = new HeuristicSolutionDistribution(1, thinningPeriod, treeCount); distribution.AddRun(annealer, annealerRuntime, defaultParameters); distribution.AddRun(deluge, delugeRuntime, defaultParameters); distribution.AddRun(thresholdAcceptor, acceptorRuntime, defaultParameters); distribution.AddRun(genetic, geneticRuntime, defaultParameters); distribution.AddRun(enumerator, enumerationRuntime, defaultParameters); distribution.AddRun(recordTravel, recordRuntime, defaultParameters); distribution.AddRun(tabu, tabuRuntime, defaultParameters); distribution.AddRun(random, randomRuntime, defaultParameters); distribution.OnRunsComplete(); }