Skip to content

Commit

Permalink
Merge branch 'main' into feature/VDYP-400-grow-qmd+lh
Browse files Browse the repository at this point in the history
# Conflicts:
#	vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java
#	vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java
#	vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java
#	vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java
#	vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java
#	vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java
  • Loading branch information
mjunkin committed Sep 10, 2024
2 parents c60977f + 34c530e commit 210d841
Show file tree
Hide file tree
Showing 15 changed files with 376 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

import ca.bc.gov.nrs.vdyp.common.ControlKey;
import ca.bc.gov.nrs.vdyp.io.FileResolver;
import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies;
import ca.bc.gov.nrs.vdyp.model.LayerType;
import ca.bc.gov.nrs.vdyp.model.PolygonMode;
import ca.bc.gov.nrs.vdyp.model.Sp64Distribution;
import ca.bc.gov.nrs.vdyp.model.UtilizationClass;
import ca.bc.gov.nrs.vdyp.model.VdypLayer;
import ca.bc.gov.nrs.vdyp.model.VdypPolygon;
import ca.bc.gov.nrs.vdyp.model.VdypSite;
import ca.bc.gov.nrs.vdyp.model.VdypSpecies;
import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder;

/**
* Write files to be input into VRI Adjust.
Expand Down Expand Up @@ -44,4 +54,186 @@ public VriAdjustInputWriter(Map<String, Object> controlMap, FileResolver resolve
controlMap
);
}

static OutputStream getOutputStream(Map<String, Object> controlMap, FileResolver resolver, String key)
throws IOException {
String fileName = Utils.expectParsedControl(controlMap, key, String.class);
return resolver.resolveForOutput(fileName);
}

// V7W_AIP
/**
* Write a polygon record to the polygon file
*
* @param polygon
* @throws IOException
*/
void writePolygon(VdypPolygon polygon) throws IOException {
writeFormat(
polygonFile, //
POLY_FORMAT, //

polygon.getPolygonIdentifier(), //
polygon.getBiogeoclimaticZone().getAlias(), //
polygon.getForestInventoryZone(), //

polygon.getPercentAvailable().intValue(), //
polygon.getLayers().get(LayerType.PRIMARY).getInventoryTypeGroup().orElse(EMPTY_INT), //
polygon.getLayers().get(LayerType.PRIMARY).getEmpiricalRelationshipParameterIndex().orElse(EMPTY_INT), //
polygon.getMode().orElse(PolygonMode.START).getCode()
);
}

/**
* Write a species record to the species file
*
* @param layer
* @param spec
* @throws IOException
*/
void writeSpecies(VdypLayer layer, VdypSpecies spec) throws IOException {

// Ensure we have a list of 4 distribution entries
var specDistributionEntries = Stream.concat(
spec.getSp64DistributionSet().getSp64DistributionList().stream(), Stream
.generate(() -> new Sp64Distribution(0, "", 0f))
).limit(4).toList();
// 082E004 615 1988 P 9 L LW 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9
writeFormat(
speciesFile, //
SPEC_FORMAT, //

spec.getPolygonIdentifier(), //
spec.getLayerType().getAlias(), //

spec.getGenusIndex(), //
spec.getGenus(), //

specDistributionEntries.get(0).getGenusAlias(), //
specDistributionEntries.get(0).getPercentage(), //
specDistributionEntries.get(1).getGenusAlias(), //
specDistributionEntries.get(1).getPercentage(), //
specDistributionEntries.get(2).getGenusAlias(), //
specDistributionEntries.get(2).getPercentage(), //
specDistributionEntries.get(3).getGenusAlias(), //
specDistributionEntries.get(3).getPercentage(), //

spec.getSite().flatMap(VdypSite::getSiteIndex).orElse(EMPTY_FLOAT),
spec.getSite().flatMap(VdypSite::getHeight).orElse(EMPTY_FLOAT),
spec.getSite().flatMap(VdypSite::getAgeTotal).orElse(EMPTY_FLOAT),
spec.getSite().flatMap(VdypSite::getYearsAtBreastHeight).orElse(EMPTY_FLOAT),
spec.getSite().flatMap(VdypSite::getYearsToBreastHeight).orElse(EMPTY_FLOAT),
layer.getPrimaryGenus().map(spec.getGenus()::equals).orElse(false) ? 1 : 0,
spec.getSite().flatMap(VdypSite::getSiteCurveNumber).orElse(EMPTY_INT)

);

}

