Skip to content

Commit

Permalink
Merge pull request #57 from bcgov/feature/VDYP-306
Browse files Browse the repository at this point in the history
VDYP-306  Veteran Layer Processing for VRIStart
  • Loading branch information
mjunkin authored Aug 28, 2024
2 parents 60006f6 + d7debb0 commit fc7729a
Show file tree
Hide file tree
Showing 11 changed files with 719 additions and 6,709 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,12 @@ protected void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer)
});
var ba = vdypLayer.getBaseAreaByUtilization();
hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x);

// Update percent based on updated areas
vdypLayer.getSpecies().values().stream().forEach(spec -> {
spec.setPercentGenus(100 * spec.getBaseAreaByUtilization().getAll() / ba.getAll());
});

vdypLayer.setLoreyHeightByUtilization(hlVector);
}
// Quadratic mean diameter for the layer is computed from the BA and TPH after
Expand All @@ -1370,6 +1376,7 @@ protected void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer)
);
vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector);
}

}

// TODO De-reflectify this when we want to make it work in GralVM
Expand Down Expand Up @@ -1400,4 +1407,131 @@ protected void scaleAllSummableUtilization(VdypUtilizationHolder holder, float f
}
}

// YUCV
protected void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinition bec)
throws ProcessingException {
log.trace(
"computeUtilizationComponentsVeteran for {}, stand total age is {}", vdypLayer.getPolygonIdentifier(),
vdypLayer.getAgeTotal()
);

var volumeAdjustMap = Utils.<Map<String, Coefficients>>expectParsedControl(
controlMap, ControlKey.VETERAN_LAYER_VOLUME_ADJUST, java.util.Map.class
);
try {
for (var vdypSpecies : vdypLayer.getSpecies().values()) {

var treesPerHectareUtil = Utils.utilizationVector();
var quadMeanDiameterUtil = Utils.utilizationVector();
var baseAreaUtil = Utils.utilizationVector();
var wholeStemVolumeUtil = Utils.utilizationVector();

var closeUtilizationVolumeUtil = Utils.utilizationVector();
var closeUtilizationNetOfDecayUtil = Utils.utilizationVector();
var closeUtilizationNetOfDecayAndWasteUtil = Utils.utilizationVector();
var closeUtilizationNetOfDecayWasteAndBreakageUtil = Utils.utilizationVector();

var hlSp = vdypSpecies.getLoreyHeightByUtilization().getAll();
{
var baSp = vdypSpecies.getBaseAreaByUtilization().getLarge();
var tphSp = vdypSpecies.getTreesPerHectareByUtilization().getLarge();
var dqSp = vdypSpecies.getQuadraticMeanDiameterByUtilization().getLarge();

treesPerHectareUtil.setAll(tphSp);
quadMeanDiameterUtil.setAll(dqSp);
baseAreaUtil.setAll(baSp);
wholeStemVolumeUtil.setAll(0f);

treesPerHectareUtil.setLarge(tphSp);
quadMeanDiameterUtil.setLarge(dqSp);
baseAreaUtil.setLarge(baSp);
wholeStemVolumeUtil.setLarge(0f);
}
// AADJUSTV
var volumeAdjustCoe = volumeAdjustMap.get(vdypSpecies.getGenus());

var utilizationClass = UtilizationClass.OVER225; // IUC_VET

// ADJ
var adjust = new Coefficients(new float[] { 0f, 0f, 0f, 0f }, 1);

// EMP091
EstimationMethods.estimateWholeStemVolume(
controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp,
quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil
);

adjust.setCoe(4, volumeAdjustCoe.getCoe(2));
// EMP092
EstimationMethods.estimateCloseUtilizationVolume(
controlMap, utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil,
wholeStemVolumeUtil, closeUtilizationVolumeUtil
);

adjust.setCoe(4, volumeAdjustCoe.getCoe(3));
// EMP093
EstimationMethods.estimateNetDecayVolume(
controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust,
vdypSpecies.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil,
closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil
);

adjust.setCoe(4, volumeAdjustCoe.getCoe(4));
// EMP094
final var netDecayCoeMap = Utils.<Map<String, Coefficients>>expectParsedControl(
controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, java.util.Map.class
);
final var wasteModifierMap = Utils.<MatrixMap2<String, Region, Float>>expectParsedControl(
controlMap, ControlKey.WASTE_MODIFIERS, ca.bc.gov.nrs.vdyp.model.MatrixMap2.class
);
EstimationMethods.estimateNetDecayAndWasteVolume(
bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, netDecayCoeMap,
wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil,
closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil
);

if (getId().isStart()) {
// EMP095
EstimationMethods.estimateNetDecayWasteAndBreakageVolume(
controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil,
closeUtilizationVolumeUtil, closeUtilizationNetOfDecayAndWasteUtil,
closeUtilizationNetOfDecayWasteAndBreakageUtil
);
}

vdypSpecies.setBaseAreaByUtilization(baseAreaUtil);
vdypSpecies.setTreesPerHectareByUtilization(treesPerHectareUtil);
vdypSpecies.setQuadraticMeanDiameterByUtilization(quadMeanDiameterUtil);
vdypSpecies.setWholeStemVolumeByUtilization(wholeStemVolumeUtil);
vdypSpecies.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeUtil);
vdypSpecies.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetOfDecayUtil);
vdypSpecies.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(
closeUtilizationNetOfDecayAndWasteUtil
);
vdypSpecies.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(
closeUtilizationNetOfDecayWasteAndBreakageUtil
);

for (var accessors : UTILIZATION_VECTOR_ACCESSORS) {
UtilizationVector utilVector = (UtilizationVector) accessors.getReadMethod().invoke(vdypSpecies);

// Set all components other than 4 to 0.0
for (var uc : UtilizationClass.ALL_BUT_LARGEST) {
utilVector.set(uc, 0f);
}

// Set component 0 to equal component 4.
utilVector.setAll(utilVector.getLarge());

accessors.getWriteMethod().invoke(vdypSpecies, utilVector);
}
}

