From 03685e93a528fa268a85c3f72fb1578af6f0bac2 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Thu, 17 Oct 2024 13:44:06 -0700 Subject: [PATCH] Consolidate Bank in common --- .../gov/nrs/vdyp/processing_state/Bank.java | 8 +- .../nrs/vdyp/processing_state}/BankTest.java | 81 +-- .../nrs/vdyp/test/ProcessingTestUtils.java | 182 +++++++ .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 465 ------------------ .../vdyp/forward/ForwardProcessingEngine.java | 1 + .../vdyp/forward/LayerProcessingState.java | 1 + .../forward/Grow10StoreSpeciesDetails.java | 1 + .../vdyp/forward/test/ForwardTestUtils.java | 170 ------- 8 files changed, 235 insertions(+), 674 deletions(-) rename lib/{vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward => vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/processing_state}/BankTest.java (84%) create mode 100644 lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/ProcessingTestUtils.java delete mode 100644 lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java diff --git a/lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/processing_state/Bank.java b/lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/processing_state/Bank.java index 364abf310..781a7a70f 100644 --- a/lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/processing_state/Bank.java +++ b/lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/processing_state/Bank.java @@ -146,11 +146,11 @@ public int getNSpecies() { return nSpecies; } - int[] getIndices() { + public int[] getIndices() { return indices; } - BecDefinition getBecZone() { + public BecDefinition getBecZone() { return becZone; } @@ -162,7 +162,7 @@ BecDefinition getBecZone() { * @param layer a (presumably modified) version of the layer. * @throws ProcessingException */ - void refreshBank(VdypLayer layer) throws ProcessingException { + public void refreshBank(VdypLayer layer) throws ProcessingException { if (!this.layer.equals(layer)) { throw new IllegalArgumentException( @@ -365,7 +365,7 @@ private float sumSpeciesUtilizationClassValues(float[][] ucValues, UtilizationCl * * @return as described */ - VdypLayer buildLayerFromBank() { + public VdypLayer buildLayerFromBank() { transferUtilizationsFromBank(0, layer); diff --git a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java b/lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/processing_state/BankTest.java similarity index 84% rename from lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java rename to lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/processing_state/BankTest.java index 5fcdd4226..fa0b44267 100644 --- a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java +++ b/lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/processing_state/BankTest.java @@ -1,8 +1,6 @@ -package ca.bc.gov.nrs.vdyp.forward; +package ca.bc.gov.nrs.vdyp.processing_state; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.controlMapHasEntry; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -10,44 +8,73 @@ import java.util.List; import java.util.Map; -import org.hamcrest.Matcher; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.test.ForwardTestUtils; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.VdypEntity; import ca.bc.gov.nrs.vdyp.model.VdypLayer; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; +import ca.bc.gov.nrs.vdyp.test.ProcessingTestUtils; +import ca.bc.gov.nrs.vdyp.test.TestUtils; class BankTest { - private ForwardControlParser parser; private Map controlMap; + private VdypPolygon polygon; - @SuppressWarnings({ "unchecked", "rawtypes" }) @BeforeEach void before() throws IOException, ResourceParseException { - parser = new ForwardControlParser(); - controlMap = ForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.SP0_DEF, instanceOf(GenusDefinitionMap.class))); + controlMap = TestUtils.loadControlMap(); + + var bec = Utils.getBec("CDF", controlMap); + + polygon = VdypPolygon.build(pb -> { + pb.polygonIdentifier("Test", 2024); + + pb.percentAvailable(99f); + pb.biogeoclimaticZone(bec); + pb.forestInventoryZone("A"); + + pb.addLayer(lb -> { + lb.layerType(LayerType.PRIMARY); + + lb.addSpecies(sb -> { + sb.genus("B", controlMap); + sb.baseArea(0.4f); + }); + lb.addSpecies(sb -> { + sb.genus("C", controlMap); + sb.baseArea(0.6f); + }); + lb.addSpecies(sb -> { + sb.genus("D", controlMap); + sb.baseArea(10f); + }); + lb.addSpecies(sb -> { + sb.genus("H", controlMap); + sb.baseArea(50f); + }); + lb.addSpecies(sb -> { + sb.genus("S", controlMap); + sb.baseArea(99.9f); + }); + }); + }); + } @Test void testConstruction() throws IOException, ResourceParseException, ProcessingException { - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); @@ -105,16 +132,12 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx @Test void testSetCopy() throws IOException, ResourceParseException, ProcessingException { - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - pLayer = ForwardTestUtils.normalizeLayer(pLayer); + pLayer = ProcessingTestUtils.normalizeLayer(pLayer); verifyBankMatchesLayer(bank, pLayer); Bank ppsCopy = bank.copy(); @@ -125,10 +148,6 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti @Test void testRemoveSmallLayers() throws IOException, ResourceParseException, ProcessingException { - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); @@ -154,10 +173,6 @@ void testRemoveSmallLayers() throws IOException, ResourceParseException, Process @Test void testCopyConstructor() throws IOException, ResourceParseException, ProcessingException { - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); @@ -165,23 +180,19 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin Bank bankCopy = new Bank(bank); - pLayer = ForwardTestUtils.normalizeLayer(pLayer); + pLayer = ProcessingTestUtils.normalizeLayer(pLayer); verifyBankMatchesLayer(bankCopy, pLayer); } @Test void testLayerUpdate() throws IOException, ResourceParseException, ProcessingException { - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - pLayer = ForwardTestUtils.normalizeLayer(pLayer); + pLayer = ProcessingTestUtils.normalizeLayer(pLayer); verifyBankMatchesLayer(bank, pLayer); diff --git a/lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/ProcessingTestUtils.java b/lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/ProcessingTestUtils.java new file mode 100644 index 000000000..568ffdefa --- /dev/null +++ b/lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/ProcessingTestUtils.java @@ -0,0 +1,182 @@ +package ca.bc.gov.nrs.vdyp.test; + +import java.util.List; + +import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationVector; +import ca.bc.gov.nrs.vdyp.model.VdypLayer; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; + +public class ProcessingTestUtils { + public static VdypLayer normalizeLayer(VdypLayer layer) { + + // Set uc All to the sum of the UC values, UC 7.5 and above only, for the summable + // values, and calculate quad-mean-diameter from these values. + + UtilizationClass ucAll = UtilizationClass.ALL; + UtilizationClass ucSmall = UtilizationClass.SMALL; + + for (var species : layer.getSpecies().values()) { + + species.getBaseAreaByUtilization().set( + ucAll, sumUtilizationClassValues(species.getBaseAreaByUtilization(), UtilizationClass.UTIL_CLASSES) + ); + species.getTreesPerHectareByUtilization().set( + ucAll, + sumUtilizationClassValues(species.getTreesPerHectareByUtilization(), UtilizationClass.UTIL_CLASSES) + ); + species.getWholeStemVolumeByUtilization().set( + ucAll, + sumUtilizationClassValues(species.getWholeStemVolumeByUtilization(), UtilizationClass.UTIL_CLASSES) + ); + species.getCloseUtilizationVolumeByUtilization().set( + ucAll, + sumUtilizationClassValues( + species.getCloseUtilizationVolumeByUtilization(), UtilizationClass.UTIL_CLASSES + ) + ); + species.getCloseUtilizationVolumeNetOfDecayByUtilization().set( + ucAll, + sumUtilizationClassValues( + species.getCloseUtilizationVolumeNetOfDecayByUtilization(), UtilizationClass.UTIL_CLASSES + ) + ); + species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set( + ucAll, + sumUtilizationClassValues( + species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), + UtilizationClass.UTIL_CLASSES + ) + ); + + if (species.getBaseAreaByUtilization().get(ucAll) > 0.0f) { + species.getQuadraticMeanDiameterByUtilization().set( + ucAll, + BaseAreaTreeDensityDiameter.quadMeanDiameter( + species.getBaseAreaByUtilization().get(ucAll), + species.getTreesPerHectareByUtilization().get(ucAll) + ) + ); + } + } + + // Set the layer's uc All values (for summable types) to the sum of those of the + // individual species. + + layer.getBaseAreaByUtilization() + .set(ucAll, sumSpeciesUtilizationClassValues(layer, "BaseArea", UtilizationClass.ALL)); + layer.getTreesPerHectareByUtilization() + .set(ucAll, sumSpeciesUtilizationClassValues(layer, "TreesPerHectare", UtilizationClass.ALL)); + layer.getWholeStemVolumeByUtilization() + .set(ucAll, sumSpeciesUtilizationClassValues(layer, "WholeStemVolume", UtilizationClass.ALL)); + layer.getCloseUtilizationVolumeByUtilization() + .set(ucAll, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolume", UtilizationClass.ALL)); + layer.getCloseUtilizationVolumeNetOfDecayByUtilization().set( + ucAll, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecay", UtilizationClass.ALL) + ); + layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set( + ucAll, + sumSpeciesUtilizationClassValues( + layer, "CloseUtilizationVolumeNetOfDecayAndWaste", UtilizationClass.ALL + ) + ); + + // Calculate the layer's uc All values for quad-mean-diameter and lorey height + + float sumLoreyHeightByBasalAreaSmall = 0.0f; + float sumBasalAreaSmall = 0.0f; + float sumLoreyHeightByBasalAreaAll = 0.0f; + + for (var species : layer.getSpecies().values()) { + sumLoreyHeightByBasalAreaSmall += species.getLoreyHeightByUtilization().get(ucSmall) + * species.getBaseAreaByUtilization().get(ucSmall); + sumBasalAreaSmall += species.getBaseAreaByUtilization().get(ucSmall); + sumLoreyHeightByBasalAreaAll += species.getLoreyHeightByUtilization().get(ucAll) + * species.getBaseAreaByUtilization().get(ucAll); + } + + if (layer.getBaseAreaByUtilization().get(ucAll) > 0.0f) { + layer.getQuadraticMeanDiameterByUtilization().set( + ucAll, + BaseAreaTreeDensityDiameter.quadMeanDiameter( + layer.getBaseAreaByUtilization().get(ucAll), + layer.getTreesPerHectareByUtilization().get(ucAll) + ) + ); + layer.getLoreyHeightByUtilization() + .set(ucAll, sumLoreyHeightByBasalAreaAll / layer.getBaseAreaByUtilization().get(ucAll)); + } + + // Calculate the layer's lorey height uc Small value + + if (sumBasalAreaSmall > 0.0f) { + layer.getLoreyHeightByUtilization().set(ucSmall, sumLoreyHeightByBasalAreaSmall / sumBasalAreaSmall); + } + + // Finally, set the layer's summable UC values (other than All, which was computed above) to + // the sums of those of each of the species. + + for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { + layer.getBaseAreaByUtilization().set(uc, sumSpeciesUtilizationClassValues(layer, "BaseArea", uc)); + layer.getTreesPerHectareByUtilization() + .set(uc, sumSpeciesUtilizationClassValues(layer, "TreesPerHectare", uc)); + layer.getWholeStemVolumeByUtilization() + .set(uc, sumSpeciesUtilizationClassValues(layer, "WholeStemVolume", uc)); + layer.getCloseUtilizationVolumeByUtilization() + .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolume", uc)); + layer.getCloseUtilizationVolumeNetOfDecayByUtilization() + .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecay", uc)); + layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() + .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecayAndWaste", uc)); + } + + return layer; + } + + private static float sumUtilizationClassValues(UtilizationVector ucValues, List subjects) { + float sum = 0.0f; + + for (UtilizationClass uc : UtilizationClass.values()) { + if (subjects.contains(uc)) { + sum += ucValues.get(uc); + } + } + + return sum; + } + + private static float sumSpeciesUtilizationClassValues(VdypLayer layer, String uvName, UtilizationClass uc) { + float sum = 0.0f; + + for (VdypSpecies species : layer.getSpecies().values()) { + switch (uvName) { + case "CloseUtilizationVolumeNetOfDecayWasteAndBreakage": + sum += species.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().get(uc); + break; + case "CloseUtilizationVolumeNetOfDecayAndWaste": + sum += species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc); + break; + case "CloseUtilizationVolumeNetOfDecay": + sum += species.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc); + break; + case "CloseUtilizationVolume": + sum += species.getCloseUtilizationVolumeByUtilization().get(uc); + break; + case "WholeStemVolume": + sum += species.getWholeStemVolumeByUtilization().get(uc); + break; + case "TreesPerHectare": + sum += species.getTreesPerHectareByUtilization().get(uc); + break; + case "BaseArea": + sum += species.getBaseAreaByUtilization().get(uc); + break; + default: + throw new IllegalStateException(uvName + " is not a known utilization vector name"); + } + } + + return sum; + } +} diff --git a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java deleted file mode 100644 index 7728c2a4f..000000000 --- a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ /dev/null @@ -1,465 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.IntStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.Sp64DistributionSet; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; -import ca.bc.gov.nrs.vdyp.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.model.VdypLayer; -import ca.bc.gov.nrs.vdyp.model.VdypSite; -import ca.bc.gov.nrs.vdyp.model.VdypSpecies; -import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; - -class Bank { - - @SuppressWarnings("unused") - private static final Logger logger = LoggerFactory.getLogger(Bank.class); - - private static final int N_UTILIZATION_CLASSES = UtilizationClass.values().length; - - private final VdypLayer layer; - private final BecDefinition becZone; - - /** - * The number of species in the state. Note that all arrays have this value plus one elements in them; the element - * at index 0 is unused for the species values* and contains the default utilization in the Utilization values. - * - * (*) except: siteCurveNumbers[0] is used to store the site curve of the primary species. - */ - private int nSpecies; // BANK1 NSPB - private int[] indices; - - // Species information - - public final String[/* nSpecies + 1 */] speciesNames; // BANK2 SP0B - public final Sp64DistributionSet[/* nSpecies + 1 */] sp64Distributions; // BANK2 SP64DISTB - public final float[/* nSpecies + 1 */] siteIndices; // BANK3 SIB - public final float[/* nSpecies + 1 */] dominantHeights; // BANK3 HDB - public final float[/* nSpecies + 1 */] ageTotals; // BANK3 AGETOTB - public final float[/* nSpecies + 1 */] yearsAtBreastHeight; // BANK3 AGEBHB - public final float[/* nSpecies + 1 */] yearsToBreastHeight; // BANK3 YTBHB - public final int[/* nSpecies + 1 */] siteCurveNumbers; // BANK3 SCNB - public final int[/* nSpecies + 1 */] speciesIndices; // BANK1 ISPB - public final float[/* nSpecies + 1 */] percentagesOfForestedLand; // BANK1 PCTB - - // Utilization information, per Species - - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] basalAreas; // BANK1 BAB. Units: m^2/hectare - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] closeUtilizationVolumes; // BANK1 VOLCUB - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] cuVolumesMinusDecay; // BANK1 VOL_DB - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] cuVolumesMinusDecayAndWastage; // BANK1 VOL_DW_B - public final float[/* nSpecies + 1, including 0 */][/* uc -1 and 0 only */] loreyHeights; // BANK1 HLB - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] quadMeanDiameters; // BANK1 DQB - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] treesPerHectare; // BANK1 TPHB - public final float[/* nSpecies + 1, including 0 */][/* all ucs */] wholeStemVolumes; // BANK1 VOLWSB - - public Bank(VdypLayer layer, BecDefinition becZone, Predicate retainCriteria) { - - this.layer = layer; - this.becZone = becZone; - - List speciesToRetain = layer.getSpecies().values().stream().filter(s -> retainCriteria.test(s)) - .sorted((s1, s2) -> s1.getGenusIndex() - s2.getGenusIndex()).toList(); - - this.nSpecies = speciesToRetain.size(); - this.indices = IntStream.range(1, nSpecies + 1).toArray(); - - // In the following, index 0 is unused - speciesNames = new String[nSpecies + 1]; - sp64Distributions = new Sp64DistributionSet[getNSpecies() + 1]; - siteIndices = new float[nSpecies + 1]; - dominantHeights = new float[nSpecies + 1]; - ageTotals = new float[nSpecies + 1]; - yearsAtBreastHeight = new float[nSpecies + 1]; - yearsToBreastHeight = new float[nSpecies + 1]; - siteCurveNumbers = new int[nSpecies + 1]; - speciesIndices = new int[nSpecies + 1]; - percentagesOfForestedLand = new float[nSpecies + 1]; - - // In the following, index 0 is used for the default species utilization - basalAreas = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - closeUtilizationVolumes = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - cuVolumesMinusDecay = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - cuVolumesMinusDecayAndWastage = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - loreyHeights = new float[nSpecies + 1][2]; - quadMeanDiameters = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - treesPerHectare = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - wholeStemVolumes = new float[nSpecies + 1][N_UTILIZATION_CLASSES]; - - int nextSlot = 1; - for (VdypSpecies s : speciesToRetain) { - transferSpeciesIntoBank(nextSlot++, s); - } - - transferUtilizationSetIntoBank(0, layer); - - // BANKCHK1 - calculate UC All values from components (rather than rely on the values - // provided in the input.) - - setCalculateUtilizationClassAllValues(); - } - - public Bank(Bank source) { - - this.becZone = source.becZone; - this.layer = source.layer; - - this.nSpecies = source.nSpecies; - this.indices = copy(source.indices); - this.speciesNames = copy(source.speciesNames); - this.speciesIndices = copy(source.speciesIndices); - - this.siteCurveNumbers = copy(source.siteCurveNumbers); - this.sp64Distributions = copy(source.sp64Distributions); - - this.ageTotals = copy(source.ageTotals); - this.dominantHeights = copy(source.dominantHeights); - this.percentagesOfForestedLand = copy(source.percentagesOfForestedLand); - this.siteIndices = copy(source.siteIndices); - this.yearsAtBreastHeight = copy(source.yearsAtBreastHeight); - this.yearsToBreastHeight = copy(source.yearsToBreastHeight); - - this.basalAreas = copy(source.basalAreas); - this.closeUtilizationVolumes = copy(source.closeUtilizationVolumes); - this.cuVolumesMinusDecay = copy(source.cuVolumesMinusDecay); - this.cuVolumesMinusDecayAndWastage = copy(source.cuVolumesMinusDecayAndWastage); - this.loreyHeights = copy(source.loreyHeights); - this.quadMeanDiameters = copy(source.quadMeanDiameters); - this.treesPerHectare = copy(source.treesPerHectare); - this.wholeStemVolumes = copy(source.wholeStemVolumes); - } - - public int getNSpecies() { - return nSpecies; - } - - int[] getIndices() { - return indices; - } - - BecDefinition getBecZone() { - return becZone; - } - - /** - * Refresh the values in the bank with an updated version (given) of the layer used to create the bank. The - * modifications cannot include any changes to the set of species, although the details of those species may of - * course change. - * - * @param layer a (presumably modified) version of the layer. - * @throws ProcessingException - */ - void refreshBank(VdypLayer layer) throws ProcessingException { - - if (!this.layer.equals(layer)) { - throw new IllegalArgumentException( - MessageFormat.format( - "One cannot refresh a bank from a" - + " layer ({0}) different from the one used to create the bank ({1})", - this.layer, layer - ) - ); - } - - List species = layer.getSpecies().values().stream() - .sorted((s1, s2) -> s1.getGenusIndex() - s2.getGenusIndex()).toList(); - - transferUtilizationSetIntoBank(0, layer); - - int nextSlot = 1; - for (VdypSpecies s : species) { - transferSpeciesIntoBank(nextSlot++, s); - } - } - - private void transferSpeciesIntoBank(int index, VdypSpecies species) { - - speciesNames[index] = species.getGenus(); - sp64Distributions[index] = species.getSp64DistributionSet(); - speciesIndices[index] = species.getGenusIndex(); - - species.getSite().ifPresentOrElse(s -> { - siteIndices[index] = s.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE); - dominantHeights[index] = s.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); - ageTotals[index] = s.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); - yearsToBreastHeight[index] = s.getYearsToBreastHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); - if (ageTotals[index] != VdypEntity.MISSING_FLOAT_VALUE - && yearsToBreastHeight[index] != VdypEntity.MISSING_FLOAT_VALUE) { - yearsAtBreastHeight[index] = ageTotals[index] - yearsToBreastHeight[index]; - } else { - yearsAtBreastHeight[index] = VdypEntity.MISSING_FLOAT_VALUE; - } - siteCurveNumbers[index] = s.getSiteCurveNumber().orElse(VdypEntity.MISSING_INTEGER_VALUE); - // percentForestedLand is output-only and so not assigned here. - }, () -> { - siteIndices[index] = VdypEntity.MISSING_FLOAT_VALUE; - dominantHeights[index] = VdypEntity.MISSING_FLOAT_VALUE; - ageTotals[index] = VdypEntity.MISSING_FLOAT_VALUE; - yearsToBreastHeight[index] = VdypEntity.MISSING_FLOAT_VALUE; - yearsAtBreastHeight[index] = VdypEntity.MISSING_FLOAT_VALUE; - siteCurveNumbers[index] = VdypEntity.MISSING_INTEGER_VALUE; - }); - - transferUtilizationSetIntoBank(index, species); - } - - private void transferUtilizationSetIntoBank(int index, VdypUtilizationHolder uh) { - - for (UtilizationClass uc : UtilizationClass.values()) { - int ucIndex = uc.ordinal(); - basalAreas[index][ucIndex] = uh.getBaseAreaByUtilization().get(uc); - closeUtilizationVolumes[index][ucIndex] = uh.getCloseUtilizationVolumeByUtilization().get(uc); - cuVolumesMinusDecay[index][ucIndex] = uh.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc); - cuVolumesMinusDecayAndWastage[index][ucIndex] = uh - .getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc); - if (ucIndex < 2 /* only uc 0 and 1 have a lorey height */) { - loreyHeights[index][ucIndex] = uh.getLoreyHeightByUtilization().get(uc); - } - quadMeanDiameters[index][ucIndex] = uh.getQuadraticMeanDiameterByUtilization().get(uc); - treesPerHectare[index][ucIndex] = uh.getTreesPerHectareByUtilization().get(uc); - wholeStemVolumes[index][ucIndex] = uh.getWholeStemVolumeByUtilization().get(uc); - } - } - - /** - * For each species, set uc All to the sum of the UC values, UC 7.5 and above only, for the summable values, and - * calculate quad-mean-diameter from these values. - *

- * For the layer, set uc All values (for summable types) to the sum of those of the individual species and set the - * other uc values to the sum of those of the individual species. Calculate the uc All value for quad-mean-diameter, - * and the uc All and Small value for lorey-height. - */ - private void setCalculateUtilizationClassAllValues() { - - int layerIndex = 0; - int ucAllIndex = UtilizationClass.ALL.ordinal(); - int ucSmallIndex = UtilizationClass.SMALL.ordinal(); - - // Each species - - for (int sp0Index : indices) { - - basalAreas[sp0Index][ucAllIndex] = sumUtilizationClassValues( - basalAreas[sp0Index], UtilizationClass.UTIL_CLASSES - ); - treesPerHectare[sp0Index][ucAllIndex] = sumUtilizationClassValues( - treesPerHectare[sp0Index], UtilizationClass.UTIL_CLASSES - ); - wholeStemVolumes[sp0Index][ucAllIndex] = sumUtilizationClassValues( - wholeStemVolumes[sp0Index], UtilizationClass.UTIL_CLASSES - ); - closeUtilizationVolumes[sp0Index][ucAllIndex] = sumUtilizationClassValues( - closeUtilizationVolumes[sp0Index], UtilizationClass.UTIL_CLASSES - ); - cuVolumesMinusDecay[sp0Index][ucAllIndex] = sumUtilizationClassValues( - cuVolumesMinusDecay[sp0Index], UtilizationClass.UTIL_CLASSES - ); - cuVolumesMinusDecayAndWastage[sp0Index][ucAllIndex] = sumUtilizationClassValues( - cuVolumesMinusDecayAndWastage[sp0Index], UtilizationClass.UTIL_CLASSES - ); - - if (basalAreas[sp0Index][ucAllIndex] > 0.0f) { - quadMeanDiameters[sp0Index][ucAllIndex] = BaseAreaTreeDensityDiameter - .quadMeanDiameter(basalAreas[sp0Index][ucAllIndex], treesPerHectare[sp0Index][ucAllIndex]); - } - } - - // Layer - - basalAreas[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues(basalAreas, UtilizationClass.ALL); - treesPerHectare[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues( - treesPerHectare, UtilizationClass.ALL - ); - wholeStemVolumes[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues( - wholeStemVolumes, UtilizationClass.ALL - ); - closeUtilizationVolumes[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues( - closeUtilizationVolumes, UtilizationClass.ALL - ); - cuVolumesMinusDecay[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues( - cuVolumesMinusDecay, UtilizationClass.ALL - ); - cuVolumesMinusDecayAndWastage[layerIndex][ucAllIndex] = sumSpeciesUtilizationClassValues( - cuVolumesMinusDecayAndWastage, UtilizationClass.ALL - ); - - // Calculate the layer's uc All values for quad-mean-diameter and lorey height - - float sumLoreyHeightByBasalAreaSmall = 0.0f; - float sumBasalAreaSmall = 0.0f; - float sumLoreyHeightByBasalAreaAll = 0.0f; - - for (int sp0Index : indices) { - sumLoreyHeightByBasalAreaSmall += loreyHeights[sp0Index][ucSmallIndex] * basalAreas[sp0Index][ucSmallIndex]; - sumBasalAreaSmall += basalAreas[sp0Index][ucSmallIndex]; - sumLoreyHeightByBasalAreaAll += loreyHeights[sp0Index][ucAllIndex] * basalAreas[sp0Index][ucAllIndex]; - } - - if (basalAreas[layerIndex][ucAllIndex] > 0.0f) { - quadMeanDiameters[layerIndex][ucAllIndex] = BaseAreaTreeDensityDiameter - .quadMeanDiameter(basalAreas[layerIndex][ucAllIndex], treesPerHectare[layerIndex][ucAllIndex]); - loreyHeights[layerIndex][ucAllIndex] = sumLoreyHeightByBasalAreaAll / basalAreas[layerIndex][ucAllIndex]; - } - - // Calculate the layer's lorey height uc Small value - - if (sumBasalAreaSmall > 0.0f) { - loreyHeights[layerIndex][ucSmallIndex] = sumLoreyHeightByBasalAreaSmall / sumBasalAreaSmall; - } - - // Finally, set the layer's summable UC values (other than All, which was computed above) to - // the sums of those of each of the species. - - for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { - basalAreas[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues(basalAreas, uc); - treesPerHectare[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues(treesPerHectare, uc); - wholeStemVolumes[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues(wholeStemVolumes, uc); - closeUtilizationVolumes[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues( - closeUtilizationVolumes, uc - ); - cuVolumesMinusDecay[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues(cuVolumesMinusDecay, uc); - cuVolumesMinusDecayAndWastage[layerIndex][uc.ordinal()] = sumSpeciesUtilizationClassValues( - cuVolumesMinusDecayAndWastage, uc - ); - } - } - - private float sumUtilizationClassValues(float[] ucValues, List subjects) { - float sum = 0.0f; - - for (UtilizationClass uc : UtilizationClass.values()) { - if (subjects.contains(uc)) { - sum += ucValues[uc.ordinal()]; - } - } - - return sum; - } - - private float sumSpeciesUtilizationClassValues(float[][] ucValues, UtilizationClass uc) { - float sum = 0.0f; - - for (int sp0Index : this.indices) { - sum += ucValues[sp0Index][uc.ordinal()]; - } - - return sum; - } - - /** - * This method copies the Bank contents out to the VdypLayer instance used to create it and returns that. It is a - * relatively expensive operation and should not be called without due consideration. - * - * @return as described - */ - VdypLayer buildLayerFromBank() { - - transferUtilizationsFromBank(0, layer); - - Collection newSpecies = new ArrayList<>(); - for (int i : indices) { - newSpecies.add(transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i]))); - } - layer.setSpecies(newSpecies); - - return layer; - } - - private VdypSpecies transferSpeciesFromBank(int index, VdypSpecies species) { - - VdypSpecies newSpecies = VdypSpecies.build(speciesBuilder -> { - speciesBuilder.copy(species); - speciesBuilder.percentGenus(this.percentagesOfForestedLand[index]); - species.getSite().ifPresentOrElse(site -> speciesBuilder.addSite(VdypSite.build(siteBuilder -> { - siteBuilder.copy(site); - siteBuilder.siteGenus(this.speciesNames[index]); - siteBuilder.ageTotal(Utils.optFloat(ageTotals[index])); - siteBuilder.height(Utils.optFloat(this.dominantHeights[index])); - siteBuilder.siteCurveNumber(Utils.optInt(this.siteCurveNumbers[index])); - siteBuilder.siteIndex(Utils.optFloat(this.siteIndices[index])); - siteBuilder.yearsToBreastHeight(Utils.optFloat(this.yearsToBreastHeight[index])); - })), () -> { - VdypSite site = VdypSite.build(siteBuilder -> { - siteBuilder.polygonIdentifier(species.getPolygonIdentifier()); - siteBuilder.layerType(species.getLayerType()); - siteBuilder.siteGenus(this.speciesNames[index]); - siteBuilder.ageTotal(Utils.optFloat(this.ageTotals[index])); - siteBuilder.height(Utils.optFloat(this.dominantHeights[index])); - siteBuilder.siteCurveNumber(Utils.optInt(this.siteCurveNumbers[index])); - siteBuilder.siteIndex(Utils.optFloat(this.siteIndices[index])); - siteBuilder.yearsToBreastHeight(Utils.optFloat(this.yearsToBreastHeight[index])); - }); - - speciesBuilder.addSite(site); - }); - }); - - transferUtilizationsFromBank(index, newSpecies); - - return newSpecies; - } - - private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { - - for (UtilizationClass uc : UtilizationClass.values()) { - int ucIndex = uc.ordinal(); - uh.getBaseAreaByUtilization().set(uc, basalAreas[index][ucIndex]); - uh.getCloseUtilizationVolumeByUtilization().set(uc, closeUtilizationVolumes[index][ucIndex]); - uh.getCloseUtilizationVolumeNetOfDecayByUtilization().set(uc, cuVolumesMinusDecay[index][ucIndex]); - uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .set(uc, cuVolumesMinusDecayAndWastage[index][ucIndex]); - if (ucIndex < 2 /* only uc 0 and 1 have a lorey height */) { - uh.getLoreyHeightByUtilization().set(uc, loreyHeights[index][ucIndex]); - } - uh.getQuadraticMeanDiameterByUtilization().set(uc, quadMeanDiameters[index][ucIndex]); - uh.getTreesPerHectareByUtilization().set(uc, treesPerHectare[index][ucIndex]); - uh.getWholeStemVolumeByUtilization().set(uc, wholeStemVolumes[index][ucIndex]); - } - } - - public Bank copy() { - return new Bank(this); - } - - private String[] copy(String[] a) { - return Arrays.stream(a).toArray(String[]::new); - } - - private int[] copy(int[] a) { - int[] t = new int[a.length]; - - System.arraycopy(a, 0, t, 0, a.length); - - return t; - } - - private float[] copy(float[] a) { - float[] t = new float[a.length]; - - System.arraycopy(a, 0, t, 0, a.length); - - return t; - } - - private float[][] copy(float[][] a) { - return Arrays.stream(a).map(float[]::clone).toArray(float[][]::new); - } - - private Sp64DistributionSet[] copy(Sp64DistributionSet[] sp64Distributions) { - return Arrays.stream(sp64Distributions).map(s -> s == null ? null : s.copy()) - .toArray(Sp64DistributionSet[]::new); - } -} \ No newline at end of file diff --git a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index a3425ea5a..2421dc74e 100644 --- a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -66,6 +66,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; +import ca.bc.gov.nrs.vdyp.processing_state.Bank; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; /** diff --git a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 60247c49c..9658b589a 100644 --- a/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -18,6 +18,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; +import ca.bc.gov.nrs.vdyp.processing_state.Bank; class LayerProcessingState { diff --git a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow10StoreSpeciesDetails.java b/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow10StoreSpeciesDetails.java index 151d71b02..ca2fcaa0d 100644 --- a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow10StoreSpeciesDetails.java +++ b/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow10StoreSpeciesDetails.java @@ -22,6 +22,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; +import ca.bc.gov.nrs.vdyp.processing_state.Bank; class Grow10StoreSpeciesDetails { diff --git a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/ForwardTestUtils.java b/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/ForwardTestUtils.java index 8f3e2b11b..e02234555 100644 --- a/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/ForwardTestUtils.java +++ b/lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/ForwardTestUtils.java @@ -118,174 +118,4 @@ public static void setGrowthTargetYear(ForwardProcessingState fps, int targetYea } } - public static VdypLayer normalizeLayer(VdypLayer layer) { - - // Set uc All to the sum of the UC values, UC 7.5 and above only, for the summable - // values, and calculate quad-mean-diameter from these values. - - UtilizationClass ucAll = UtilizationClass.ALL; - UtilizationClass ucSmall = UtilizationClass.SMALL; - - for (var species : layer.getSpecies().values()) { - - species.getBaseAreaByUtilization().set( - ucAll, sumUtilizationClassValues(species.getBaseAreaByUtilization(), UtilizationClass.UTIL_CLASSES) - ); - species.getTreesPerHectareByUtilization().set( - ucAll, - sumUtilizationClassValues(species.getTreesPerHectareByUtilization(), UtilizationClass.UTIL_CLASSES) - ); - species.getWholeStemVolumeByUtilization().set( - ucAll, - sumUtilizationClassValues(species.getWholeStemVolumeByUtilization(), UtilizationClass.UTIL_CLASSES) - ); - species.getCloseUtilizationVolumeByUtilization().set( - ucAll, - sumUtilizationClassValues( - species.getCloseUtilizationVolumeByUtilization(), UtilizationClass.UTIL_CLASSES - ) - ); - species.getCloseUtilizationVolumeNetOfDecayByUtilization().set( - ucAll, - sumUtilizationClassValues( - species.getCloseUtilizationVolumeNetOfDecayByUtilization(), UtilizationClass.UTIL_CLASSES - ) - ); - species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set( - ucAll, - sumUtilizationClassValues( - species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), - UtilizationClass.UTIL_CLASSES - ) - ); - - if (species.getBaseAreaByUtilization().get(ucAll) > 0.0f) { - species.getQuadraticMeanDiameterByUtilization().set( - ucAll, - BaseAreaTreeDensityDiameter.quadMeanDiameter( - species.getBaseAreaByUtilization().get(ucAll), - species.getTreesPerHectareByUtilization().get(ucAll) - ) - ); - } - } - - // Set the layer's uc All values (for summable types) to the sum of those of the - // individual species. - - layer.getBaseAreaByUtilization() - .set(ucAll, sumSpeciesUtilizationClassValues(layer, "BaseArea", UtilizationClass.ALL)); - layer.getTreesPerHectareByUtilization() - .set(ucAll, sumSpeciesUtilizationClassValues(layer, "TreesPerHectare", UtilizationClass.ALL)); - layer.getWholeStemVolumeByUtilization() - .set(ucAll, sumSpeciesUtilizationClassValues(layer, "WholeStemVolume", UtilizationClass.ALL)); - layer.getCloseUtilizationVolumeByUtilization() - .set(ucAll, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolume", UtilizationClass.ALL)); - layer.getCloseUtilizationVolumeNetOfDecayByUtilization().set( - ucAll, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecay", UtilizationClass.ALL) - ); - layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set( - ucAll, - sumSpeciesUtilizationClassValues( - layer, "CloseUtilizationVolumeNetOfDecayAndWaste", UtilizationClass.ALL - ) - ); - - // Calculate the layer's uc All values for quad-mean-diameter and lorey height - - float sumLoreyHeightByBasalAreaSmall = 0.0f; - float sumBasalAreaSmall = 0.0f; - float sumLoreyHeightByBasalAreaAll = 0.0f; - - for (var species : layer.getSpecies().values()) { - sumLoreyHeightByBasalAreaSmall += species.getLoreyHeightByUtilization().get(ucSmall) - * species.getBaseAreaByUtilization().get(ucSmall); - sumBasalAreaSmall += species.getBaseAreaByUtilization().get(ucSmall); - sumLoreyHeightByBasalAreaAll += species.getLoreyHeightByUtilization().get(ucAll) - * species.getBaseAreaByUtilization().get(ucAll); - } - - if (layer.getBaseAreaByUtilization().get(ucAll) > 0.0f) { - layer.getQuadraticMeanDiameterByUtilization().set( - ucAll, - BaseAreaTreeDensityDiameter.quadMeanDiameter( - layer.getBaseAreaByUtilization().get(ucAll), - layer.getTreesPerHectareByUtilization().get(ucAll) - ) - ); - layer.getLoreyHeightByUtilization() - .set(ucAll, sumLoreyHeightByBasalAreaAll / layer.getBaseAreaByUtilization().get(ucAll)); - } - - // Calculate the layer's lorey height uc Small value - - if (sumBasalAreaSmall > 0.0f) { - layer.getLoreyHeightByUtilization().set(ucSmall, sumLoreyHeightByBasalAreaSmall / sumBasalAreaSmall); - } - - // Finally, set the layer's summable UC values (other than All, which was computed above) to - // the sums of those of each of the species. - - for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { - layer.getBaseAreaByUtilization().set(uc, sumSpeciesUtilizationClassValues(layer, "BaseArea", uc)); - layer.getTreesPerHectareByUtilization() - .set(uc, sumSpeciesUtilizationClassValues(layer, "TreesPerHectare", uc)); - layer.getWholeStemVolumeByUtilization() - .set(uc, sumSpeciesUtilizationClassValues(layer, "WholeStemVolume", uc)); - layer.getCloseUtilizationVolumeByUtilization() - .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolume", uc)); - layer.getCloseUtilizationVolumeNetOfDecayByUtilization() - .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecay", uc)); - layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .set(uc, sumSpeciesUtilizationClassValues(layer, "CloseUtilizationVolumeNetOfDecayAndWaste", uc)); - } - - return layer; - } - - private static float sumUtilizationClassValues(UtilizationVector ucValues, List subjects) { - float sum = 0.0f; - - for (UtilizationClass uc : UtilizationClass.values()) { - if (subjects.contains(uc)) { - sum += ucValues.get(uc); - } - } - - return sum; - } - - private static float sumSpeciesUtilizationClassValues(VdypLayer layer, String uvName, UtilizationClass uc) { - float sum = 0.0f; - - for (VdypSpecies species : layer.getSpecies().values()) { - switch (uvName) { - case "CloseUtilizationVolumeNetOfDecayWasteAndBreakage": - sum += species.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().get(uc); - break; - case "CloseUtilizationVolumeNetOfDecayAndWaste": - sum += species.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc); - break; - case "CloseUtilizationVolumeNetOfDecay": - sum += species.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc); - break; - case "CloseUtilizationVolume": - sum += species.getCloseUtilizationVolumeByUtilization().get(uc); - break; - case "WholeStemVolume": - sum += species.getWholeStemVolumeByUtilization().get(uc); - break; - case "TreesPerHectare": - sum += species.getTreesPerHectareByUtilization().get(uc); - break; - case "BaseArea": - sum += species.getBaseAreaByUtilization().get(uc); - break; - default: - throw new IllegalStateException(uvName + " is not a known utilization vector name"); - } - } - - return sum; - } }