/**
* Write the utilization records for a layer or species to the utilization file.
*
* @param layer
* @param utils
* @throws IOException
*/
// V7W_AIU Internalized loop over utilization classes
void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOException {
Optional<String> specId = Optional.empty();
Optional<Integer> specIndex = Optional.empty();
if (utils instanceof VdypSpecies spec) {
specId = Optional.of(spec.getGenus());
specIndex = Optional.of(spec.getGenusIndex());
}

for (var uc : UtilizationClass.values()) {
Optional<Float> height = Optional.empty();
if (uc.index < 1) {
height = Optional.of(utils.getLoreyHeightByUtilization().getCoe(uc.index)).filter(x -> x > 0f);
}
Optional<Float> quadMeanDiameter = Optional.empty();
if (utils.getBaseAreaByUtilization().getCoe(uc.index) > 0) {
quadMeanDiameter = Optional.of(
BaseAreaTreeDensityDiameter.quadMeanDiameter(
utils.getBaseAreaByUtilization().getCoe(uc.index), utils
.getTreesPerHectareByUtilization().getCoe(uc.index)
)
);
}

writeFormat(
utilizationFile, //
UTIL_FORMAT, //

layer.getPolygonIdentifier(), //
layer.getLayerType().getAlias(), //

specIndex.orElse(0), //
specId.orElse(" "), //

uc.index,

utils.getBaseAreaByUtilization().getCoe(uc.index), //
utils.getTreesPerHectareByUtilization().getCoe(uc.index), //
height.orElse(EMPTY_FLOAT), //

utils.getWholeStemVolumeByUtilization().getCoe(uc.index), //
utils.getCloseUtilizationVolumeByUtilization().getCoe(uc.index), //
utils.getCloseUtilizationVolumeNetOfDecayByUtilization().getCoe(uc.index), //
utils.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().getCoe(uc.index), //
utils.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().getCoe(uc.index), //

quadMeanDiameter.orElse(layer.getLayerType() == LayerType.PRIMARY ? //
EMPTY_FLOAT : 0f
) // FIXME: VDYP7 is being inconsistent. Should consider using -9 for both.
);
}
}

/**
* Output a polygon and its children.
*
* @param polygon
* @throws IOException
*/
// VDYP_OUT when JPROGRAM = 1 (FIPSTART) or 3 (VRISTART)
public void writePolygonWithSpeciesAndUtilization(VdypPolygon polygon) throws IOException {

writePolygon(polygon);
for (var layer : polygon.getLayers().values()) {
writeUtilization(layer, layer);
List<VdypSpecies> specs = new ArrayList<>(layer.getSpecies().size());
specs.addAll(layer.getSpecies().values());
specs.sort(Utils.compareUsing(BaseVdypSpecies::getGenus));
for (var species : specs) {
writeSpecies(layer, species);
writeUtilization(layer, species);
}
}
writeSpeciesEndRecord(polygon);
writeUtilizationEndRecord(polygon);
}

private void writeEndRecord(OutputStream os, VdypPolygon polygon) throws IOException {
writeFormat(os, END_RECORD_FORMAT, polygon.getPolygonIdentifier());
}

private void writeUtilizationEndRecord(VdypPolygon polygon) throws IOException {
writeEndRecord(utilizationFile, polygon);
}

private void writeSpeciesEndRecord(VdypPolygon polygon) throws IOException {
writeEndRecord(speciesFile, polygon);
}

void writeFormat(OutputStream os, String format, Object... params) throws IOException {
os.write(String.format(format, params).getBytes());
}