computeLayerUtilizationComponentsFromSpecies(vdypLayer);

} catch (IllegalAccessException | InvocationTargetException ex) {
throw new IllegalStateException(ex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.causedBy;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.closeTo;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.notPresent;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.utilization;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.utilizationAllAndBiggest;
import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.utilizationHeight;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
Expand Down Expand Up @@ -1327,6 +1330,147 @@ void testEstimate() throws ProcessingException, IOException {
}
}

@Nested
class VeteranUtilization {
@Test
void testCompute() throws ProcessingException, IOException {
controlMap = TestUtils.loadControlMap();
var bec = Utils.getBec("IDF", controlMap);
try (var app = new TestStartApplication(controlMap, false)) {
ApplicationTestUtils.setControlMap(app, controlMap);

var layer = VdypLayer.build(lb -> {
lb.polygonIdentifier("Test", 2024);
lb.layerType(LayerType.VETERAN);
lb.inventoryTypeGroup(14);
lb.addSpecies(sb -> {
sb.genus("B", controlMap);
sb.percentGenus(20f);

sb.volumeGroup(15);
sb.decayGroup(11);
sb.breakageGroup(4);

sb.loreyHeight(34f);
sb.baseArea(4f);
sb.treesPerHectare(24.199366f);
sb.quadMeanDiameter(45.87574f);

sb.addSp64Distribution("BL", 100);
});
lb.addSpecies(sb -> {
sb.genus("C", controlMap);
sb.percentGenus(30f);

sb.volumeGroup(23);
sb.decayGroup(15);
sb.breakageGroup(10);

sb.loreyHeight(30f);
sb.baseArea(6f);
sb.treesPerHectare(40.991108f);
sb.quadMeanDiameter(43.17038f);

sb.addSp64Distribution("CW", 100);
});
lb.addSpecies(sb -> {
sb.genus("H", controlMap);
sb.percentGenus(50f);

sb.volumeGroup(40);
sb.decayGroup(33);
sb.breakageGroup(19);

sb.loreyHeight(34f);
sb.baseArea(10f);
sb.treesPerHectare(57.809525f);
sb.quadMeanDiameter(46.93052f);

sb.addSite(siteBuilder -> {
siteBuilder.ageTotal(200f);
siteBuilder.yearsToBreastHeight(9.7f);
siteBuilder.height(34f);
siteBuilder.siteCurveNumber(37);
siteBuilder.siteIndex(14.6f);
});

});

});

app.computeUtilizationComponentsVeteran(layer, bec);

VdypSpecies resultSpecB = TestUtils.assertHasSpecies(layer, "B", "C", "H");

assertThat(resultSpecB, hasProperty("percentGenus", closeTo(20f)));

assertThat(resultSpecB, hasProperty("loreyHeightByUtilization", utilizationHeight(0f, 34f)));
assertThat(resultSpecB, hasProperty("baseAreaByUtilization", utilizationAllAndBiggest(4f)));
assertThat(
resultSpecB,
hasProperty("quadraticMeanDiameterByUtilization", utilizationAllAndBiggest(45.8757401f))
);
assertThat(
resultSpecB, hasProperty("treesPerHectareByUtilization", utilizationAllAndBiggest(24.1993656f))
);

assertThat(
resultSpecB, hasProperty("wholeStemVolumeByUtilization", utilizationAllAndBiggest(47.5739288f))
);
assertThat(
resultSpecB,
hasProperty("closeUtilizationVolumeByUtilization", utilizationAllAndBiggest(45.9957237f))
);
assertThat(
resultSpecB,
hasProperty(
"closeUtilizationVolumeNetOfDecayByUtilization", utilizationAllAndBiggest(39.5351295f)
)
);
assertThat(
resultSpecB,
hasProperty(
"closeUtilizationVolumeNetOfDecayAndWasteByUtilization",
utilizationAllAndBiggest(37.830616f)
)
);
assertThat(
resultSpecB,
hasProperty(
"closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization",
utilizationAllAndBiggest(36.8912659f)
)
);

assertThat(layer, hasProperty("ageTotal", present(closeTo(200))));
assertThat(layer, hasProperty("breastHeightAge", present(closeTo(190.3f))));
assertThat(layer, hasProperty("yearsToBreastHeight", present(closeTo(9.7f))));

assertThat(layer, hasProperty("siteGenus", present(is("H"))));

assertThat(layer, hasProperty("height", present(closeTo(34f))));
assertThat(layer, hasProperty("inventoryTypeGroup", present(is(14)))); // ?
assertThat(layer, hasProperty("empiricalRelationshipParameterIndex", notPresent())); // ?

assertThat(layer, hasProperty("loreyHeightByUtilization", utilizationHeight(0f, 32.8f)));
assertThat(layer, hasProperty("baseAreaByUtilization", utilizationAllAndBiggest(20f)));
assertThat(
layer, hasProperty("quadraticMeanDiameterByUtilization", utilizationAllAndBiggest(45.5006409f))
);
assertThat(layer, hasProperty("treesPerHectareByUtilization", utilizationAllAndBiggest(123f)));

assertThat(
layer,
hasProperty(
"closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization",
utilizationAllAndBiggest(167.61972f)
)
);

}
}
}

@Nested
class ApplyGroups {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,10 @@ public static Matcher<PolygonIdentifier> isPolyId(String base, int year) {
return allOf(instanceOf(PolygonIdentifier.class), hasProperty("base", is(base)), hasProperty("year", is(year)));
}

public static Matcher<BecDefinition> isBec(String alias) {
return allOf(instanceOf(BecDefinition.class), hasProperty("alias", is(alias)));
}

public static Matcher<Coefficients>
utilization(float small, float all, float util1, float util2, float util3, float util4) {
return new TypeSafeDiagnosingMatcher<Coefficients>() {
Expand Down
Loading

0 comments on commit fc7729a

Please sign in to comment.