Skip to content

Commit

Permalink
Consolidate Bank in common
Browse files Browse the repository at this point in the history
  • Loading branch information
smithkm committed Oct 18, 2024
1 parent 1082ad4 commit 03685e9
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 674 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ public int getNSpecies() {
return nSpecies;
}

int[] getIndices() {
public int[] getIndices() {
return indices;
}

BecDefinition getBecZone() {
public BecDefinition getBecZone() {
return becZone;
}

Expand All @@ -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(
Expand Down Expand Up @@ -365,7 +365,7 @@ private float sumSpeciesUtilizationClassValues(float[][] ucValues, UtilizationCl
*
* @return as described
*/
VdypLayer buildLayerFromBank() {
public VdypLayer buildLayerFromBank() {

transferUtilizationsFromBank(0, layer);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,80 @@
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;

import java.io.IOException;
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<String, Object> 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());

Expand Down Expand Up @@ -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();
Expand All @@ -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());

Expand All @@ -154,34 +173,26 @@ 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());

Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true);

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

Expand Down
Original file line number Diff line number Diff line change
@@ -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<UtilizationClass> 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;
}
}
Loading

0 comments on commit 03685e9

Please sign in to comment.