@Override
public void close() throws IOException {
polygonFile.close();
speciesFile.close();
utilizationFile.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;

import ca.bc.gov.nrs.vdyp.common.Computed;

public abstract class BaseVdypLayer<S extends BaseVdypSpecies<I>, I extends BaseVdypSite> {

private final PolygonIdentifier polygonIdentifier;
Expand Down Expand Up @@ -81,6 +83,17 @@ public void setInventoryTypeGroup(Optional<Integer> inventoryTypeGroup) {
this.inventoryTypeGroup = inventoryTypeGroup;
}

public abstract Optional<String> getPrimaryGenus();

@Computed
public Optional<S> getPrimarySpeciesRecord() {
return getPrimaryGenus().map(this.getSpecies()::get);
}

@Computed
public Optional<I> getPrimarySite() {
return getPrimaryGenus().map(this.getSites()::get);

@Override
public String toString() {
return polygonIdentifier.toStringCompact() + "-" + layerType;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.nrs.vdyp.model;


public interface InputLayer {

public float getCrownClosure();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,9 @@ public LinkedHashMap<String, I> getSites() {
return result;
}

@Override
public Optional<String> getPrimaryGenus() {
return getSiteGenus();
}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package ca.bc.gov.nrs.vdyp.model;

import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import ca.bc.gov.nrs.vdyp.common.Computed;
import ca.bc.gov.nrs.vdyp.common.Utils;

public class VdypLayer extends SingleSiteLayer<VdypSpecies, VdypSite> implements VdypUtilizationHolder {
public class VdypLayer extends BaseVdypLayer<VdypSpecies, VdypSite> implements VdypUtilizationHolder {

private UtilizationVector baseAreaByUtilization = //
VdypUtilizationHolder.emptyUtilization(); // LVCOM/BA species 0
Expand All @@ -28,21 +29,38 @@ public class VdypLayer extends SingleSiteLayer<VdypSpecies, VdypSite> implements
private UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = //
VdypUtilizationHolder.emptyUtilization(); // LVCOM/VOL_DWB species 0

private Optional<Integer> empiricalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1
private Optional<Integer> empericalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1
private Optional<String> primarySp0;

public VdypLayer(
PolygonIdentifier polygonIdentifier, LayerType layer, Optional<Integer> inventoryTypeGroup,
Optional<Integer> empiricalRelationshipParameterIndex
Optional<Integer> empericalRelationshipParameterIndex, Optional<String> primarySp0
) {
super(polygonIdentifier, layer, inventoryTypeGroup);
this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex;
this.empericalRelationshipParameterIndex = empericalRelationshipParameterIndex;
this.primarySp0 = primarySp0;
}

@Computed
public Optional<Float> getBreastHeightAge() {
return this.getAgeTotal().flatMap(at -> this.getYearsToBreastHeight().map(bha -> at - bha));
}

@Computed
public Optional<Float> getAgeTotal() {
return this.getPrimarySite().flatMap(BaseVdypSite::getAgeTotal);
}

@Computed
public Optional<Float> getYearsToBreastHeight() {
return this.getPrimarySite().flatMap(BaseVdypSite::getYearsToBreastHeight);
}

@Computed
public Optional<Float> getHeight() {
return this.getPrimarySite().flatMap(BaseVdypSite::getHeight);
}

@Override
public UtilizationVector getBaseAreaByUtilization() {
return baseAreaByUtilization;
Expand Down Expand Up @@ -147,6 +165,11 @@ public void setEmpericalRelationshipParameterIndex(Optional<Integer> empericalRe
this.empiricalRelationshipParameterIndex = empericalRelationshipParameterIndex;
}

@Override
public Optional<String> getPrimaryGenus() {
return primarySp0;
}

/**
* Accepts a configuration function that accepts a builder to configure.
*
Expand Down Expand Up @@ -199,7 +222,18 @@ public void empiricalRelationshipParameterIndex(int empiricalRelationshipParamet
this.empiricalRelationshipParameterIndex(Optional.of(empiricalRelationshipParameterIndex));
}

UtilizationVector loreyHeightByUtilization = VdypUtilizationHolder.emptyLoreyHeightUtilization();
protected Optional<String> primarySp0 = Optional.empty();

public VdypLayer.Builder primaryGenus(Optional<String> primarySp0) {
this.primarySp0 = primarySp0;
return this;
}

public VdypLayer.Builder primaryGenus(String primarySp0) {
return primaryGenus(Optional.of(primarySp0));
}

UtilizationVector loreyHeight = VdypUtilizationHolder.emptyLoreyHeightUtilization();

public void loreyHeightByUtilization(float height) {
this.loreyHeightByUtilization = Utils.heightVector(0, height);
Expand Down Expand Up @@ -348,7 +382,8 @@ protected VdypLayer doBuild() {
polygonIdentifier.get(), //
layerType.get(), //
inventoryTypeGroup, //
empiricalRelationshipParameterIndex
empericalRelationshipParameterIndex, //
primarySp0
);
}

Expand All @@ -360,5 +395,30 @@ protected VdypSpecies buildSpecies(Consumer<VdypSpecies.Builder> config) {
builder.layerType(this.layerType.get());
});
}

public void baseAreaByUtilization(UtilizationVector utilizationVector) {
// TODO Auto-generated method stub

}

@Override
public <S2 extends BaseVdypSpecies<I2>, I2 extends BaseVdypSite>
BaseVdypLayer.Builder<VdypLayer, VdypSpecies, VdypSite, VdypSpecies.Builder, VdypSite.Builder>
adaptSpecies(
BaseVdypLayer<S2, ?> toCopy, BiConsumer<VdypSpecies.Builder, S2> config
) {
this.primaryGenus(toCopy.getPrimaryGenus());
return super.adaptSpecies(toCopy, config);
}

@Override
public BaseVdypLayer.Builder<VdypLayer, VdypSpecies, VdypSite, VdypSpecies.Builder, VdypSite.Builder>
copySpecies(
VdypLayer toCopy, BiConsumer<VdypSpecies.Builder, VdypSpecies> config
) {
this.primaryGenus(toCopy.getPrimaryGenus());
return super.copySpecies(toCopy, config);
}

}
}
Loading

0 comments on commit 210d841

Please sign in to comment.