Skip to content

Commit

Permalink
Further Forward changes - possibly complete?
Browse files Browse the repository at this point in the history
  • Loading branch information
mjunkin committed Oct 8, 2024
1 parent 474cf84 commit 4548791
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ public void estimateWholeStemVolume(
UtilizationVector wholeStemVolumeUtil
) throws ProcessingException {
var wholeStemUtilizationComponentMap = controlMap.getWholeStemUtilizationComponentMap();
var dqSp = quadMeanDiameterUtil.getAll();
var spDqAll = quadMeanDiameterUtil.getAll();

estimateUtilization(baseAreaUtil, wholeStemVolumeUtil, utilizationClass, (uc, ba) -> {
Coefficients wholeStemCoe = wholeStemUtilizationComponentMap.get(uc.index, volumeGroup).orElseThrow(
Expand All @@ -565,7 +565,7 @@ public void estimateWholeStemVolume(
var a3 = wholeStemCoe.getCoe(3);

var arg = a0 + a1 * log(hlSp) + a2 * log(quadMeanDiameterUtil.getCoe(uc.index))
+ ( (uc != UtilizationClass.OVER225) ? a3 * log(dqSp) : a3 * dqSp);
+ ( (uc != UtilizationClass.OVER225) ? a3 * log(spDqAll) : a3 * spDqAll);

if (uc == utilizationClass) {
arg += adjustCloseUtil;
Expand Down Expand Up @@ -806,7 +806,7 @@ public void estimateNetDecayWasteAndBreakageVolume(
* EMP106 - estimate basal area yield for the primary layer (from IPSJF160.doc)
*
* @param estimateBasalAreaYieldCoefficients estimate basal area yield coefficients
* @param controlVariable2Setting the value of control variable 2
* @param debugSetting2Value the value of debug setting 2
* @param dominantHeight dominant height (m)
* @param breastHeightAge breast height age (years)
* @param veteranBaseArea basal area of overstory (>= 0)
Expand All @@ -817,7 +817,7 @@ public void estimateNetDecayWasteAndBreakageVolume(
* @throws StandProcessingException
*/
public float estimateBaseAreaYield(
Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight,
Coefficients estimateBasalAreaYieldCoefficients, int debugSetting2Value, float dominantHeight,
float breastHeightAge, Optional<Float> veteranBasalArea, boolean fullOccupancy, float upperBoundBasalArea
) throws StandProcessingException {

Expand All @@ -839,8 +839,8 @@ public float estimateBaseAreaYield(

float ageToUse = breastHeightAge;

if (controlVariable2Setting > 0) {
ageToUse = Math.min(ageToUse, controlVariable2Setting * 100f);
if (debugSetting2Value > 0) {
ageToUse = Math.min(ageToUse, debugSetting2Value * 100f);
}

if (ageToUse <= 0f) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
import ca.bc.gov.nrs.vdyp.common.ControlKey;
import ca.bc.gov.nrs.vdyp.common.Utils;
import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter;
import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl;
import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap;
import ca.bc.gov.nrs.vdyp.io.FileResolver;
import ca.bc.gov.nrs.vdyp.math.FloatMath;
import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies;
import ca.bc.gov.nrs.vdyp.model.BecDefinition;
import ca.bc.gov.nrs.vdyp.model.LayerType;
import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier;
import ca.bc.gov.nrs.vdyp.model.PolygonMode;
Expand All @@ -36,6 +40,8 @@ public class VdypOutputWriter implements Closeable {
@SuppressWarnings("unused")
private Optional<OutputStream> compatibilityVariablesFile;

private ResolvedControlMap controlMap;

private Optional<Integer> currentYear = Optional.empty();

static final String POLY_IDENTIFIER_FORMAT = "%-25s";
Expand Down Expand Up @@ -69,31 +75,36 @@ public class VdypOutputWriter implements Closeable {
/**
* Create a writer for Vdyp output files using provided OutputStreams. The Streams will be closed when the writer is
* closed.
*
*
* @param controlMap
* @param polygonFile
* @param speciesFile
* @param utilizationFile
* @param compatibilityVariablesFile
* @param controlMap
*/
public VdypOutputWriter(OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile) {
this(polygonFile, speciesFile, utilizationFile, Optional.empty());
public VdypOutputWriter(
Map<String, Object> controlMap, OutputStream polygonFile, OutputStream speciesFile,
OutputStream utilizationFile
) {
this(controlMap, polygonFile, speciesFile, utilizationFile, Optional.empty());
}

/**
* Create a writer for Vdyp output files using provided OutputStreams. The Streams will be closed when the writer is
* closed.
*
*
* @param controlMap
* @param polygonFile
* @param speciesFile
* @param utilizationFile
* @param compatibilityVariablesFile
* @param controlMap
*/
public VdypOutputWriter(
OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile,
Optional<OutputStream> compatibilityVariablesFile
Map<String, Object> controlMap, OutputStream polygonFile, OutputStream speciesFile,
OutputStream utilizationFile, Optional<OutputStream> compatibilityVariablesFile
) {
this.controlMap = new CachingResolvedControlMapImpl(controlMap);
this.polygonFile = polygonFile;
this.speciesFile = speciesFile;
this.utilizationFile = utilizationFile;
Expand All @@ -110,7 +121,7 @@ public VdypOutputWriter(
*/
public VdypOutputWriter(Map<String, Object> controlMap, FileResolver resolver) throws IOException {
this(
getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name()),
controlMap, getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name()),
getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name()),
getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()),
controlMap.containsKey(ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) ? Optional.of(
Expand Down Expand Up @@ -149,6 +160,13 @@ public void writePolygonWithSpeciesAndUtilization(VdypPolygon polygon) throws IO
// Primary then Veteran (if present)
var sortedLayers = polygon.getLayers().values().stream()
.sorted((l1, l2) -> l1.getLayerType().getIndex() - l2.getLayerType().getIndex()).toList();

// The original VDYP7 system performs this task at this location, storing the result in
// a separate COMMON. Here, we store the result in the Polygon, knowing that the originally
// calculated values are not being used.
sortedLayers.stream()
.forEach(l -> calculateCuVolumeLessDecayWastageBreakage(l, polygon.getBiogeoclimaticZone()));

for (var layer : sortedLayers) {
writeUtilization(polygon, layer, layer);
List<VdypSpecies> specs = new ArrayList<>(layer.getSpecies().size());
Expand All @@ -163,6 +181,58 @@ public void writePolygonWithSpeciesAndUtilization(VdypPolygon polygon) throws IO
writeUtilizationEndRecord(polygon);
}

private void calculateCuVolumeLessDecayWastageBreakage(VdypLayer layer, BecDefinition bec) {

for (VdypSpecies s : layer.getSpecies().values()) {

String sp0 = s.getGenus();
var breakageEquationGroup = controlMap.getBreakageEquationGroups().get(sp0, bec.getAlias());

var breakageCoefficients = controlMap.getNetBreakageMap().get(breakageEquationGroup);
var a1 = breakageCoefficients.getCoe(1);
var a2 = breakageCoefficients.getCoe(2);
var a3 = breakageCoefficients.getCoe(3);
var a4 = breakageCoefficients.getCoe(4);

var speciesCuVolumeLessDWBByUtilization = s
.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization();

var speciesCuVolumeLessDWBSum = 0.0f;
for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) {
var ba = s.getBaseAreaByUtilization().get(uc);
var tph = s.getTreesPerHectareByUtilization().get(uc);
var dq = (ba > 0) ? BaseAreaTreeDensityDiameter.quadMeanDiameter(ba, tph) : 0.0f;
var cuVolume = s.getCloseUtilizationVolumeByUtilization().get(uc);
var cuVolumeLessDW = s.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc);

var breakagePercent = FloatMath.clamp(a1 + a2 * FloatMath.log(dq), a3, a4);
var breakage = Math.min(breakagePercent / 100.0f * cuVolume, cuVolumeLessDW);
if (cuVolumeLessDW <= 0.0f) {
speciesCuVolumeLessDWBByUtilization.set(uc, 0.0f);
} else {
var cuVolumeLessDWBforUc = cuVolumeLessDW - breakage;
speciesCuVolumeLessDWBByUtilization.set(uc, cuVolumeLessDWBforUc);
speciesCuVolumeLessDWBSum += cuVolumeLessDWBforUc;
}
}

speciesCuVolumeLessDWBByUtilization.set(UtilizationClass.SMALL, 0.0f);
speciesCuVolumeLessDWBByUtilization.set(UtilizationClass.ALL, speciesCuVolumeLessDWBSum);
}

var layerCuVolumeLessDWBByUtilization = layer
.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization();
for (UtilizationClass uc : UtilizationClass.values()) {
var layerCuVolumeLessDWBSum = 0.0f;
for (VdypSpecies s : layer.getSpecies().values()) {
var speciesCuVolumeLessDWBByUtilization = s
.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization();
layerCuVolumeLessDWBSum += speciesCuVolumeLessDWBByUtilization.get(uc);
}
layerCuVolumeLessDWBByUtilization.set(uc, layerCuVolumeLessDWBSum);
}
}

static OutputStream getOutputStream(Map<String, Object> controlMap, FileResolver resolver, String key)
throws IOException {
String fileName = Utils.expectParsedControl(controlMap, key, String.class);
Expand Down Expand Up @@ -250,10 +320,10 @@ void writeSpecies(VdypLayer layer, VdypSpecies spec) throws IOException {
*
* @param polygon
* @param layer
* @return
* @return if layer is PRIMARY, the polygon's precentage available or else (VETERAN) return 1.0.
*/
protected float fractionForest(VdypPolygon polygon, VdypLayer layer) {
return polygon.getPercentAvailable() / 100f;
return LayerType.PRIMARY.equals(layer.getLayerType()) ? polygon.getPercentAvailable() / 100f : 1.0f;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void initStreams() {
@Test
void testClosesGivenStreams() throws IOException {

var unit = new VdypOutputWriter(polyStream, specStream, utilStream);
var unit = new VdypOutputWriter(controlMap, polyStream, specStream, utilStream);

unit.close();

Expand Down
Loading

0 comments on commit 4548791

Please sign in to comment.